First version of Service
This commit is contained in:
commit
e99b2c5a5a
363
.gitignore
vendored
Normal file
363
.gitignore
vendored
Normal file
@ -0,0 +1,363 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
17
Core.Inventory.Application/Core.Inventory.Application.csproj
Normal file
17
Core.Inventory.Application/Core.Inventory.Application.csproj
Normal file
@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MongoDB.Driver" Version="3.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core.Inventory.External\Core.Inventory.External.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -0,0 +1,33 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="FurnitureBasePort.cs">
|
||||
// Core.Inventory.Application
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Core.Adapters.Lib;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Ports;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Adapter
|
||||
{
|
||||
public class FurnitureBasePort : BasePresenter, IFurnitureBasePort
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles success with a single <see cref="FurnitureBase"/>.
|
||||
/// </summary>
|
||||
/// <param name="output">The output adapter.</param>
|
||||
public void Success(FurnitureBase output)
|
||||
{
|
||||
ViewModel = new OkObjectResult(output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles success with a list of <see cref="FurnitureBase"/>.
|
||||
/// </summary>
|
||||
/// <param name="output">The output list.</param>
|
||||
public void Success(List<FurnitureBase> output)
|
||||
{
|
||||
ViewModel = new OkObjectResult(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="FurnitureVariantPort.cs">
|
||||
// Core.Inventory.Application
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
|
||||
using Core.Adapters.Lib;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Ports;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Adapter
|
||||
{
|
||||
/// <summary>
|
||||
/// Presenter for FurnitureVariant use cases. Maps output to HTTP responses.
|
||||
/// </summary>
|
||||
public class FurnitureVariantPort : BasePresenter, IFurnitureVariantPort
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles success with a single <see cref="FurnitureVariant"/>.
|
||||
/// </summary>
|
||||
/// <param name="output">The output adapter.</param>
|
||||
public void Success(FurnitureVariant output)
|
||||
{
|
||||
ViewModel = new OkObjectResult(output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles success with a list of <see cref="FurnitureVariant"/>.
|
||||
/// </summary>
|
||||
/// <param name="output">The output list.</param>
|
||||
public void Success(List<FurnitureVariant> output)
|
||||
{
|
||||
ViewModel = new OkObjectResult(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="ChangeFurnitureBaseStatusRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
|
||||
using Core.Blueprint.Mongo;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Command to change the status of a furniture base model.
|
||||
/// </summary>
|
||||
public class ChangeFurnitureBaseStatusRequest : Notificator, ICommand
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
public StatusEnum Status { get; set; }
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="ChangeFurnitureVariantStatusRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Core.Blueprint.Mongo;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Command to change the status of a furniture variant.
|
||||
/// </summary>
|
||||
public class ChangeFurnitureVariantStatusRequest : Notificator, ICommand
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
public StatusEnum Status { get; set; }
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="Dimensions.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Value object representing the dimensions of a furniture item.
|
||||
/// </summary>
|
||||
public class Dimensions
|
||||
{
|
||||
public float Width { get; set; }
|
||||
public float Height { get; set; }
|
||||
public float Depth { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="CreateFurnitureBaseRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input.Common;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Command for creating a new furniture base entity.
|
||||
/// </summary>
|
||||
public class CreateFurnitureBaseRequest : Notificator, ICommand
|
||||
{
|
||||
public string ModelName { get; set; } = null!;
|
||||
public string Material { get; set; } = null!;
|
||||
public string Condition { get; set; } = null!;
|
||||
public string? BaseDescription { get; set; }
|
||||
public string? Representation { get; set; }
|
||||
public string? MaintenanceNotes { get; set; }
|
||||
|
||||
public Dimensions Dimensions { get; set; } = new();
|
||||
|
||||
public List<string>? VariantIds { get; set; }
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(ModelName) &&
|
||||
!string.IsNullOrWhiteSpace(Material) &&
|
||||
!string.IsNullOrWhiteSpace(Condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="CreateFurnitureVariantRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
public class CreateFurnitureVariantRequest : Notificator, ICommand
|
||||
{
|
||||
public string ModelId { get; set; } = null!;
|
||||
public string Name { get; set; } = null!;
|
||||
public string Color { get; set; } = null!;
|
||||
public string? Line { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
public string Currency { get; set; } = "USD";
|
||||
public int Stock { get; set; }
|
||||
|
||||
public Guid CategoryId { get; set; }
|
||||
public Guid ProviderId { get; set; }
|
||||
|
||||
public Dictionary<string, object> Attributes { get; set; } = [];
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(ModelId)
|
||||
&& !string.IsNullOrWhiteSpace(Name)
|
||||
&& !string.IsNullOrWhiteSpace(Color)
|
||||
&& Price >= 0
|
||||
&& Stock >= 0
|
||||
&& CategoryId != Guid.Empty
|
||||
&& ProviderId != Guid.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="GetAllFurnitureBaseRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
public class GetAllFurnitureBaseRequest : ICommand
|
||||
{
|
||||
public bool Validate() => true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="GetAllFurnitureVariantsByModelIdRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
public class GetAllFurnitureVariantsByModelIdRequest : Notificator, ICommand
|
||||
{
|
||||
public string ModelId { get; set; } = null!;
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(ModelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="GetFurnitureBaseByIdRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Query to retrieve a furniture base by its identifier.
|
||||
/// </summary>
|
||||
public class GetFurnitureBaseByIdRequest : Notificator, ICommand
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="GetFurnitureVariantByIdRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
public class GetFurnitureVariantByIdRequest : Notificator, ICommand
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="UpdateFurnitureBaseRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input.Common;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Command for updating an existing furniture base entity.
|
||||
/// </summary>
|
||||
public class UpdateFurnitureBaseRequest : Notificator, ICommand
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
public string ModelName { get; set; } = null!;
|
||||
public string Material { get; set; } = null!;
|
||||
public string Condition { get; set; } = null!;
|
||||
public string? BaseDescription { get; set; }
|
||||
public string? Representation { get; set; }
|
||||
public string? MaintenanceNotes { get; set; }
|
||||
|
||||
public Dimensions Dimensions { get; set; } = new();
|
||||
|
||||
public List<string>? VariantIds { get; set; }
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Id)
|
||||
&& !string.IsNullOrWhiteSpace(ModelName)
|
||||
&& !string.IsNullOrWhiteSpace(Material)
|
||||
&& !string.IsNullOrWhiteSpace(Condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="UpdateFurnitureVariantRequest.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Command for updating an existing furniture variant.
|
||||
/// </summary>
|
||||
public class UpdateFurnitureVariantRequest : Notificator, ICommand
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
public string ModelId { get; set; } = null!;
|
||||
public string Name { get; set; } = null!;
|
||||
public string Color { get; set; } = null!;
|
||||
public string? Line { get; set; }
|
||||
|
||||
public int Stock { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public string Currency { get; set; } = "USD";
|
||||
|
||||
public Guid CategoryId { get; set; }
|
||||
public Guid ProviderId { get; set; }
|
||||
|
||||
public Dictionary<string, object> Attributes { get; set; } = [];
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(Id) &&
|
||||
!string.IsNullOrWhiteSpace(ModelId) &&
|
||||
!string.IsNullOrWhiteSpace(Name) &&
|
||||
!string.IsNullOrWhiteSpace(Color) &&
|
||||
Price > 0 &&
|
||||
Stock >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,324 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Ports;
|
||||
using Core.Inventory.External.Clients;
|
||||
using Core.Inventory.External.Clients.Requests;
|
||||
using FluentValidation;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
using Lib.Architecture.BuildingBlocks.Helpers;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory
|
||||
{
|
||||
public class InventoryHandler :
|
||||
// FurnitureBase
|
||||
IComponentHandler<CreateFurnitureBaseRequest>,
|
||||
IComponentHandler<UpdateFurnitureBaseRequest>,
|
||||
IComponentHandler<GetAllFurnitureBaseRequest>,
|
||||
IComponentHandler<ChangeFurnitureBaseStatusRequest>,
|
||||
IComponentHandler<GetFurnitureBaseByIdRequest>,
|
||||
// FurnitureVariant
|
||||
IComponentHandler<CreateFurnitureVariantRequest>,
|
||||
IComponentHandler<UpdateFurnitureVariantRequest>,
|
||||
IComponentHandler<GetFurnitureVariantByIdRequest>,
|
||||
IComponentHandler<GetAllFurnitureVariantsByModelIdRequest>,
|
||||
IComponentHandler<ChangeFurnitureVariantStatusRequest>
|
||||
{
|
||||
// FurnitureBase
|
||||
private readonly IFurnitureBasePort _basePort;
|
||||
private readonly IValidator<CreateFurnitureBaseRequest> _createBaseValidator;
|
||||
private readonly IValidator<UpdateFurnitureBaseRequest> _updateBaseValidator;
|
||||
private readonly IValidator<ChangeFurnitureBaseStatusRequest> _changeBaseStatusValidator;
|
||||
|
||||
// FurnitureVariant
|
||||
private readonly IFurnitureVariantPort _variantPort;
|
||||
private readonly IValidator<CreateFurnitureVariantRequest> _createVariantValidator;
|
||||
private readonly IValidator<UpdateFurnitureVariantRequest> _updateVariantValidator;
|
||||
private readonly IValidator<ChangeFurnitureVariantStatusRequest> _changeVariantStatusValidator;
|
||||
|
||||
private readonly IInventoryServiceClient _inventoryDALService;
|
||||
|
||||
public InventoryHandler(
|
||||
// FurnitureBase
|
||||
IFurnitureBasePort basePort,
|
||||
IValidator<CreateFurnitureBaseRequest> createBaseValidator,
|
||||
IValidator<UpdateFurnitureBaseRequest> updateBaseValidator,
|
||||
IValidator<ChangeFurnitureBaseStatusRequest> changeBaseStatusValidator,
|
||||
|
||||
// FurnitureVariant
|
||||
IFurnitureVariantPort variantPort,
|
||||
IValidator<CreateFurnitureVariantRequest> createVariantValidator,
|
||||
IValidator<UpdateFurnitureVariantRequest> updateVariantValidator,
|
||||
IValidator<ChangeFurnitureVariantStatusRequest> changeVariantStatusValidator,
|
||||
|
||||
IInventoryServiceClient inventoryDALService
|
||||
)
|
||||
{
|
||||
_basePort= basePort;
|
||||
_createBaseValidator= createBaseValidator;
|
||||
_updateBaseValidator= updateBaseValidator;
|
||||
_changeBaseStatusValidator= changeBaseStatusValidator;
|
||||
_variantPort= variantPort;
|
||||
_createVariantValidator= createVariantValidator;
|
||||
_updateVariantValidator= updateVariantValidator;
|
||||
_changeVariantStatusValidator= changeVariantStatusValidator;
|
||||
_inventoryDALService= inventoryDALService;
|
||||
}
|
||||
|
||||
#region FurnitureBase
|
||||
public async ValueTask ExecuteAsync(CreateFurnitureBaseRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
if (!command.IsValid(_createBaseValidator))
|
||||
{
|
||||
_basePort.ValidationErrors(command.Notifications);
|
||||
return;
|
||||
}
|
||||
|
||||
var request = new FurnitureBaseRequest
|
||||
{
|
||||
BaseDescription = command.BaseDescription,
|
||||
Condition = command.Condition,
|
||||
MaintenanceNotes = command.MaintenanceNotes,
|
||||
Material = command.Material,
|
||||
ModelName = command.ModelName,
|
||||
Representation = command.Representation,
|
||||
VariantIds = command.VariantIds,
|
||||
Dimensions = new Adapters.Lib.Dimensions
|
||||
{
|
||||
Depth = command.Dimensions.Depth,
|
||||
Height = command.Dimensions.Height,
|
||||
Width = command.Dimensions.Width
|
||||
}
|
||||
};
|
||||
|
||||
var result = await _inventoryDALService.CreateFurnitureBaseAsync(request, cancellationToken);
|
||||
_basePort.Success(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _basePort);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteAsync(UpdateFurnitureBaseRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
if (!command.IsValid(_updateBaseValidator))
|
||||
{
|
||||
_basePort.ValidationErrors(command.Notifications);
|
||||
return;
|
||||
}
|
||||
|
||||
var request = new FurnitureBaseRequest
|
||||
{
|
||||
BaseDescription = command.BaseDescription,
|
||||
Condition = command.Condition,
|
||||
MaintenanceNotes = command.MaintenanceNotes,
|
||||
Material = command.Material,
|
||||
ModelName = command.ModelName,
|
||||
Representation = command.Representation,
|
||||
VariantIds = command.VariantIds,
|
||||
Dimensions = new Adapters.Lib.Dimensions
|
||||
{
|
||||
Depth = command.Dimensions.Depth,
|
||||
Height = command.Dimensions.Height,
|
||||
Width = command.Dimensions.Width
|
||||
}
|
||||
};
|
||||
|
||||
var result = await _inventoryDALService.UpdateFurnitureBaseAsync(request, command.Id, cancellationToken);
|
||||
_basePort.Success(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _basePort);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteAsync(GetAllFurnitureBaseRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _inventoryDALService.GetAllFurnitureBaseAsync(cancellationToken);
|
||||
if (!result.Any())
|
||||
{
|
||||
_basePort.NoContentSuccess();
|
||||
return;
|
||||
}
|
||||
_basePort.Success([.. result]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _basePort);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteAsync(GetFurnitureBaseByIdRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
var result = await _inventoryDALService.GetFurnitureBaseByIdAsync(command.Id, cancellationToken);
|
||||
if (result is null)
|
||||
{
|
||||
_basePort.NoContentSuccess();
|
||||
return;
|
||||
}
|
||||
_basePort.Success(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _basePort);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteAsync(ChangeFurnitureBaseStatusRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
if (!command.IsValid(_changeBaseStatusValidator))
|
||||
{
|
||||
_basePort.ValidationErrors(command.Notifications);
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await _inventoryDALService.ChangeFurnitureBaseStatusAsync(command.Id, command.Status, cancellationToken);
|
||||
_basePort.Success(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _basePort);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FurnitureVariant
|
||||
public async ValueTask ExecuteAsync(CreateFurnitureVariantRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
if (!command.IsValid(_createVariantValidator))
|
||||
{
|
||||
_variantPort.ValidationErrors(command.Notifications);
|
||||
return;
|
||||
}
|
||||
var request = new FurnitureVariantRequest
|
||||
{
|
||||
Stock = command.Stock,
|
||||
Attributes= command.Attributes,
|
||||
CategoryId = command.CategoryId,
|
||||
Color = command.Color,
|
||||
Currency = command.Currency,
|
||||
Line = command.Line,
|
||||
ModelId = command.ModelId,
|
||||
Name = command.Name,
|
||||
Price = command.Price,
|
||||
ProviderId = command.ProviderId
|
||||
};
|
||||
var result = await _inventoryDALService.CreateFurnitureVariantAsync(request, cancellationToken);
|
||||
_variantPort.Success(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _variantPort);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteAsync(UpdateFurnitureVariantRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
if (!command.IsValid(_updateVariantValidator))
|
||||
{
|
||||
_variantPort.ValidationErrors(command.Notifications);
|
||||
return;
|
||||
}
|
||||
var request = new FurnitureVariantRequest
|
||||
{
|
||||
Stock = command.Stock,
|
||||
Attributes= command.Attributes,
|
||||
CategoryId = command.CategoryId,
|
||||
Color = command.Color,
|
||||
Currency = command.Currency,
|
||||
Line = command.Line,
|
||||
ModelId = command.ModelId,
|
||||
Name = command.Name,
|
||||
Price = command.Price,
|
||||
ProviderId = command.ProviderId
|
||||
};
|
||||
var result = await _inventoryDALService.UpdateFurnitureVariantAsync(request, command.Id, cancellationToken);
|
||||
_variantPort.Success(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _variantPort);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteAsync(GetFurnitureVariantByIdRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
var result = await _inventoryDALService.GetFurnitureVariantByIdAsync(command.Id, cancellationToken);
|
||||
if (result is null)
|
||||
{
|
||||
_variantPort.NoContentSuccess();
|
||||
return;
|
||||
}
|
||||
_variantPort.Success(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _variantPort);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteAsync(GetAllFurnitureVariantsByModelIdRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
var result = await _inventoryDALService.GetAllVariantsByModelIdAsync(command.ModelId, cancellationToken);
|
||||
if (!result.Any())
|
||||
{
|
||||
_variantPort.NoContentSuccess();
|
||||
return;
|
||||
}
|
||||
_variantPort.Success([.. result]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _variantPort);
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask ExecuteAsync(ChangeFurnitureVariantStatusRequest command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(command);
|
||||
if (!command.IsValid(_changeVariantStatusValidator))
|
||||
{
|
||||
_variantPort.ValidationErrors(command.Notifications);
|
||||
return;
|
||||
}
|
||||
var result = await _inventoryDALService.ChangeFurnitureVariantStatusAsync(command.Id, command.Status, cancellationToken);
|
||||
_variantPort.Success(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ApiResponseHelper.EvaluatePort(ex, _variantPort);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="IFurnitureBasePort.cs">
|
||||
// Core.Inventory.Application
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Core.Adapters.Lib;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Ports
|
||||
{
|
||||
/// <summary>
|
||||
/// Output port interface for handling results from FurnitureBase use cases.
|
||||
/// </summary>
|
||||
public interface IFurnitureBasePort : IBasePort,
|
||||
ICommandSuccessPort<FurnitureBase>,
|
||||
ICommandSuccessPort<List<FurnitureBase>>,
|
||||
INoContentPort, IBusinessErrorPort, ITimeoutPort, IValidationErrorPort,
|
||||
INotFoundPort, IForbiddenPort, IUnauthorizedPort, IInternalServerErrorPort,
|
||||
IBadRequestPort
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="IFurnitureVariantPort.cs">
|
||||
// Core.Inventory.Application
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Core.Adapters.Lib;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Ports
|
||||
{
|
||||
/// <summary>
|
||||
/// Output port interface for handling results from FurnitureVariant use cases.
|
||||
/// </summary>
|
||||
public interface IFurnitureVariantPort : IBasePort,
|
||||
ICommandSuccessPort<FurnitureVariant>,
|
||||
ICommandSuccessPort<List<FurnitureVariant>>,
|
||||
INoContentPort, IBusinessErrorPort, ITimeoutPort, IValidationErrorPort,
|
||||
INotFoundPort, IForbiddenPort, IUnauthorizedPort, IInternalServerErrorPort,
|
||||
IBadRequestPort
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class ChangeFurnitureBaseStatusValidator : AbstractValidator<ChangeFurnitureBaseStatusRequest>
|
||||
{
|
||||
public ChangeFurnitureBaseStatusValidator()
|
||||
{
|
||||
RuleFor(x => x.Id)
|
||||
.NotEmpty().WithMessage("Id is required.");
|
||||
|
||||
RuleFor(x => x.Status)
|
||||
.IsInEnum().WithMessage("Invalid status value.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class ChangeFurnitureVariantStatusValidator : AbstractValidator<ChangeFurnitureVariantStatusRequest>
|
||||
{
|
||||
public ChangeFurnitureVariantStatusValidator()
|
||||
{
|
||||
RuleFor(x => x.Id)
|
||||
.NotEmpty().WithMessage("Id is required.");
|
||||
|
||||
RuleFor(x => x.Status)
|
||||
.IsInEnum().WithMessage("Invalid status value.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input.Common;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator.Common
|
||||
{
|
||||
public class DimensionsValidator : AbstractValidator<Dimensions>
|
||||
{
|
||||
public DimensionsValidator()
|
||||
{
|
||||
RuleFor(x => x.Width)
|
||||
.GreaterThan(0).WithMessage("Width must be greater than 0.");
|
||||
|
||||
RuleFor(x => x.Height)
|
||||
.GreaterThan(0).WithMessage("Height must be greater than 0.");
|
||||
|
||||
RuleFor(x => x.Depth)
|
||||
.GreaterThan(0).WithMessage("Depth must be greater than 0.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
// ***********************************************************************
|
||||
// <copyright file="CreateFurnitureBaseValidator.cs">
|
||||
// Core.Inventory
|
||||
// </copyright>
|
||||
// ***********************************************************************
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Validator.Common;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class CreateFurnitureBaseValidator : AbstractValidator<CreateFurnitureBaseRequest>
|
||||
{
|
||||
public CreateFurnitureBaseValidator()
|
||||
{
|
||||
RuleFor(x => x.ModelName)
|
||||
.NotEmpty().WithMessage("Model name is required.");
|
||||
|
||||
RuleFor(x => x.Material)
|
||||
.NotEmpty().WithMessage("Material is required.");
|
||||
|
||||
RuleFor(x => x.Condition)
|
||||
.NotEmpty().WithMessage("Condition is required.");
|
||||
|
||||
RuleFor(x => x.Dimensions)
|
||||
.SetValidator(new DimensionsValidator());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class CreateFurnitureVariantValidator : AbstractValidator<CreateFurnitureVariantRequest>
|
||||
{
|
||||
public CreateFurnitureVariantValidator()
|
||||
{
|
||||
RuleFor(x => x.ModelId)
|
||||
.NotEmpty().WithMessage("ModelId is required.");
|
||||
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty().WithMessage("Name is required.");
|
||||
|
||||
RuleFor(x => x.Color)
|
||||
.NotEmpty().WithMessage("Color is required.");
|
||||
|
||||
RuleFor(x => x.Price)
|
||||
.GreaterThanOrEqualTo(0).WithMessage("Price must be a non-negative value.");
|
||||
|
||||
RuleFor(x => x.Stock)
|
||||
.GreaterThanOrEqualTo(0).WithMessage("Stock must be a non-negative value.");
|
||||
|
||||
RuleFor(x => x.CategoryId)
|
||||
.NotEqual(Guid.Empty).WithMessage("CategoryId is required.");
|
||||
|
||||
RuleFor(x => x.ProviderId)
|
||||
.NotEqual(Guid.Empty).WithMessage("ProviderId is required.");
|
||||
|
||||
RuleFor(x => x.Currency)
|
||||
.NotEmpty().WithMessage("Currency is required.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class GetAllFurnitureVariantsByModelIdValidator : AbstractValidator<GetAllFurnitureVariantsByModelIdRequest>
|
||||
{
|
||||
public GetAllFurnitureVariantsByModelIdValidator()
|
||||
{
|
||||
RuleFor(x => x.ModelId)
|
||||
.NotEmpty().WithMessage("ModelId is required.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class GetFurnitureBaseByIdValidator : AbstractValidator<GetFurnitureBaseByIdRequest>
|
||||
{
|
||||
public GetFurnitureBaseByIdValidator()
|
||||
{
|
||||
RuleFor(x => x.Id)
|
||||
.NotEmpty().WithMessage("Id is required.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class GetFurnitureVariantByIdValidator : AbstractValidator<GetFurnitureVariantByIdRequest>
|
||||
{
|
||||
public GetFurnitureVariantByIdValidator()
|
||||
{
|
||||
RuleFor(x => x.Id)
|
||||
.NotEmpty().WithMessage("Id is required.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Validator.Common;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class UpdateFurnitureBaseValidator : AbstractValidator<UpdateFurnitureBaseRequest>
|
||||
{
|
||||
public UpdateFurnitureBaseValidator()
|
||||
{
|
||||
RuleFor(x => x.ModelName)
|
||||
.NotEmpty().WithMessage("Model name is required.");
|
||||
|
||||
RuleFor(x => x.Material)
|
||||
.NotEmpty().WithMessage("Material is required.");
|
||||
|
||||
RuleFor(x => x.Condition)
|
||||
.NotEmpty().WithMessage("Condition is required.");
|
||||
|
||||
RuleFor(x => x.Dimensions)
|
||||
.SetValidator(new DimensionsValidator());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Core.Inventory.Application.UseCases.Inventory.Validator
|
||||
{
|
||||
public class UpdateFurnitureVariantValidator : AbstractValidator<UpdateFurnitureVariantRequest>
|
||||
{
|
||||
public UpdateFurnitureVariantValidator()
|
||||
{
|
||||
RuleFor(x => x.Id)
|
||||
.NotEmpty().WithMessage("Id is required.");
|
||||
|
||||
RuleFor(x => x.ModelId)
|
||||
.NotEmpty().WithMessage("ModelId is required.");
|
||||
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty().WithMessage("Name is required.");
|
||||
|
||||
RuleFor(x => x.Color)
|
||||
.NotEmpty().WithMessage("Color is required.");
|
||||
|
||||
RuleFor(x => x.Price)
|
||||
.GreaterThan(0).WithMessage("Price must be greater than 0.");
|
||||
|
||||
RuleFor(x => x.Stock)
|
||||
.GreaterThanOrEqualTo(0).WithMessage("Stock must be a non-negative value.");
|
||||
|
||||
RuleFor(x => x.Currency)
|
||||
.NotEmpty().WithMessage("Currency is required.");
|
||||
|
||||
RuleFor(x => x.CategoryId)
|
||||
.NotEqual(Guid.Empty).WithMessage("CategoryId is required.");
|
||||
|
||||
RuleFor(x => x.ProviderId)
|
||||
.NotEqual(Guid.Empty).WithMessage("ProviderId is required.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
using Core.Inventory.External.Clients;
|
||||
using Core.Inventory.External.GatewayConfigurations;
|
||||
using Core.Inventory.External.Helpers;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Refit;
|
||||
|
||||
namespace Core.Inventory.External.ClientConfiguration
|
||||
{
|
||||
public static class RegisterClientConfiguration
|
||||
{
|
||||
public static IServiceCollection RegisterExternalLayer(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var gatewayConfiguration = new GatewayConfiguration();
|
||||
var gatewaySettingsConfiguration = new GatewaySettingsConfigurations(configuration);
|
||||
|
||||
// Register GatewayConfiguration as a singleton
|
||||
services.AddSingleton(gatewayConfiguration);
|
||||
|
||||
// Register IHttpContextAccessor
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
|
||||
// Register ITokenProvider
|
||||
services.AddSingleton<ITokenProvider, HttpContextTokenProvider>();
|
||||
|
||||
// Register the custom AuthenticatedHttpClientHandler
|
||||
services.AddTransient(provider =>
|
||||
{
|
||||
var tokenProvider = provider.GetRequiredService<ITokenProvider>();
|
||||
var handler = new AuthenticatedHttpClientHandler(tokenProvider)
|
||||
{
|
||||
InnerHandler = new HttpClientHandler()
|
||||
};
|
||||
return handler;
|
||||
});
|
||||
|
||||
var inventoryServiceApiUrl = GatewaySettingsConfigurations.GetInventoryServiceAPIEndpoint().Endpoint.Url;
|
||||
|
||||
// Register IInventoryServiceClient with the manually created HttpClient
|
||||
services.AddScoped<IInventoryServiceClient>(provider =>
|
||||
{
|
||||
var handler = provider.GetRequiredService<AuthenticatedHttpClientHandler>();
|
||||
var httpClient = new HttpClient(handler)
|
||||
{
|
||||
BaseAddress = new Uri(inventoryServiceApiUrl),
|
||||
Timeout = TimeSpan.FromMinutes(1)
|
||||
};
|
||||
return RestService.For<IInventoryServiceClient>(httpClient);
|
||||
});
|
||||
|
||||
services.AddScoped<IAuthenticationService, AuthenticationService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
Core.Inventory.External/Clients/IInventoryServiceClient.cs
Normal file
49
Core.Inventory.External/Clients/IInventoryServiceClient.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using Core.Adapters.Lib;
|
||||
using Core.Blueprint.Mongo;
|
||||
using Core.Inventory.External.Clients.Requests;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Refit;
|
||||
|
||||
namespace Core.Inventory.External.Clients
|
||||
{
|
||||
public interface IInventoryServiceClient
|
||||
{
|
||||
#region FurnitureBase
|
||||
|
||||
[Get("/api/v1/FurnitureBase")]
|
||||
Task<IEnumerable<FurnitureBase>> GetAllFurnitureBaseAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
[Get("/api/v1/FurnitureBase/{id}")]
|
||||
Task<FurnitureBase> GetFurnitureBaseByIdAsync([FromRoute] string id, CancellationToken cancellationToken = default);
|
||||
|
||||
[Post("/api/v1/FurnitureBase")]
|
||||
Task<FurnitureBase> CreateFurnitureBaseAsync([FromBody] FurnitureBaseRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
[Put("/api/v1/FurnitureBase/{id}")]
|
||||
Task<FurnitureBase> UpdateFurnitureBaseAsync([FromBody] FurnitureBaseRequest request, [FromRoute] string id, CancellationToken cancellationToken = default);
|
||||
|
||||
[Patch("/api/v1/FurnitureBase/{id}/{newStatus}/ChangeStatus")]
|
||||
Task<FurnitureBase> ChangeFurnitureBaseStatusAsync([FromRoute] string id, [FromRoute] StatusEnum newStatus, CancellationToken cancellationToken = default);
|
||||
|
||||
#endregion
|
||||
|
||||
#region FurnitureVariant
|
||||
|
||||
[Get("/api/v1/FurnitureVariant/{modelId}")]
|
||||
Task<IEnumerable<FurnitureVariant>> GetAllVariantsByModelIdAsync([FromRoute] string modelId, CancellationToken cancellationToken = default);
|
||||
|
||||
[Get("/api/v1/FurnitureVariant/{id}/byId")]
|
||||
Task<FurnitureVariant> GetFurnitureVariantByIdAsync([FromRoute] string id, CancellationToken cancellationToken = default);
|
||||
|
||||
[Post("/api/v1/FurnitureVariant")]
|
||||
Task<FurnitureVariant> CreateFurnitureVariantAsync([FromBody] FurnitureVariantRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
[Put("/api/v1/FurnitureVariant/{id}")]
|
||||
Task<FurnitureVariant> UpdateFurnitureVariantAsync([FromBody] FurnitureVariantRequest request, [FromRoute] string id, CancellationToken cancellationToken = default);
|
||||
|
||||
[Patch("/api/v1/FurnitureVariant/{id}/{newStatus}/ChangeStatus")]
|
||||
Task<FurnitureVariant> ChangeFurnitureVariantStatusAsync([FromRoute] string id, [FromRoute] StatusEnum newStatus, CancellationToken cancellationToken = default);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
using Core.Adapters.Lib;
|
||||
|
||||
namespace Core.Inventory.External.Clients.Requests
|
||||
{
|
||||
public class FurnitureBaseRequest
|
||||
{
|
||||
public string ModelName { get; set; } = null!;
|
||||
public string Material { get; set; } = null!;
|
||||
public string Condition { get; set; } = null!;
|
||||
public string? BaseDescription { get; set; }
|
||||
public string? Representation { get; set; }
|
||||
public string? MaintenanceNotes { get; set; }
|
||||
|
||||
public Dimensions Dimensions { get; set; } = new();
|
||||
public List<string>? VariantIds { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
namespace Core.Inventory.External.Clients.Requests
|
||||
{
|
||||
public class FurnitureVariantRequest
|
||||
{
|
||||
public string ModelId { get; set; } = null!;
|
||||
public string Name { get; set; } = null!;
|
||||
public string Color { get; set; } = null!;
|
||||
public string? Line { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
public string Currency { get; set; } = "USD";
|
||||
public int Stock { get; set; }
|
||||
|
||||
public Guid CategoryId { get; set; }
|
||||
public Guid ProviderId { get; set; }
|
||||
|
||||
public Dictionary<string, object> Attributes { get; set; } = [];
|
||||
}
|
||||
}
|
||||
15
Core.Inventory.External/Core.Inventory.External.csproj
Normal file
15
Core.Inventory.External/Core.Inventory.External.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Adapters.Lib" Version="1.0.3" />
|
||||
<PackageReference Include="BuildingBlocks.Library" Version="1.0.0" />
|
||||
<PackageReference Include="Refit" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -0,0 +1,20 @@
|
||||
using Core.Blueprint.External;
|
||||
|
||||
namespace Core.Inventory.External.GatewayConfigurations
|
||||
{
|
||||
public record GatewayConfiguration
|
||||
{
|
||||
public GatewayConfiguration()
|
||||
{
|
||||
InventoryService = new InventoryServiceAPI();
|
||||
}
|
||||
|
||||
public InventoryServiceAPI InventoryService { get; set; }
|
||||
}
|
||||
|
||||
public record InventoryServiceAPI
|
||||
{
|
||||
public string Channel { get; set; }
|
||||
public BaseEndpoint Endpoint { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
using Core.Blueprint.External;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Core.Inventory.External.GatewayConfigurations
|
||||
{
|
||||
public class GatewaySettingsConfigurations
|
||||
{
|
||||
private static GatewayConfiguration GatewayConfigurations { get; set; } = new GatewayConfiguration();
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public GatewaySettingsConfigurations(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
this.SetInventoryServiceAPIEndpoint();
|
||||
}
|
||||
|
||||
public static InventoryServiceAPI GetInventoryServiceAPIEndpoint()
|
||||
{
|
||||
return GatewayConfigurations.InventoryService;
|
||||
}
|
||||
|
||||
private GatewayConfiguration SetInventoryServiceAPIEndpoint()
|
||||
{
|
||||
IConfigurationSection source;
|
||||
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty;
|
||||
|
||||
if (environment == "Local")
|
||||
source = _configuration.GetSection("LocalGateways");
|
||||
else
|
||||
source = _configuration.GetSection("Gateways");
|
||||
|
||||
var endpoint = source["InventoryDAL"] ?? string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(endpoint))
|
||||
throw new Exception("Inventory DAL endpoint is empty or null");
|
||||
|
||||
GatewayConfigurations.InventoryService = new InventoryServiceAPI()
|
||||
{
|
||||
Endpoint = new BaseEndpoint()
|
||||
{
|
||||
Uri = new Uri(endpoint),
|
||||
Url = endpoint,
|
||||
Token = string.Empty,
|
||||
APIName = "Inventory Service"
|
||||
}
|
||||
};
|
||||
|
||||
return GatewayConfigurations;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
namespace Core.Inventory.External.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to inject the token in all requests.
|
||||
/// </summary>
|
||||
public class AuthenticatedHttpClientHandler : DelegatingHandler
|
||||
{
|
||||
private readonly ITokenProvider _tokenProvider;
|
||||
|
||||
public AuthenticatedHttpClientHandler(ITokenProvider tokenProvider)
|
||||
{
|
||||
_tokenProvider = tokenProvider;
|
||||
}
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
var token = _tokenProvider.GetToken();
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||
}
|
||||
|
||||
return await base.SendAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Core.Inventory.External/Helpers/HttpContextTokenProvider.cs
Normal file
25
Core.Inventory.External/Helpers/HttpContextTokenProvider.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Core.Inventory.External.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to return the access token to controllers.
|
||||
/// </summary>
|
||||
public class HttpContextTokenProvider : ITokenProvider
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public HttpContextTokenProvider(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get token from headers.
|
||||
/// </summary>
|
||||
public string GetToken()
|
||||
{
|
||||
return _httpContextAccessor.HttpContext?.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Core.Inventory.External/Helpers/ITokenProvider.cs
Normal file
13
Core.Inventory.External/Helpers/ITokenProvider.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace Core.Inventory.External.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for token provider.
|
||||
/// </summary>
|
||||
public interface ITokenProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Get token from headers.
|
||||
/// </summary>
|
||||
string GetToken();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
using Asp.Versioning;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Ports;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Core.Inventory.Service.API.Controllers
|
||||
{
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/v{api-version:apiVersion}/[controller]")]
|
||||
[Produces("application/json")]
|
||||
[ApiController]
|
||||
public class FurnitureBaseController : ControllerBase
|
||||
{
|
||||
private readonly IComponentHandler<GetFurnitureBaseByIdRequest> _getByIdHandler;
|
||||
private readonly IComponentHandler<GetAllFurnitureBaseRequest> _getAllHandler;
|
||||
private readonly IComponentHandler<CreateFurnitureBaseRequest> _createHandler;
|
||||
private readonly IComponentHandler<UpdateFurnitureBaseRequest> _updateHandler;
|
||||
private readonly IComponentHandler<ChangeFurnitureBaseStatusRequest> _changeStatusHandler;
|
||||
private readonly IFurnitureBasePort _port;
|
||||
|
||||
public FurnitureBaseController(
|
||||
IComponentHandler<GetFurnitureBaseByIdRequest> getByIdHandler,
|
||||
IComponentHandler<GetAllFurnitureBaseRequest> getAllHandler,
|
||||
IComponentHandler<CreateFurnitureBaseRequest> createHandler,
|
||||
IComponentHandler<UpdateFurnitureBaseRequest> updateHandler,
|
||||
IComponentHandler<ChangeFurnitureBaseStatusRequest> changeStatusHandler,
|
||||
IFurnitureBasePort port)
|
||||
{
|
||||
_getByIdHandler= getByIdHandler;
|
||||
_getAllHandler= getAllHandler;
|
||||
_createHandler= createHandler;
|
||||
_updateHandler= updateHandler;
|
||||
_changeStatusHandler= changeStatusHandler;
|
||||
_port= port;
|
||||
}
|
||||
|
||||
[HttpGet("GetAll")]
|
||||
public async Task<IActionResult> GetAllAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await _getAllHandler.ExecuteAsync(new GetAllFurnitureBaseRequest { }, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
|
||||
[HttpPost("GetById")]
|
||||
public async Task<IActionResult> GetByIdAsync([FromBody] GetFurnitureBaseByIdRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(request?.Id)) return BadRequest("Furniture base identifier is required");
|
||||
|
||||
await _getByIdHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
|
||||
[HttpPost("Create")]
|
||||
public async Task<IActionResult> CreateAsync([FromBody] CreateFurnitureBaseRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _createHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
|
||||
[HttpPut("Update")]
|
||||
public async Task<IActionResult> UpdateAsync([FromBody] UpdateFurnitureBaseRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _updateHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
|
||||
[HttpPatch("ChangeStatus")]
|
||||
public async Task<IActionResult> ChangeStatusAsync([FromBody] ChangeFurnitureBaseStatusRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(request?.Id)) return BadRequest("Furniture base identifier is required");
|
||||
|
||||
await _changeStatusHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
using Asp.Versioning;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Ports;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Core.Inventory.Service.API.Controllers
|
||||
{
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/v{api-version:apiVersion}/[controller]")]
|
||||
[Produces("application/json")]
|
||||
[ApiController]
|
||||
public class FurnitureVariantController(
|
||||
IComponentHandler<GetFurnitureVariantByIdRequest> getByIdHandler,
|
||||
IComponentHandler<GetAllFurnitureVariantsByModelIdRequest> getAllHandler,
|
||||
IComponentHandler<CreateFurnitureVariantRequest> createHandler,
|
||||
IComponentHandler<UpdateFurnitureVariantRequest> updateHandler,
|
||||
IComponentHandler<ChangeFurnitureVariantStatusRequest> changeStatusHandler,
|
||||
IFurnitureVariantPort port) : ControllerBase
|
||||
{
|
||||
private readonly IComponentHandler<GetFurnitureVariantByIdRequest> _getByIdHandler = getByIdHandler;
|
||||
private readonly IComponentHandler<GetAllFurnitureVariantsByModelIdRequest> _getAllHandler = getAllHandler;
|
||||
private readonly IComponentHandler<CreateFurnitureVariantRequest> _createHandler = createHandler;
|
||||
private readonly IComponentHandler<UpdateFurnitureVariantRequest> _updateHandler = updateHandler;
|
||||
private readonly IComponentHandler<ChangeFurnitureVariantStatusRequest> _changeStatusHandler = changeStatusHandler;
|
||||
private readonly IFurnitureVariantPort _port = port;
|
||||
|
||||
[HttpGet("GetAllByModelId")]
|
||||
public async Task<IActionResult> GetAllAsync([FromQuery] string modelId, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(modelId)) return BadRequest("Model ID is required");
|
||||
|
||||
var request = new GetAllFurnitureVariantsByModelIdRequest { ModelId = modelId };
|
||||
await _getAllHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
|
||||
[HttpPost("GetById")]
|
||||
public async Task<IActionResult> GetByIdAsync([FromBody] GetFurnitureVariantByIdRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(request?.Id)) return BadRequest("Furniture variant identifier is required");
|
||||
|
||||
await _getByIdHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
|
||||
[HttpPost("Create")]
|
||||
public async Task<IActionResult> CreateAsync([FromBody] CreateFurnitureVariantRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _createHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
|
||||
[HttpPut("Update")]
|
||||
public async Task<IActionResult> UpdateAsync([FromBody] UpdateFurnitureVariantRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _updateHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
|
||||
[HttpPatch("ChangeStatus")]
|
||||
public async Task<IActionResult> ChangeStatusAsync([FromBody] ChangeFurnitureVariantStatusRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(request?.Id)) return BadRequest("Furniture variant identifier is required");
|
||||
|
||||
await _changeStatusHandler.ExecuteAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return _port.ViewModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
Core.Inventory.Service.API/Core.Inventory.Service.API.csproj
Normal file
20
Core.Inventory.Service.API/Core.Inventory.Service.API.csproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
|
||||
<PackageReference Include="Core.Blueprint.Logging" Version="1.0.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core.Inventory.Application\Core.Inventory.Application.csproj" />
|
||||
<ProjectReference Include="..\Core.Inventory.External\Core.Inventory.External.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -0,0 +1,6 @@
|
||||
@Core.Inventory.Service.API_HostAddress = http://localhost:5257
|
||||
|
||||
GET {{Core.Inventory.Service.API_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
@ -0,0 +1,65 @@
|
||||
using Core.Inventory.Application.UseCases.Inventory;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Adapter;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Input;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Ports;
|
||||
using Core.Inventory.Application.UseCases.Inventory.Validator;
|
||||
using FluentValidation;
|
||||
using Lib.Architecture.BuildingBlocks;
|
||||
|
||||
namespace Core.Inventory.Service.API.Extensions
|
||||
{
|
||||
public static class ServiceCollectionExtension
|
||||
{
|
||||
public static IServiceCollection AddServiceConfigurationLayer(this IServiceCollection services)
|
||||
{
|
||||
#region FurnitureBase
|
||||
services.AddScoped<IFurnitureBasePort, FurnitureBasePort>();
|
||||
|
||||
services.AddScoped<IComponentHandler<GetAllFurnitureBaseRequest>, InventoryHandler>();
|
||||
services.AddScoped<IComponentHandler<GetFurnitureBaseByIdRequest>, InventoryHandler>();
|
||||
services.AddScoped<IComponentHandler<CreateFurnitureBaseRequest>, InventoryHandler>();
|
||||
services.AddScoped<IComponentHandler<UpdateFurnitureBaseRequest>, InventoryHandler>();
|
||||
services.AddScoped<IComponentHandler<ChangeFurnitureBaseStatusRequest>, InventoryHandler>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<CreateFurnitureBaseValidator>();
|
||||
services.AddScoped<IValidator<CreateFurnitureBaseRequest>, CreateFurnitureBaseValidator>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<UpdateFurnitureBaseValidator>();
|
||||
services.AddScoped<IValidator<UpdateFurnitureBaseRequest>, UpdateFurnitureBaseValidator>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<ChangeFurnitureBaseStatusValidator>();
|
||||
services.AddScoped<IValidator<ChangeFurnitureBaseStatusRequest>, ChangeFurnitureBaseStatusValidator>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<GetFurnitureBaseByIdValidator>();
|
||||
services.AddScoped<IValidator<GetFurnitureBaseByIdRequest>, GetFurnitureBaseByIdValidator>();
|
||||
#endregion
|
||||
|
||||
#region FurnitureVariant
|
||||
services.AddScoped<IFurnitureVariantPort, FurnitureVariantPort>();
|
||||
|
||||
services.AddScoped<IComponentHandler<GetAllFurnitureVariantsByModelIdRequest>, InventoryHandler>();
|
||||
services.AddScoped<IComponentHandler<GetFurnitureVariantByIdRequest>, InventoryHandler>();
|
||||
services.AddScoped<IComponentHandler<CreateFurnitureVariantRequest>, InventoryHandler>();
|
||||
services.AddScoped<IComponentHandler<UpdateFurnitureVariantRequest>, InventoryHandler>();
|
||||
services.AddScoped<IComponentHandler<ChangeFurnitureVariantStatusRequest>, InventoryHandler>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<CreateFurnitureVariantValidator>();
|
||||
services.AddScoped<IValidator<CreateFurnitureVariantRequest>, CreateFurnitureVariantValidator>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<UpdateFurnitureVariantValidator>();
|
||||
services.AddScoped<IValidator<UpdateFurnitureVariantRequest>, UpdateFurnitureVariantValidator>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<ChangeFurnitureVariantStatusValidator>();
|
||||
services.AddScoped<IValidator<ChangeFurnitureVariantStatusRequest>, ChangeFurnitureVariantStatusValidator>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<GetFurnitureVariantByIdValidator>();
|
||||
services.AddScoped<IValidator<GetFurnitureVariantByIdRequest>, GetFurnitureVariantByIdValidator>();
|
||||
|
||||
services.AddValidatorsFromAssemblyContaining<GetAllFurnitureVariantsByModelIdValidator>();
|
||||
services.AddScoped<IValidator<GetAllFurnitureVariantsByModelIdRequest>, GetAllFurnitureVariantsByModelIdValidator>();
|
||||
#endregion
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Core.Inventory.Service.API/Extensions/SwaggerExtensions.cs
Normal file
98
Core.Inventory.Service.API/Extensions/SwaggerExtensions.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using Asp.Versioning.ApiExplorer;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||
|
||||
namespace Core.Inventory.Service.API.Extensions
|
||||
{
|
||||
public static class SwaggerExtensions
|
||||
{
|
||||
public static void AddSwagger(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddEndpointsApiExplorer();
|
||||
AddSwaggerGen(services, configuration);
|
||||
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures Swagger generation with OAuth2 security and XML comments.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
|
||||
/// <param name="configuration">The <see cref="IConfiguration"/> containing Swagger and OAuth2 configuration settings.</param>
|
||||
public static void AddSwaggerGen(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Description = "JWT Authorization header using the Bearer scheme",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.Http,
|
||||
Scheme = "bearer",
|
||||
BearerFormat = "JWT"
|
||||
});
|
||||
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
Array.Empty<string>()
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
public static void ConfigureSwagger(this WebApplication app)
|
||||
{
|
||||
//Swagger Stuff Goes Here
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
foreach (var version in app.DescribeApiVersions().Select(version => version.GroupName))
|
||||
options.SwaggerEndpoint($"/swagger/{version}/swagger.json", version);
|
||||
|
||||
options.DisplayRequestDuration();
|
||||
options.EnableTryItOutByDefault();
|
||||
options.DocExpansion(DocExpansion.None);
|
||||
});
|
||||
}
|
||||
|
||||
public static IServiceCollection AddVersioning(this IServiceCollection services)
|
||||
{
|
||||
services.AddApiVersioning(options => options.ReportApiVersions = true)
|
||||
.AddApiExplorer(options =>
|
||||
{
|
||||
options.GroupNameFormat = "'v'VVV";
|
||||
options.SubstituteApiVersionInUrl = true;
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
public class ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) : IConfigureOptions<SwaggerGenOptions>
|
||||
{
|
||||
private readonly IApiVersionDescriptionProvider _provider = provider;
|
||||
|
||||
public void Configure(SwaggerGenOptions options)
|
||||
{
|
||||
foreach (var description in _provider.ApiVersionDescriptions)
|
||||
options.SwaggerDoc(description.GroupName, new()
|
||||
{
|
||||
Title = AppDomain.CurrentDomain.FriendlyName,
|
||||
Version = description.ApiVersion.ToString()
|
||||
});
|
||||
|
||||
|
||||
options.CustomSchemaIds(type => type.ToString().Replace("+", "."));
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Core.Inventory.Service.API/Program.cs
Normal file
80
Core.Inventory.Service.API/Program.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using Core.Blueprint.Logging.Configuration;
|
||||
using Core.Inventory.External.ClientConfiguration;
|
||||
using Core.Inventory.Service.API.Extensions;
|
||||
using Microsoft.AspNetCore.HttpLogging;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddLogs(builder);
|
||||
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
builder.Configuration
|
||||
.AddUserSecrets(Assembly.GetExecutingAssembly())
|
||||
.AddEnvironmentVariables();
|
||||
|
||||
builder.Services.RegisterExternalLayer(builder.Configuration);
|
||||
builder.Services.AddServiceConfigurationLayer();
|
||||
builder.Services.AddResponseCompression();
|
||||
builder.Services.AddProblemDetails();
|
||||
builder.Services.AddMemoryCache();
|
||||
|
||||
builder.Host.ConfigureServices((context, services) =>
|
||||
{
|
||||
|
||||
services.AddLogging();
|
||||
services.AddControllers();
|
||||
services.AddProblemDetails();
|
||||
services.AddCors(options
|
||||
=> options.AddDefaultPolicy(policyBuilder
|
||||
=> policyBuilder
|
||||
.AllowAnyOrigin()
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod()));
|
||||
|
||||
builder.Services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options =>
|
||||
{
|
||||
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||
});
|
||||
|
||||
services
|
||||
.AddEndpointsApiExplorer()
|
||||
.AddVersioning()
|
||||
.AddSwagger(builder.Configuration);
|
||||
|
||||
services.AddHealthChecks();
|
||||
services.AddHttpLogging(options => options.LoggingFields = HttpLoggingFields.All);
|
||||
|
||||
builder.Services.AddOutputCache(options =>
|
||||
{
|
||||
options.AddBasePolicy(builder =>
|
||||
builder.Expire(TimeSpan.FromSeconds(10)));
|
||||
options.AddPolicy("Expire20", builder =>
|
||||
builder.Expire(TimeSpan.FromSeconds(20)));
|
||||
options.AddPolicy("Expire30", builder =>
|
||||
builder.Expire(TimeSpan.FromSeconds(30)));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseRouting();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
app.UseCors();
|
||||
app.ConfigureSwagger();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseResponseCompression();
|
||||
app.UseOutputCache();
|
||||
app.UseResponseCaching();
|
||||
app.UseLogging(builder.Configuration);
|
||||
app.MapHealthChecks("/health");
|
||||
|
||||
app.Run();
|
||||
41
Core.Inventory.Service.API/Properties/launchSettings.json
Normal file
41
Core.Inventory.Service.API/Properties/launchSettings.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:58212",
|
||||
"sslPort": 44339
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5257",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Local"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7028;http://localhost:5257",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Local"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Local"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Core.Inventory.Service.API/WeatherForecast.cs
Normal file
13
Core.Inventory.Service.API/WeatherForecast.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace Core.Inventory.Service.API
|
||||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
9
Core.Inventory.Service.API/appsettings.Development.json
Normal file
9
Core.Inventory.Service.API/appsettings.Development.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
12
Core.Inventory.Service.API/appsettings.Local.json
Normal file
12
Core.Inventory.Service.API/appsettings.Local.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"LocalGateways": {
|
||||
"InventoryDAL": "https://localhost:7037"
|
||||
}
|
||||
}
|
||||
9
Core.Inventory.Service.API/appsettings.json
Normal file
9
Core.Inventory.Service.API/appsettings.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
46
Core.Inventory.Service.sln
Normal file
46
Core.Inventory.Service.sln
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36212.18 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Inventory.Service.API", "Core.Inventory.Service.API\Core.Inventory.Service.API.csproj", "{877AA831-C2E1-4926-AB6B-340ACCD88474}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Application", "Application", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Presentation", "Presentation", "{FAA84161-ED65-46CF-AC03-998CBDC8FCD3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Inventory.Application", "Core.Inventory.Application\Core.Inventory.Application.csproj", "{BA083BDD-F32A-4040-88F9-DC2DE767FB7A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Inventory.External", "Core.Inventory.External\Core.Inventory.External.csproj", "{C2C165F5-7787-4EE7-A335-31B59673BFCB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{877AA831-C2E1-4926-AB6B-340ACCD88474}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{877AA831-C2E1-4926-AB6B-340ACCD88474}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{877AA831-C2E1-4926-AB6B-340ACCD88474}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{877AA831-C2E1-4926-AB6B-340ACCD88474}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BA083BDD-F32A-4040-88F9-DC2DE767FB7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BA083BDD-F32A-4040-88F9-DC2DE767FB7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BA083BDD-F32A-4040-88F9-DC2DE767FB7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BA083BDD-F32A-4040-88F9-DC2DE767FB7A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C2C165F5-7787-4EE7-A335-31B59673BFCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C2C165F5-7787-4EE7-A335-31B59673BFCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C2C165F5-7787-4EE7-A335-31B59673BFCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C2C165F5-7787-4EE7-A335-31B59673BFCB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{877AA831-C2E1-4926-AB6B-340ACCD88474} = {FAA84161-ED65-46CF-AC03-998CBDC8FCD3}
|
||||
{BA083BDD-F32A-4040-88F9-DC2DE767FB7A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{C2C165F5-7787-4EE7-A335-31B59673BFCB} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E943164B-39DF-481C-8CF1-A2B1D97F90BA}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Loading…
Reference in New Issue
Block a user