Compare commits
46 Commits
lab-2-no-l
...
lab-7-hard
| Author | SHA1 | Date | |
|---|---|---|---|
| d7b6039323 | |||
| b13ae5a0f6 | |||
| 6daf8317e0 | |||
| 8dc9cc8995 | |||
| 6134ab544d | |||
| f96a4906d0 | |||
| b9fbb33468 | |||
| 7d7c2bd522 | |||
| 813564aece | |||
| a21f0e3d88 | |||
| 235b06a497 | |||
| 3501f2a724 | |||
| 00a8846f33 | |||
| 86881f7317 | |||
| d51c616862 | |||
| 4518d36016 | |||
| c692f50d0d | |||
| e7dcfd6f30 | |||
| a3e1230e5c | |||
| 8f5c38d239 | |||
| dbc3fb8394 | |||
| 524bfca4d0 | |||
| 6b7212a13d | |||
| 4113d2ab9e | |||
| d295b50e32 | |||
| f9966ae73d | |||
| d84b3850d6 | |||
| 6449c0df73 | |||
| 7beb84b967 | |||
| 082111e301 | |||
| 14b48e3a30 | |||
| f649754da7 | |||
| e0f0af6754 | |||
| cec7b9240e | |||
| dbde99c7eb | |||
| d2f7afae63 | |||
| fa6b1b64a2 | |||
| bdb510f098 | |||
| 75c5ceabc0 | |||
| 514f2adefb | |||
| 6ad09c5ff2 | |||
| 807ac64a9f | |||
| ffaeb985e5 | |||
| 7b71b14c71 | |||
| b481914563 | |||
| b7c31860e1 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -10,7 +10,7 @@
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
*.idea
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
@@ -247,9 +247,9 @@ orleans.codegen.cs
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_ingredients
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
#bower_ingredients/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
@@ -414,3 +414,4 @@ FodyWeavers.xsd
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
/.idea/
|
||||
|
||||
6
.idea/.idea.PIBD24_BoikoM.S._Candyhouse.dir/.idea/vcs.xml
generated
Normal file
6
.idea/.idea.PIBD24_BoikoM.S._Candyhouse.dir/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
6
CandyHouseSolution/.idea/.idea.CandyHouseSolution/.idea/vcs.xml
generated
Normal file
6
CandyHouseSolution/.idea/.idea.CandyHouseSolution/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -1,3 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("CandyHouseTests")]
|
||||
@@ -1,172 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="8.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
|
||||
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')"/>
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{5DF70B46-31F7-4D15-8C60-52C0A0A364F0}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CandyHouseBase</RootNamespace>
|
||||
<AssemblyName>CandyHouseBase</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<LangVersion>12</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=5.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.5.1.1\lib\net462\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.0-preview.1.25080.5\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=10.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.10.0.0-preview.1.25080.5\lib\net462\Microsoft.Extensions.DependencyInjection.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=10.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.10.0.0-preview.1.25080.5\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging, Version=10.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.10.0.0-preview.1.25080.5\lib\net462\Microsoft.Extensions.Logging.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=10.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.10.0.0-preview.1.25080.5\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Options, Version=10.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Options.10.0.0-preview.1.25080.5\lib\net462\Microsoft.Extensions.Options.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Primitives, Version=10.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Primitives.10.0.0-preview.1.25080.5\lib\net462\Microsoft.Extensions.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.20.72.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.20.72\lib\net462\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System"/>
|
||||
<Reference Include="System.Buffers, Version=4.0.4.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.6.0\lib\net462\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core"/>
|
||||
<Reference Include="System.Data"/>
|
||||
<Reference Include="System.Diagnostics.DiagnosticSource, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.10.0.0-preview.1.25080.5\lib\net462\System.Diagnostics.DiagnosticSource.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Pipelines, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Pipelines.10.0.0-preview.1.25080.5\lib\net462\System.IO.Pipelines.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Memory, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.6.0\lib\net462\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.6.0\lib\net462\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.1.0\lib\net462\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Encodings.Web, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Encodings.Web.10.0.0-preview.1.25080.5\lib\net462\System.Text.Encodings.Web.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Json.10.0.0-preview.1.25080.5\lib\net462\System.Text.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.6.0\lib\net462\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyInfo.cs" />
|
||||
<Compile Include="DataModels\IngredientDataModel.cs" />
|
||||
<Compile Include="DataModels\OrderDataModel.cs" />
|
||||
<Compile Include="DataModels\PekarDataModel.cs" />
|
||||
<Compile Include="DataModels\PekarHistoryDataModel.cs" />
|
||||
<Compile Include="DataModels\PositionDataModel.cs" />
|
||||
<Compile Include="DataModels\ProductDataModel.cs" />
|
||||
<Compile Include="DataModels\RecipeDataModel.cs" />
|
||||
<Compile Include="DataModels\SalaryDataModel.cs" />
|
||||
<Compile Include="Enums\PositionType.cs" />
|
||||
<Compile Include="Enums\StatusType.cs" />
|
||||
<Compile Include="Exceptions\DateTimeExtensions.cs" />
|
||||
<Compile Include="Exceptions\ElementExistsException.cs" />
|
||||
<Compile Include="Exceptions\ElementNotFoundException.cs" />
|
||||
<Compile Include="Exceptions\IncorrectDatesException.cs" />
|
||||
<Compile Include="Exceptions\NullListException.cs" />
|
||||
<Compile Include="Exceptions\StorageException.cs" />
|
||||
<Compile Include="Exceptions\ValidationException.cs" />
|
||||
<Compile Include="Extensions\StringExtensions.cs" />
|
||||
<Compile Include="Implementations\IngredientBusinessLogicContract.cs" />
|
||||
<Compile Include="Implementations\OrderBusinessLogicContract.cs" />
|
||||
<Compile Include="Implementations\PekarBusinessLogicContract.cs" />
|
||||
<Compile Include="Implementations\PositionBusinessLogicContract.cs" />
|
||||
<Compile Include="Implementations\ProductBusinessLogicContract.cs" />
|
||||
<Compile Include="Implementations\SalaryBusinessLogicContract.cs" />
|
||||
<Compile Include="Infrastructure\IValidation.cs" />
|
||||
<Compile Include="Interfaces\BusinessLogicsContracts\IIngredientBusinessLogicContact.cs" />
|
||||
<Compile Include="Interfaces\BusinessLogicsContracts\IOrderBusinessLogicContact.cs" />
|
||||
<Compile Include="Interfaces\BusinessLogicsContracts\IPekarBusinessLogicContact.cs" />
|
||||
<Compile Include="Interfaces\BusinessLogicsContracts\IPositionBusinessLogicContact.cs" />
|
||||
<Compile Include="Interfaces\BusinessLogicsContracts\IProductBusinessLogicContact.cs" />
|
||||
<Compile Include="Interfaces\BusinessLogicsContracts\ISalaryBusinessLogicContact.cs" />
|
||||
<Compile Include="Interfaces\StoragesContracts\IIngredientStorageContact.cs" />
|
||||
<Compile Include="Interfaces\StoragesContracts\IOrderStorageContact.cs" />
|
||||
<Compile Include="Interfaces\StoragesContracts\IPekarStorageContact.cs" />
|
||||
<Compile Include="Interfaces\StoragesContracts\IPositionStorageContact.cs" />
|
||||
<Compile Include="Interfaces\StoragesContracts\IProductStorageContact.cs" />
|
||||
<Compile Include="Interfaces\StoragesContracts\ISalaryStorageContact.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="CatHasPawsTests" />
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="ILLink\ILLink.Descriptors.LibraryBuild.xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets"/>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>$(AssemblyName).Test.dll</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,31 +0,0 @@
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Extensions;
|
||||
using CandyHouseBase.Infrastructure;
|
||||
|
||||
namespace CandyHouseBase.DataModels
|
||||
{
|
||||
public class IngredientDataModel : IValidation
|
||||
{
|
||||
public string Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string Unit { get; private set; }
|
||||
public decimal Cost { get; private set; }
|
||||
|
||||
public IngredientDataModel(string id, string name, string unit, decimal cost)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Unit = unit;
|
||||
Cost = cost;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Id.IsEmpty()) throw new ValidationException("Field Id is empty");
|
||||
if (!Id.IsGuid()) throw new ValidationException("Id must be a GUID");
|
||||
if (Name.IsEmpty()) throw new ValidationException("Field Name is empty");
|
||||
if (Unit.IsEmpty()) throw new ValidationException("Field Unit is empty");
|
||||
if (Cost < 0) throw new ValidationException("Cost must be non-negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using CandyHouseBase.Enums;
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Extensions;
|
||||
using CandyHouseBase.Infrastructure;
|
||||
|
||||
namespace CandyHouseBase.DataModels
|
||||
{
|
||||
public class OrderDataModel : IValidation
|
||||
{
|
||||
public string Id { get; private set; }
|
||||
public string CustomerName { get; private set; } // Может быть null, если клиент разовый
|
||||
public DateTime OrderDate { get; private set; }
|
||||
public decimal TotalAmount { get; private set; }
|
||||
public decimal DiscountAmount { get; private set; }
|
||||
public string ProductId { get; private set; }
|
||||
public string PekarId { get; private set; }
|
||||
public StatusType StatusType { get; private set; }
|
||||
|
||||
public OrderDataModel(string id, string customerName, DateTime orderDate, decimal totalAmount,
|
||||
decimal discountAmount, string productId, string pekarId, StatusType statusType)
|
||||
{
|
||||
Id = id;
|
||||
CustomerName = customerName;
|
||||
OrderDate = orderDate;
|
||||
TotalAmount = totalAmount;
|
||||
DiscountAmount = discountAmount;
|
||||
ProductId = productId;
|
||||
PekarId = pekarId;
|
||||
StatusType = statusType;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Id.IsEmpty()) throw new ValidationException("Field Id is empty");
|
||||
if (!Id.IsGuid()) throw new ValidationException("Id must be a GUID");
|
||||
if (CustomerName.IsEmpty())
|
||||
throw new ValidationException("CustomerName is empty");
|
||||
if (TotalAmount < 0) throw new ValidationException("TotalAmount cannot be negative");
|
||||
if (DiscountAmount < 0) throw new ValidationException("DiscountAmount cannot be negative");
|
||||
if (ProductId.IsEmpty()) throw new ValidationException("Field productId is empty");
|
||||
if (!ProductId.IsGuid()) throw new ValidationException("productId must be a GUID");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Infrastructure;
|
||||
using CandyHouseBase.Extensions;
|
||||
|
||||
namespace CandyHouseBase.DataModels
|
||||
{
|
||||
public class PekarDataModel : IValidation
|
||||
{
|
||||
public string Id { get; private set; }
|
||||
public string FIO { get; private set; }
|
||||
public string Position { get; private set; }
|
||||
public decimal BonusCoefficient { get; private set; }
|
||||
public List<ProductDataModel> ProductsItems { get; private set; }
|
||||
|
||||
|
||||
public PekarDataModel(string id, string fio, string position, decimal bonusCoefficient,
|
||||
List<ProductDataModel> productsItems)
|
||||
{
|
||||
Id = id;
|
||||
FIO = fio;
|
||||
Position = position;
|
||||
BonusCoefficient = bonusCoefficient;
|
||||
ProductsItems = productsItems;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Id.IsEmpty()) throw new ValidationException("Field Id is empty");
|
||||
if (!Id.IsGuid()) throw new ValidationException("Id must be a GUID");
|
||||
if (FIO.IsEmpty()) throw new ValidationException("Field FIO is empty");
|
||||
var fioPattern = @"^[A-Za-zА-Яа-яЁё\s\-]+$";
|
||||
if (!Regex.IsMatch(FIO, fioPattern))
|
||||
throw new ValidationException("FIO contains invalid characters");
|
||||
|
||||
if (Position.IsEmpty()) throw new ValidationException("Field Position is empty");
|
||||
if (!Position.IsGuid()) throw new ValidationException("Field must be a GUID");
|
||||
if (BonusCoefficient <= 0) throw new ValidationException("BonusCoefficient must be positive");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Infrastructure;
|
||||
using CandyHouseBase.Extensions;
|
||||
|
||||
namespace CandyHouseBase.DataModels
|
||||
{
|
||||
public class PekarHistoryDataModel : IValidation
|
||||
{
|
||||
public string PekarId { get; private set; }
|
||||
public string FIO { get; private set; }
|
||||
public string PositionId { get; private set; }
|
||||
public DateTime Date { get; private set; }
|
||||
public decimal BonusCoefficient { get; private set; }
|
||||
|
||||
public PekarHistoryDataModel(string peKarId, string fio, string positionId, decimal bonusCoefficient, DateTime dateTime)
|
||||
{
|
||||
PekarId = peKarId;
|
||||
FIO = fio;
|
||||
PositionId = positionId;
|
||||
BonusCoefficient = bonusCoefficient;
|
||||
Date = dateTime;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (PekarId.IsEmpty()) throw new ValidationException("Field Id is empty");
|
||||
if (!PekarId.IsGuid()) throw new ValidationException("Id must be a GUID");
|
||||
if (FIO.IsEmpty()) throw new ValidationException("Field FIO is empty");
|
||||
if (PositionId.IsEmpty()) throw new ValidationException("Field Position is empty");
|
||||
if (!PositionId.IsGuid()) throw new ValidationException("Field must be a GUID");
|
||||
if (BonusCoefficient <= 0) throw new ValidationException("BonusCoefficient must be positive");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using CandyHouseBase.Enums;
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Extensions;
|
||||
using CandyHouseBase.Infrastructure;
|
||||
|
||||
namespace CandyHouseBase.DataModels
|
||||
{
|
||||
public class PositionDataModel : IValidation
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public PositionType Type { get; set; }
|
||||
public string Title { get; set; }
|
||||
|
||||
public PositionDataModel(string id, PositionType type, string title)
|
||||
{
|
||||
Id = id;
|
||||
Type = type;
|
||||
Title = title;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Id.IsEmpty()) throw new ValidationException("Field Id is empty");
|
||||
if (!Id.IsGuid()) throw new ValidationException("Id must be a GUID");
|
||||
var titlePattern = @"^[A-Za-zА-Яа-яЁё\s\-]+$";
|
||||
if (!Regex.IsMatch(Title, titlePattern))
|
||||
throw new ValidationException("FIO contains invalid characters");
|
||||
|
||||
if (string.IsNullOrEmpty(Title)) throw new ValidationException("Field Title is empty");
|
||||
if (!Enum.IsDefined(typeof(PositionType), Type)) throw new ValidationException("Invalid PositionType");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Extensions;
|
||||
using CandyHouseBase.Infrastructure;
|
||||
|
||||
namespace CandyHouseBase.DataModels
|
||||
{
|
||||
public class ProductDataModel : IValidation
|
||||
{
|
||||
public string Id { get; private set; }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => name;
|
||||
set
|
||||
{
|
||||
if (!name.IsEmpty()) OldName = name;
|
||||
name = value.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get => description;
|
||||
set
|
||||
{
|
||||
if (!description.IsEmpty()) OldDescription = description;
|
||||
description = value.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public string OldName { get; private set; }
|
||||
|
||||
public string OldDescription { get; private set; }
|
||||
|
||||
private string name;
|
||||
private string description;
|
||||
|
||||
public List<IngredientDataModel> IngredientsItems { get; private set; }
|
||||
|
||||
public ProductDataModel(string id, string name, string description, List<IngredientDataModel> ingredients)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Description = description;
|
||||
IngredientsItems = ingredients;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Id.IsEmpty()) throw new ValidationException("Field Id is empty");
|
||||
if (!Id.IsGuid()) throw new ValidationException("Id must be a GUID");
|
||||
if (Name.IsEmpty()) throw new ValidationException("Field Name is empty");
|
||||
if (Description.IsEmpty()) throw new ValidationException("Field Description is empty");
|
||||
if (IngredientsItems.Count == 0) throw new ValidationException("Field IngredientsItems is empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Extensions;
|
||||
using CandyHouseBase.Infrastructure;
|
||||
|
||||
namespace CandyHouseBase.DataModels
|
||||
{
|
||||
public class RecipeDataModel : IValidation
|
||||
{
|
||||
public string ProductId { get; private set; }
|
||||
public string IngredientId { get; private set; }
|
||||
public int Quantity { get; private set; }
|
||||
|
||||
public RecipeDataModel(string productId, string ingredientId, int quantity)
|
||||
{
|
||||
ProductId = productId;
|
||||
IngredientId = ingredientId;
|
||||
Quantity = quantity;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (!ProductId.IsGuid()) throw new ValidationException("ProductId must be a GUID");
|
||||
if (!IngredientId.IsGuid()) throw new ValidationException("IngredientId must be a GUID");
|
||||
if (Quantity <= 0) throw new ValidationException("Quantity must be positive");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using System;
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Extensions;
|
||||
using CandyHouseBase.Infrastructure;
|
||||
|
||||
namespace CandyHouseBase.DataModels
|
||||
{
|
||||
public class SalaryDataModel : IValidation
|
||||
{
|
||||
public string Id { get; private set; }
|
||||
public string PekarId { get; private set; }
|
||||
public DateTime Period { get; private set; }
|
||||
public decimal BaseRate { get; private set; }
|
||||
public decimal BonusRate { get; private set; }
|
||||
public decimal TotalSalary { get; private set; }
|
||||
|
||||
public SalaryDataModel(string id, string pekarId, DateTime period, decimal baseRate, decimal bonusRate, decimal totalSalary)
|
||||
{
|
||||
Id = id;
|
||||
PekarId = pekarId;
|
||||
Period = period;
|
||||
BaseRate = baseRate;
|
||||
BonusRate = bonusRate;
|
||||
TotalSalary = totalSalary;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (Id.IsEmpty()) throw new ValidationException("Field Id is empty");
|
||||
if (!Id.IsGuid()) throw new ValidationException("Id must be a GUID");
|
||||
if (PekarId.IsEmpty()) throw new ValidationException("Field PekarId is empty");
|
||||
if (!PekarId.IsGuid()) throw new ValidationException("PekarId must be a GUID");
|
||||
if (BaseRate < 0) throw new ValidationException("BaseRate cannot be negative");
|
||||
if (BonusRate < 0) throw new ValidationException("BonusRate cannot be negative");
|
||||
if (TotalSalary < 0) throw new ValidationException("TotalSalary cannot be negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace CandyHouseBase.Enums
|
||||
{
|
||||
public enum PositionType
|
||||
{
|
||||
None = 1,
|
||||
Small = 2,
|
||||
Medium = 3,
|
||||
Cool = 4,
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace CandyHouseBase.Enums
|
||||
{
|
||||
public enum StatusType
|
||||
{
|
||||
Pending,
|
||||
Completed,
|
||||
Cancelled,
|
||||
InProgress
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace CandyHouseBase.Exceptions;
|
||||
|
||||
public class ElementExistsException : Exception
|
||||
{
|
||||
public string ParamName { get; private set; }
|
||||
public string ParamValue { get; private set; }
|
||||
|
||||
public ElementExistsException(string paramName, string paramValue) :
|
||||
base($"There is already an element with value {paramValue} of parameter {paramName}")
|
||||
{
|
||||
ParamName = paramName;
|
||||
ParamValue = paramValue;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace CandyHouseBase.Exceptions;
|
||||
|
||||
public class ElementNotFoundException : Exception
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
|
||||
public ElementNotFoundException(string value) : base($"Element not found at value = {value}")
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace CandyHouseBase.Exceptions;
|
||||
|
||||
public class IncorrectDatesException : Exception
|
||||
{
|
||||
public IncorrectDatesException(DateTime start, DateTime end) : base(
|
||||
$"The end date must be later than the start date.. StartDate: {start:dd.MM.YYYY}. EndDate: {end:dd.MM.YYYY}")
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace CandyHouseBase.Exceptions;
|
||||
|
||||
public class NullListException : Exception
|
||||
{
|
||||
public NullListException() : base("The returned list is null")
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace CandyHouseBase.Exceptions;
|
||||
|
||||
public class StorageException : Exception
|
||||
|
||||
{
|
||||
public StorageException(Exception ex) : base($"Error while working in storage: {ex.Message}", ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace CandyHouseBase.Exceptions
|
||||
{
|
||||
public class ValidationException : Exception
|
||||
{
|
||||
public ValidationException(string message) : base(message) { }
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace CandyHouseBase.Extensions
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static bool IsEmpty(this string str) => string.IsNullOrWhiteSpace(str);
|
||||
public static bool IsGuid(this string str) => Guid.TryParse(str, out _);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
|
||||
using CandyHouseBase.Interfaces.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CandyHouseBase.Implementations
|
||||
{
|
||||
internal class IngredientBusinessLogicContract(
|
||||
IIngredientStorageContact ingredientStorageContact,
|
||||
ILogger logger)
|
||||
: IIngredientBusinessLogicContact
|
||||
{
|
||||
private readonly IIngredientStorageContact _ingredientStorageContact = ingredientStorageContact;
|
||||
private readonly ILogger _logger = logger;
|
||||
|
||||
public List<IngredientDataModel> GetAllIngredients()
|
||||
{
|
||||
return new List<IngredientDataModel>();
|
||||
}
|
||||
|
||||
public IngredientDataModel GetIngredientByData(string data)
|
||||
{
|
||||
return new IngredientDataModel("", "", "", 100);
|
||||
}
|
||||
|
||||
public void InsertIngredient(IngredientDataModel ingredient)
|
||||
{
|
||||
}
|
||||
|
||||
public void UpdateIngredient(IngredientDataModel ingredient)
|
||||
{
|
||||
}
|
||||
|
||||
public void DeleteIngredient(string id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
using CandyHouseBase.Enums;
|
||||
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
|
||||
using CandyHouseBase.Interfaces.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CandyHouseBase.Implementations
|
||||
{
|
||||
internal class OrderBusinessLogicContract(
|
||||
IOrderStorageContact orderStorageContact,
|
||||
IPekarStorageContact pekarStorageContact,
|
||||
IProductStorageContact productStorageContact,
|
||||
ILogger logger)
|
||||
: IOrderBusinessLogicContact
|
||||
{
|
||||
private readonly IOrderStorageContact _orderStorageContact = orderStorageContact;
|
||||
private readonly IPekarStorageContact _pekarStorageContact = pekarStorageContact;
|
||||
private readonly IProductStorageContact _productStorageContact = productStorageContact;
|
||||
private readonly ILogger _logger = logger;
|
||||
|
||||
public List<OrderDataModel> GetAllOrders()
|
||||
{
|
||||
return new List<OrderDataModel>();
|
||||
}
|
||||
|
||||
public OrderDataModel GetOrderByData(string data)
|
||||
{
|
||||
return new OrderDataModel("", "", new DateTime(),
|
||||
100, 100m, "", "", StatusType.Cancelled);
|
||||
}
|
||||
|
||||
public void InsertOrder(OrderDataModel order)
|
||||
{
|
||||
}
|
||||
|
||||
public void UpdateOrder(OrderDataModel order)
|
||||
{
|
||||
}
|
||||
|
||||
public void DeleteOrder(string id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
using CandyHouseBase.Enums;
|
||||
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
|
||||
using CandyHouseBase.Interfaces.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CandyHouseBase.Implementations
|
||||
{
|
||||
internal class PekarBusinessLogicContract(
|
||||
IPekarStorageContact pekarStorageContact,
|
||||
IProductStorageContact productStorageContact,
|
||||
IPositionStorageContact positionStorageContact,
|
||||
ILogger logger)
|
||||
: IPekarBusinessLogicContact
|
||||
{
|
||||
private readonly IPekarStorageContact _pekarStorageContact = pekarStorageContact;
|
||||
private readonly IProductStorageContact _productStorageContact = productStorageContact;
|
||||
private readonly IPositionStorageContact _positionStorageContact = positionStorageContact;
|
||||
private readonly ILogger _logger = logger;
|
||||
|
||||
public List<PekarDataModel> GetAllPekars()
|
||||
{
|
||||
return new List<PekarDataModel>();
|
||||
}
|
||||
|
||||
public List<PekarDataModel> GetAllDataOfPekar(string pekarId)
|
||||
{
|
||||
return new List<PekarDataModel>();
|
||||
}
|
||||
|
||||
public PekarDataModel GetPekarByData(string data)
|
||||
{
|
||||
return new PekarDataModel("", "", "",
|
||||
0, new List<ProductDataModel>());
|
||||
}
|
||||
|
||||
public void InsertPekar(PekarDataModel order)
|
||||
{
|
||||
}
|
||||
|
||||
public void UpdatePekar(PekarDataModel order)
|
||||
{
|
||||
}
|
||||
|
||||
public void DeletePekar(string id)
|
||||
{
|
||||
}
|
||||
|
||||
public void RestorePekar(string id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
using CandyHouseBase.Enums;
|
||||
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
|
||||
using CandyHouseBase.Interfaces.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CandyHouseBase.Implementations
|
||||
{
|
||||
internal class PositionBusinessLogicContract(
|
||||
IPositionStorageContact positionStorageContact,
|
||||
ILogger logger)
|
||||
: IPositionBusinessLogicContact
|
||||
{
|
||||
private readonly IPositionStorageContact _positionStorageContact = positionStorageContact;
|
||||
private readonly ILogger _logger = logger;
|
||||
|
||||
public List<PositionDataModel> GetAllPositions()
|
||||
{
|
||||
return new List<PositionDataModel>();
|
||||
}
|
||||
|
||||
public PositionDataModel GetPositionByData(string data)
|
||||
{
|
||||
return new PositionDataModel("", PositionType.Cool, "");
|
||||
}
|
||||
|
||||
public void InsertPosition(PositionDataModel position)
|
||||
{
|
||||
}
|
||||
|
||||
public void UpdatePosition(PositionDataModel position)
|
||||
{
|
||||
}
|
||||
|
||||
public void DeletePosition(string id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
using CandyHouseBase.Enums;
|
||||
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
|
||||
using CandyHouseBase.Interfaces.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CandyHouseBase.Implementations
|
||||
{
|
||||
internal class ProductBusinessLogicContract(
|
||||
IProductStorageContact productStorageContact,
|
||||
IIngredientStorageContact ingredientStorageContact,
|
||||
ILogger logger)
|
||||
: IProductBusinessLogicContact
|
||||
{
|
||||
private readonly IProductStorageContact _productStorageContact = productStorageContact;
|
||||
private readonly IIngredientStorageContact _ingredientStorageContact = ingredientStorageContact;
|
||||
private readonly ILogger _logger = logger;
|
||||
|
||||
public List<ProductDataModel> GetAllProducts()
|
||||
{
|
||||
return new List<ProductDataModel>();
|
||||
}
|
||||
|
||||
public ProductDataModel GetProductByData(string data)
|
||||
{
|
||||
return new ProductDataModel("", "", "", new List<IngredientDataModel>());
|
||||
}
|
||||
|
||||
public void InsertProduct(ProductDataModel product)
|
||||
{
|
||||
}
|
||||
|
||||
public void UpdateProduct(ProductDataModel product)
|
||||
{
|
||||
}
|
||||
|
||||
public void DeleteProduct(string id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using CandyHouseBase.DataModels;
|
||||
using CandyHouseBase.Exceptions;
|
||||
using CandyHouseBase.Extensions;
|
||||
using CandyHouseBase.Interfaces.BusinessLogicsContracts;
|
||||
using CandyHouseBase.Interfaces.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CandyHouseBase.Implementations
|
||||
{
|
||||
internal class SalaryBusinessLogicContract(
|
||||
ISalaryStorageContact salaryStorageContact,
|
||||
IPekarStorageContact pekarStorageContact,
|
||||
ILogger logger)
|
||||
: ISalaryBusinessLogicContact
|
||||
{
|
||||
private readonly ISalaryStorageContact _salaryStorageContact = salaryStorageContact;
|
||||
private readonly IPekarStorageContact _pekarStorageContact = pekarStorageContact;
|
||||
private readonly ILogger _logger = logger;
|
||||
|
||||
public List<SalaryDataModel> GetAllSalaries()
|
||||
{
|
||||
return new List<SalaryDataModel>();
|
||||
}
|
||||
|
||||
public SalaryDataModel GetSalaryByData(string data)
|
||||
{
|
||||
return new SalaryDataModel("", "", new DateTime(), 0, 0, 0);
|
||||
}
|
||||
|
||||
public void InsertSalary(SalaryDataModel salary)
|
||||
{
|
||||
}
|
||||
|
||||
public void UpdateSalary(SalaryDataModel salary)
|
||||
{
|
||||
}
|
||||
|
||||
public void DeleteSalary(string id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace CandyHouseBase.Infrastructure
|
||||
{
|
||||
public interface IValidation
|
||||
{
|
||||
void Validate();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.BusinessLogicsContracts
|
||||
{
|
||||
public interface IIngredientBusinessLogicContact
|
||||
{
|
||||
List<IngredientDataModel> GetAllIngredients();
|
||||
IngredientDataModel GetIngredientByData(string data);
|
||||
void InsertIngredient(IngredientDataModel ingredient);
|
||||
void UpdateIngredient(IngredientDataModel ingredient);
|
||||
void DeleteIngredient(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.BusinessLogicsContracts
|
||||
{
|
||||
public interface IOrderBusinessLogicContact
|
||||
{
|
||||
List<OrderDataModel> GetAllOrders();
|
||||
OrderDataModel GetOrderByData(string data);
|
||||
void InsertOrder(OrderDataModel order);
|
||||
void UpdateOrder(OrderDataModel order);
|
||||
void DeleteOrder(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.BusinessLogicsContracts
|
||||
{
|
||||
public interface IPekarBusinessLogicContact
|
||||
{
|
||||
List<PekarDataModel> GetAllPekars();
|
||||
List<PekarDataModel> GetAllDataOfPekar(string pekarId);
|
||||
PekarDataModel GetPekarByData(string data);
|
||||
void InsertPekar(PekarDataModel order);
|
||||
void UpdatePekar(PekarDataModel order);
|
||||
void DeletePekar(string id);
|
||||
void RestorePekar(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.BusinessLogicsContracts
|
||||
{
|
||||
public interface IPositionBusinessLogicContact
|
||||
{
|
||||
List<PositionDataModel> GetAllPositions();
|
||||
PositionDataModel GetPositionByData(string data);
|
||||
void InsertPosition(PositionDataModel position);
|
||||
void UpdatePosition(PositionDataModel position);
|
||||
void DeletePosition(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.BusinessLogicsContracts
|
||||
{
|
||||
public interface IProductBusinessLogicContact
|
||||
{
|
||||
List<ProductDataModel> GetAllProducts();
|
||||
ProductDataModel GetProductByData(string data);
|
||||
void InsertProduct(ProductDataModel product);
|
||||
void UpdateProduct(ProductDataModel product);
|
||||
void DeleteProduct(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.BusinessLogicsContracts
|
||||
{
|
||||
public interface ISalaryBusinessLogicContact
|
||||
{
|
||||
List<SalaryDataModel> GetAllSalaries();
|
||||
SalaryDataModel GetSalaryByData(string data);
|
||||
void InsertSalary(SalaryDataModel salary);
|
||||
void UpdateSalary(SalaryDataModel salary);
|
||||
void DeleteSalary(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.StoragesContracts
|
||||
{
|
||||
public interface IIngredientStorageContact
|
||||
{
|
||||
List<IngredientDataModel> GetList();
|
||||
IngredientDataModel GetElementById(string id);
|
||||
IngredientDataModel GetElementByName(string name);
|
||||
void AddElement(IngredientDataModel ingredient);
|
||||
void UpdateElement(IngredientDataModel ingredient);
|
||||
void DeleteElement(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.StoragesContracts
|
||||
{
|
||||
public interface IOrderStorageContact
|
||||
{
|
||||
List<OrderDataModel> GetOrders();
|
||||
void AddElement(OrderDataModel order);
|
||||
void UpdateElement(OrderDataModel order);
|
||||
void DeleteElement(OrderDataModel order);
|
||||
OrderDataModel GetElementById(string orderId);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.StoragesContracts
|
||||
{
|
||||
public interface IPekarStorageContact
|
||||
{
|
||||
List<PekarDataModel> GetList();
|
||||
List<PekarDataModel> GetPekarWithHistory(string id);
|
||||
PekarDataModel GetElementById(string id);
|
||||
PekarDataModel GetElementByFio(string fio);
|
||||
void AddElement(PekarDataModel item);
|
||||
void UpdateElement(PekarDataModel item);
|
||||
void DeleteElement(string id);
|
||||
void RestoreElement(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.StoragesContracts
|
||||
{
|
||||
public interface IProductStorageContact
|
||||
{
|
||||
List<ProductDataModel> GetList();
|
||||
ProductDataModel GetElementById(string id);
|
||||
ProductDataModel GetElementByName(string name);
|
||||
ProductDataModel GetElementByOldName(string name);
|
||||
void AddElement(ProductDataModel element);
|
||||
void UpdateElement(ProductDataModel element);
|
||||
void DeleteElement(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.StoragesContracts
|
||||
{
|
||||
public interface IPositionStorageContact
|
||||
{
|
||||
List<PositionDataModel> GetList();
|
||||
PositionDataModel GetElementById(string id);
|
||||
void AddElement(PositionDataModel element);
|
||||
void UpdateElement(PositionDataModel element);
|
||||
void DeleteElement(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using CandyHouseBase.DataModels;
|
||||
|
||||
namespace CandyHouseBase.Interfaces.StoragesContracts
|
||||
{
|
||||
public interface ISalaryStorageContact
|
||||
{
|
||||
List<SalaryDataModel> GetList();
|
||||
SalaryDataModel GetElementById(string id);
|
||||
void AddElement(SalaryDataModel element);
|
||||
void UpdateElement(SalaryDataModel element);
|
||||
void DeleteElement(string id);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace CandyHouseBase
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.3" />
|
||||
<PackageReference Include="PdfSharp.MigraDoc.Standard" Version="1.51.15" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="CandyHouseTests" />
|
||||
<InternalsVisibleTo Include="CandyHouseWebApi" />
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CandyHouseContracts\CandyHouseContracts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,80 @@
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using CandyHouseContracts.Resources;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
internal class CustomerBusinessLogicContract(ICustomerStorageContract customerStorage, IStringLocalizer<Messages> localizer, ILogger<CustomerBusinessLogicContract> logger) : ICustomerBusinessLogicContract
|
||||
{
|
||||
private readonly ILogger<CustomerBusinessLogicContract> _logger = logger;
|
||||
private readonly ICustomerStorageContract _customerStorage = customerStorage;
|
||||
private readonly IStringLocalizer<Messages> _localizer = localizer;
|
||||
|
||||
public List<CustomerDataModel> GetAllCustomers()
|
||||
{
|
||||
_logger.LogInformation("Fetching all customers");
|
||||
return _customerStorage.GetList();
|
||||
}
|
||||
|
||||
public CustomerDataModel GetCustomerByData(string data)
|
||||
{
|
||||
_logger.LogInformation("Fetching customer by data={data}", data);
|
||||
if (data.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
CustomerDataModel? result;
|
||||
if (data.IsGuid())
|
||||
{
|
||||
result = _customerStorage.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
else if (data.StartsWith("+7"))
|
||||
{
|
||||
result = _customerStorage.GetElementByPhone(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
else if (data.Contains("@"))
|
||||
{
|
||||
result = _customerStorage.GetElementByEmail(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _customerStorage.GetElementByFIO(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void InsertCustomer(CustomerDataModel customerDataModel)
|
||||
{
|
||||
_logger.LogInformation("Inserting customer: {json}", JsonSerializer.Serialize(customerDataModel));
|
||||
ArgumentNullException.ThrowIfNull(customerDataModel);
|
||||
customerDataModel.Validate(_localizer);
|
||||
_customerStorage.AddElement(customerDataModel);
|
||||
}
|
||||
|
||||
public void UpdateCustomer(CustomerDataModel customerDataModel)
|
||||
{
|
||||
_logger.LogInformation("Updating customer: {json}", JsonSerializer.Serialize(customerDataModel));
|
||||
ArgumentNullException.ThrowIfNull(customerDataModel);
|
||||
customerDataModel.Validate(_localizer);
|
||||
_customerStorage.UpdateElement(customerDataModel);
|
||||
}
|
||||
|
||||
public void DeleteCustomer(string id)
|
||||
{
|
||||
_logger.LogInformation("Deleting customer with id={id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
_customerStorage.DeleteElement(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using CandyHouseContracts.Resources;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
internal class IngredientBusinessLogicContract(IIngredientStorageContract ingredientStorage, IStringLocalizer<Messages> localizer, ILogger<IngredientBusinessLogicContract> logger) : IIngredientBusinessLogicContract
|
||||
{
|
||||
private readonly ILogger<IngredientBusinessLogicContract> _logger = logger;
|
||||
private readonly IIngredientStorageContract _ingredientStorage = ingredientStorage;
|
||||
private readonly IStringLocalizer<Messages> _localizer = localizer;
|
||||
|
||||
public List<IngredientDataModel> GetAllIngredients(bool onlyActive = true)
|
||||
{
|
||||
_logger.LogInformation("GetAllIngredients params: {onlyActive}", onlyActive);
|
||||
return _ingredientStorage.GetList(onlyActive, null);
|
||||
}
|
||||
|
||||
public List<IngredientDataModel> GetAllIngredientsByManufacturer(string manufacturerId, bool onlyActive = true)
|
||||
{
|
||||
_logger.LogInformation("GetAllIngredients params: {manufacturerId}, {onlyActive}", manufacturerId, onlyActive);
|
||||
if (manufacturerId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(manufacturerId));
|
||||
}
|
||||
if (!manufacturerId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "ManufacturerId"));
|
||||
}
|
||||
return _ingredientStorage.GetList(onlyActive, manufacturerId);
|
||||
}
|
||||
|
||||
public List<IngredientHistoryDataModel> GetIngredientHistory(string ingredientId)
|
||||
{
|
||||
_logger.LogInformation("GetIngredientHistory for {ingredientId}", ingredientId);
|
||||
if (ingredientId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ingredientId));
|
||||
}
|
||||
if (!ingredientId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "IngredientId"));
|
||||
}
|
||||
return _ingredientStorage.GetHistoryByIngredientId(ingredientId);
|
||||
}
|
||||
|
||||
public IngredientDataModel GetIngredientByData(string data)
|
||||
{
|
||||
_logger.LogInformation("Get element by data: {data}", data);
|
||||
if (data.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
IngredientDataModel? result;
|
||||
if (data.IsGuid())
|
||||
{
|
||||
result = _ingredientStorage.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _ingredientStorage.GetElementByName(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void InsertIngredient(IngredientDataModel ingredientDataModel)
|
||||
{
|
||||
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(ingredientDataModel));
|
||||
ArgumentNullException.ThrowIfNull(ingredientDataModel);
|
||||
ingredientDataModel.Validate(_localizer);
|
||||
_ingredientStorage.AddElement(ingredientDataModel);
|
||||
}
|
||||
|
||||
public void UpdateIngredient(IngredientDataModel ingredientDataModel)
|
||||
{
|
||||
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(ingredientDataModel));
|
||||
ArgumentNullException.ThrowIfNull(ingredientDataModel);
|
||||
ingredientDataModel.Validate(_localizer);
|
||||
_ingredientStorage.UpdateElement(ingredientDataModel);
|
||||
}
|
||||
|
||||
public void DeleteIngredient(string id)
|
||||
{
|
||||
_logger.LogInformation("Delete by id: {id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
_ingredientStorage.DeleteElement(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using CandyHouseContracts.Resources;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
internal class ManufacturerBusinessLogicContract(IManufacturerStorageContract manufacturerStorage, IStringLocalizer<Messages> localizer, ILogger<ManufacturerBusinessLogicContract> logger) : IManufacturerBusinessLogicContract
|
||||
{
|
||||
private readonly ILogger<ManufacturerBusinessLogicContract> _logger = logger;
|
||||
private readonly IManufacturerStorageContract _manufacturerStorage = manufacturerStorage;
|
||||
private readonly IStringLocalizer<Messages> _localizer = localizer;
|
||||
|
||||
public List<ManufacturerDataModel> GetAllManufacturers()
|
||||
{
|
||||
_logger.LogInformation("GetAllManufacturers");
|
||||
return _manufacturerStorage.GetList();
|
||||
}
|
||||
|
||||
public ManufacturerDataModel GetManufacturerByData(string data)
|
||||
{
|
||||
_logger.LogInformation("Get element by data: {data}", data);
|
||||
if (data.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
if (data.IsGuid())
|
||||
{
|
||||
return _manufacturerStorage.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
|
||||
// Сначала ищем по ManufacturerName
|
||||
var manufacturer = _manufacturerStorage.GetElementByName(data);
|
||||
if (manufacturer != null)
|
||||
{
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
// Если не нашли по ManufacturerName, ищем по PrevManufacturerName
|
||||
manufacturer = _manufacturerStorage.GetList()
|
||||
.FirstOrDefault(m => m.PrevManufacturerName != null && m.PrevManufacturerName.Equals(data, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return manufacturer ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
|
||||
public void InsertManufacturer(ManufacturerDataModel manufacturerDataModel)
|
||||
{
|
||||
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(manufacturerDataModel));
|
||||
ArgumentNullException.ThrowIfNull(manufacturerDataModel);
|
||||
manufacturerDataModel.Validate(_localizer);
|
||||
_manufacturerStorage.AddElement(manufacturerDataModel);
|
||||
}
|
||||
|
||||
public void UpdateManufacturer(ManufacturerDataModel manufacturerDataModel)
|
||||
{
|
||||
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(manufacturerDataModel));
|
||||
ArgumentNullException.ThrowIfNull(manufacturerDataModel);
|
||||
manufacturerDataModel.Validate(_localizer);
|
||||
_manufacturerStorage.UpdateElement(manufacturerDataModel);
|
||||
}
|
||||
|
||||
public void DeleteManufacturer(string id)
|
||||
{
|
||||
_logger.LogInformation("Delete by id: {id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
_manufacturerStorage.DeleteElement(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using CandyHouseContracts.Resources;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
|
||||
internal class PostBusinessLogicContract(IPostStorageContract postStorageContract, IStringLocalizer<Messages> localizer, ILogger logger) : IPostBusinessLogicContract
|
||||
{
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly IPostStorageContract _postStorageContract = postStorageContract;
|
||||
private readonly IStringLocalizer<Messages> _localizer = localizer;
|
||||
|
||||
public List<PostDataModel> GetAllPosts()
|
||||
{
|
||||
_logger.LogInformation("GetAllPosts");
|
||||
return _postStorageContract.GetList();
|
||||
}
|
||||
|
||||
public List<PostDataModel> GetAllDataOfPost(string postId)
|
||||
{
|
||||
_logger.LogInformation("GetAllDataOfPost for {postId}", postId);
|
||||
if (postId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(postId));
|
||||
}
|
||||
if (!postId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "PostId"));
|
||||
}
|
||||
return _postStorageContract.GetPostHistory(postId);
|
||||
}
|
||||
public List<PostDataModel> GetPostHistory(string postId)
|
||||
{
|
||||
_logger.LogInformation("GetPostHistory for {postId}", postId);
|
||||
if (postId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(postId));
|
||||
}
|
||||
if (!postId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "PostId"));
|
||||
}
|
||||
return _postStorageContract.GetPostHistory(postId);
|
||||
}
|
||||
|
||||
public PostDataModel GetPostByData(string data)
|
||||
{
|
||||
_logger.LogInformation("Get element by data: {data}", data);
|
||||
if (data.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
if (data.IsGuid())
|
||||
{
|
||||
return _postStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
return _postStorageContract.GetElementByName(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
|
||||
public void InsertPost(PostDataModel postDataModel)
|
||||
{
|
||||
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(postDataModel));
|
||||
ArgumentNullException.ThrowIfNull(postDataModel);
|
||||
postDataModel.Validate(_localizer);
|
||||
_postStorageContract.AddElement(postDataModel);
|
||||
}
|
||||
|
||||
public void UpdatePost(PostDataModel postDataModel)
|
||||
{
|
||||
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(postDataModel));
|
||||
ArgumentNullException.ThrowIfNull(postDataModel);
|
||||
postDataModel.Validate(_localizer);
|
||||
_postStorageContract.UpdateElement(postDataModel);
|
||||
}
|
||||
|
||||
public void DeletePost(string id)
|
||||
{
|
||||
_logger.LogInformation("Delete by id: {id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
_postStorageContract.DeleteElement(id);
|
||||
}
|
||||
|
||||
public void RestorePost(string id)
|
||||
{
|
||||
_logger.LogInformation("Restore by id: {id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
_postStorageContract.ResElement(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using CandyHouseContracts.Resources;
|
||||
using DocumentFormat.OpenXml.Office2010.Excel;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
|
||||
/// <summary>
|
||||
/// Реализация бизнес-логики
|
||||
/// </summary>
|
||||
internal class ProductBusinessLogicContract : IProductBusinessLogicContract
|
||||
{
|
||||
private readonly ILogger<ProductBusinessLogicContract> _logger;
|
||||
private readonly IProductStorageContract _productStorageContract;
|
||||
private readonly IStringLocalizer<Messages> _localizer;
|
||||
public ProductBusinessLogicContract(IProductStorageContract productStorage, IStringLocalizer<Messages> localizer, ILogger<ProductBusinessLogicContract> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_productStorageContract = productStorage;
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
public List<ProductDataModel> GetAllProducts(bool onlyActive = true)
|
||||
{
|
||||
_logger.LogInformation("Fetching all products with onlyActive={onlyActive}", onlyActive);
|
||||
return _productStorageContract.GetList(onlyActive: onlyActive);
|
||||
}
|
||||
|
||||
public ProductDataModel GetProductById(string id)
|
||||
{
|
||||
_logger.LogInformation("Fetching sale product by id={id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
return _productStorageContract.GetElementById(id) ?? throw new ElementNotFoundException(id, _localizer);
|
||||
}
|
||||
|
||||
public void InsertProduct(ProductDataModel productDataModel)
|
||||
{
|
||||
_logger.LogInformation("Inserting sale product: {json}", JsonSerializer.Serialize(productDataModel));
|
||||
ArgumentNullException.ThrowIfNull(productDataModel);
|
||||
productDataModel.Validate(_localizer);
|
||||
_productStorageContract.AddElement(productDataModel);
|
||||
}
|
||||
|
||||
public void UpdateProduct(ProductDataModel productDataModel)
|
||||
{
|
||||
_logger.LogInformation("Updating sale product: {json}", JsonSerializer.Serialize(productDataModel));
|
||||
ArgumentNullException.ThrowIfNull(productDataModel);
|
||||
productDataModel.Validate(_localizer);
|
||||
_productStorageContract.UpdateElement(productDataModel);
|
||||
}
|
||||
|
||||
public void DeleteProduct(string id)
|
||||
{
|
||||
_logger.LogInformation("Deleting sale product with id={id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
_productStorageContract.DeleteElement(id);
|
||||
}
|
||||
|
||||
public List<ProductIngredientDataModel> GetIngredientsByProductId(string productId)
|
||||
{
|
||||
_logger.LogInformation("Fetching ingredients for sale product with id={saleProductId}", productId);
|
||||
if (productId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(productId));
|
||||
}
|
||||
if (!productId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "ProductId"));
|
||||
}
|
||||
return _productStorageContract.GetIngredientsByProductId(productId);
|
||||
}
|
||||
|
||||
public void AddIngredientToProduct(ProductIngredientDataModel productIngredient)
|
||||
{
|
||||
_logger.LogInformation("Adding ingredient to product: {json}", JsonSerializer.Serialize(productIngredient));
|
||||
ArgumentNullException.ThrowIfNull(productIngredient);
|
||||
productIngredient.Validate(_localizer);
|
||||
_productStorageContract.AddIngredientToProduct(productIngredient);
|
||||
}
|
||||
|
||||
public void RemoveIngredientFromProduct(string ingredientId, string productId)
|
||||
{
|
||||
_logger.LogInformation("Removing ingredient {ingredientId} from product {productId}", ingredientId, productId);
|
||||
if (ingredientId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ingredientId));
|
||||
}
|
||||
|
||||
if (!ingredientId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "IngredientId"));
|
||||
}
|
||||
|
||||
if (productId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(productId));
|
||||
}
|
||||
|
||||
if (!productId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "ProductId"));
|
||||
}
|
||||
|
||||
_productStorageContract.RemoveIngredientFromProduct(ingredientId, productId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,623 @@
|
||||
using DocumentFormat.OpenXml.Wordprocessing;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using CandyHouseBusinessLogic.OfficePackage;
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.Resources;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using System.Globalization;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
|
||||
internal class ReportContract : IReportContract
|
||||
{
|
||||
private readonly IIngredientStorageContract _ingredientStorageContract;
|
||||
|
||||
private readonly IStringLocalizer<Messages> _localizer;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly BaseWordBuilder _baseWordBuilder;
|
||||
|
||||
private readonly ISaleStorageContract _saleStorageContract;
|
||||
|
||||
private readonly ISalaryStorageContract _salaryStorageContract;
|
||||
|
||||
private readonly IStorageContract _storageContract;
|
||||
|
||||
private readonly ISupplyStorageContract _supplyStorageContract;
|
||||
|
||||
private readonly BaseExcelBuilder _baseExcelBuilder;
|
||||
|
||||
private readonly BasePdfBuilder _basePdfBuilder;
|
||||
|
||||
private readonly string[] _documentHeader;
|
||||
|
||||
private readonly string[] _tableHeader;
|
||||
|
||||
private readonly string[] _supplyTableHeader;
|
||||
|
||||
private readonly string[] _movementTableHeader;
|
||||
|
||||
private readonly string[] _stockTableHeader;
|
||||
|
||||
public ReportContract(IIngredientStorageContract ingredientStorageContract, ISaleStorageContract saleStorageContract, IProductStorageContract productStorageContract, ISalaryStorageContract salaryStorageContract, IStorageContract storageContract, ISupplyStorageContract supplyStorageContract, BaseWordBuilder baseWordBuilder, BaseExcelBuilder baseExcelBuilder, BasePdfBuilder basePdfBuilder, IStringLocalizer<Messages> localizer, ILogger logger)
|
||||
{
|
||||
_ingredientStorageContract = ingredientStorageContract;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_baseWordBuilder = baseWordBuilder;
|
||||
_saleStorageContract = saleStorageContract;
|
||||
_salaryStorageContract = salaryStorageContract;
|
||||
_storageContract = storageContract;
|
||||
_supplyStorageContract = supplyStorageContract;
|
||||
_baseExcelBuilder = baseExcelBuilder;
|
||||
_basePdfBuilder = basePdfBuilder;
|
||||
_documentHeader = [_localizer["DocumentDocCaptionIngredient"], _localizer["DocumentDocCaptionIngredientHistory"], _localizer["DocumentDocCaptionOldPrice"]];
|
||||
_tableHeader = [_localizer["DocumentExcelCaptionDate"], _localizer["DocumentExcelCaptionSum"],
|
||||
_localizer["DocumentExcelCaptionDiscount"], _localizer["DocumentExcelCaptionWorker"], _localizer["DocumentExcelCaptionProduct"], _localizer["DocumentExcelCaptionCount"]];
|
||||
|
||||
_supplyTableHeader = [_localizer["DocumentDocSupplyCaptionDate"],
|
||||
_localizer["DocumentDocSupplyCaptionStorage"],
|
||||
_localizer["DocumentDocSupplyCaptionIngredient"],
|
||||
_localizer["DocumentDocSupplyCaptionCount"]
|
||||
];
|
||||
_movementTableHeader = [_localizer["DocumentExcelMovementCaptionDate"],
|
||||
_localizer["DocumentExcelMovementCaptionOperation"],
|
||||
_localizer["DocumentExcelMovementCaptionIngredient"],
|
||||
_localizer["DocumentExcelMovementCaptionCount"],
|
||||
_localizer["DocumentExcelMovementCaptionStorage"]
|
||||
];
|
||||
_stockTableHeader = [_localizer["DocumentPdfStockCaptionIngredient"],
|
||||
_localizer["DocumentPdfStockCaptionCount"]
|
||||
];
|
||||
}
|
||||
|
||||
public async Task<List<IngredientWithHistoryDataModel>> GetDataIngredientsWithHistoryAsync(CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data IngredientsWithHistory");
|
||||
return await GetDataByIngredientsAsync(ct);
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentIngredientsWithHistoryAsync(CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report IngredientsWithHistory");
|
||||
|
||||
// Получаем данные
|
||||
var data = await GetDataIngredientsWithHistoryAsync(ct);
|
||||
if (!data.Any())
|
||||
{
|
||||
throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
}
|
||||
|
||||
// Формируем строки таблицы
|
||||
var tableRows = new List<string[]>
|
||||
{
|
||||
_documentHeader // ["DocumentDocCaptionIngredient", "DocumentDocCaptionIngredientHistory", "DocumentDocCaptionOldPrice"]
|
||||
};
|
||||
|
||||
foreach (var ingredient in data.OrderBy(c => c.IngredientName))
|
||||
{
|
||||
if (ingredient.History.Any())
|
||||
{
|
||||
// Сортируем историю по убыванию даты
|
||||
var sortedHistory = ingredient.History.OrderByDescending(h => h.ChangeDate).ToList();
|
||||
|
||||
// Добавляем первую строку с названием комплектующей
|
||||
var firstHistory = sortedHistory.First();
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
ingredient.IngredientName,
|
||||
firstHistory.ChangeDate.ToLocalTime().ToString("dd.MM.yyyy HH:mm:ss"),
|
||||
firstHistory.OldPrice.ToString("N2", CultureInfo.CurrentCulture)
|
||||
});
|
||||
|
||||
// Добавляем остальные записи истории
|
||||
foreach (var history in sortedHistory.Skip(1))
|
||||
{
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
"", // Пустая ячейка для названия комплектующей
|
||||
history.ChangeDate.ToLocalTime().ToString("dd.MM.yyyy HH:mm:ss"),
|
||||
history.OldPrice.ToString("N2", CultureInfo.CurrentCulture)
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Если истории нет, добавляем строку с локализованным текстом
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
ingredient.IngredientName,
|
||||
_localizer["NotFoundDataMessage"], // Локализованный текст "Нет данных"
|
||||
"" // Пустая ячейка для старой цены
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Создаём документ с таблицей
|
||||
return _baseWordBuilder
|
||||
.AddHeader(_localizer["DocumentDocHeader"]) // "Продукты по производителям" или аналог
|
||||
.AddParagraph(string.Format(_localizer["DocumentDocSubHeader"], DateTime.Now.ToLocalTime().ToShortDateString()))
|
||||
.AddTable(new[] { 4000, 3000, 2000 }, tableRows) // Устанавливаем ширину колонок
|
||||
.Build();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentSalesByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Creating SalesByPeriod report from {DateStart} to {DateFinish}", dateStart, dateFinish);
|
||||
|
||||
var salesData = await GetDataBySalesAsync(dateStart, dateFinish, ct)
|
||||
?? throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
|
||||
if (!salesData.Any())
|
||||
{
|
||||
_logger.LogInformation("No sales records found from {DateStart} to {DateFinish}", dateStart, dateFinish);
|
||||
throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
}
|
||||
|
||||
var tableRows = new List<string[]>
|
||||
{
|
||||
_tableHeader // ["DocumentExcelCaptionDate", "DocumentExcelCaptionSum", ..., "DocumentExcelCaptionCount"]
|
||||
};
|
||||
|
||||
foreach (var sale in salesData)
|
||||
{
|
||||
if (sale.Product == null)
|
||||
{
|
||||
_logger.LogWarning("Product data missing for sale ID {SaleId}", sale.Id);
|
||||
continue;
|
||||
}
|
||||
|
||||
var productInfo = sale.Product;
|
||||
var productName = productInfo.ProductName;
|
||||
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
sale.SaleDate.ToLocalTime().ToShortDateString(),
|
||||
sale.Sum.ToString("N2", CultureInfo.CurrentCulture),
|
||||
sale.Discount.ToString("N2", CultureInfo.CurrentCulture),
|
||||
sale.WorkerFIO ?? _localizer["NotFoundDataMessage"],
|
||||
productName,
|
||||
"1"
|
||||
});
|
||||
}
|
||||
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
_localizer["DocumentExcelCaptionTotal"], // "Всего"
|
||||
salesData.Sum(x => x.Sum).ToString("N2", CultureInfo.CurrentCulture),
|
||||
salesData.Sum(x => x.Discount).ToString("N2", CultureInfo.CurrentCulture),
|
||||
"", "", ""
|
||||
});
|
||||
|
||||
return _baseExcelBuilder
|
||||
.AddHeader(_localizer["DocumentExcelHeader"], startIndex: 0, count: 6) // "Продажи за период"
|
||||
.AddParagraph(string.Format(_localizer["DocumentExcelSubHeader"], dateStart.ToLocalTime().ToShortDateString(), dateFinish.ToLocalTime().ToShortDateString()), columnIndex: 0)
|
||||
.AddTable(
|
||||
columnsWidths: new[] { 15, 10, 10, 20, 30, 10 },
|
||||
data: tableRows
|
||||
)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report SalaryByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
var data = await GetDataBySalaryAsync(dateStart, dateFinish, ct) ?? throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
return _basePdfBuilder
|
||||
.AddHeader(_localizer["DocumentPdfHeader"]) // "Зарплатная ведомость"
|
||||
.AddParagraph(string.Format(_localizer["DocumentPdfSubHeader"], dateStart.ToLocalTime().ToShortDateString(), dateFinish.ToLocalTime().ToShortDateString()))
|
||||
.AddPieChart(_localizer["DocumentPdfDiagramCaption"], [.. data.Select(x => (x.WorkerFIO, x.TotalSalary))]) // "Начисления"
|
||||
.Build();
|
||||
}
|
||||
|
||||
public Task<List<SaleDataModel>> GetDataSaleByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data SalesByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
return GetDataBySalesAsync(dateStart, dateFinish, ct);
|
||||
}
|
||||
|
||||
public Task<List<WorkerSalaryByPeriodDataModel>> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data SalaryByPeriod from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
return GetDataBySalaryAsync(dateStart, dateFinish, ct);
|
||||
}
|
||||
|
||||
private async Task<List<IngredientWithHistoryDataModel>> GetDataByIngredientsAsync(CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Starting GetDataByIngredientsAsync");
|
||||
|
||||
// Получаем все комплектующие
|
||||
var ingredients = await _ingredientStorageContract.GetListAsync(ct);
|
||||
_logger.LogInformation("Retrieved {Count} ingredients from storage", ingredients.Count);
|
||||
|
||||
// Формируем список комплектующих с их историей (последовательно)
|
||||
var result = new List<IngredientWithHistoryDataModel>();
|
||||
foreach (var ingredient in ingredients)
|
||||
{
|
||||
_logger.LogInformation("Processing ingredient {IngredientName} with ID {IngredientId}", ingredient.IngredientName, ingredient.Id);
|
||||
|
||||
// Получаем историю изменений для текущей комплектующей асинхронно
|
||||
var history = await _ingredientStorageContract.GetHistoryByIngredientIdAsync(ingredient.Id, ct);
|
||||
_logger.LogInformation("Retrieved {HistoryCount} history records for ingredient {IngredientName}", history.Count, ingredient.IngredientName);
|
||||
|
||||
// Логируем данные, которые передаём в IngredientWithHistoryDataModel
|
||||
_logger.LogInformation("Creating IngredientWithHistoryDataModel for {IngredientName}. ManufacturerName: {ManufacturerName}, CurrentPrice: {Price}, History is null: {HistoryIsNull}",
|
||||
ingredient.IngredientName, ingredient.ManufacturerName, ingredient.Price, history == null);
|
||||
|
||||
// Создаём объект для отчёта
|
||||
var ingredientWithHistory = new IngredientWithHistoryDataModel(
|
||||
ingredientName: ingredient.IngredientName,
|
||||
currentPrice: ingredient.Price,
|
||||
manufacturerName: ingredient.ManufacturerName,
|
||||
history: history
|
||||
);
|
||||
|
||||
// Вызываем валидацию
|
||||
try
|
||||
{
|
||||
ingredientWithHistory.Validate(_localizer);
|
||||
_logger.LogInformation("Validation passed for ingredient {IngredientName}", ingredient.IngredientName);
|
||||
}
|
||||
catch (ValidationException ex)
|
||||
{
|
||||
_logger.LogError(ex, "Validation failed for ingredient {IngredientName}: {Message}", ingredient.IngredientName, ex.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
result.Add(ingredientWithHistory);
|
||||
}
|
||||
|
||||
_logger.LogInformation("All ingredients processed, {Count} ingredients processed", result.Count);
|
||||
|
||||
return result.OrderBy(x => x.IngredientName).ToList();
|
||||
}
|
||||
|
||||
private async Task<List<SaleDataModel>> GetDataBySalesAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
if (dateStart.IsDateNotOlder(dateFinish))
|
||||
{
|
||||
throw new IncorrectDatesException(dateStart, dateFinish, _localizer);
|
||||
}
|
||||
return [.. (await _saleStorageContract.GetListAsync(dateStart, dateFinish, ct)).OrderBy(x => x.SaleDate)];
|
||||
}
|
||||
|
||||
private async Task<List<WorkerSalaryByPeriodDataModel>> GetDataBySalaryAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
if (dateStart.IsDateNotOlder(dateFinish))
|
||||
{
|
||||
throw new IncorrectDatesException(dateStart, dateFinish, _localizer);
|
||||
}
|
||||
return (await _salaryStorageContract.GetListAsync(dateStart, dateFinish, ct))
|
||||
.GroupBy(x => x.WorkerId)
|
||||
.Select(x => new WorkerSalaryByPeriodDataModel
|
||||
{
|
||||
WorkerFIO = x.First().WorkerFIO,
|
||||
TotalSalary = x.Sum(y => y.Salary),
|
||||
FromPeriod = x.Min(y => y.SalaryDate),
|
||||
ToPeriod = x.Max(y => y.SalaryDate)
|
||||
})
|
||||
.OrderBy(x => x.WorkerFIO)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public async Task<List<SupplyInformationDataModel>> GetDataSupplyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data Supply from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
if (dateStart.IsDateNotOlder(dateFinish))
|
||||
{
|
||||
_logger.LogError("Invalid date range: start date {DateStart} is not older than finish date {DateFinish}", dateStart, dateFinish);
|
||||
throw new IncorrectDatesException(dateStart, dateFinish, _localizer);
|
||||
}
|
||||
var supplies = await _supplyStorageContract.GetListAsync(dateStart, dateFinish, ct);
|
||||
var result = new List<SupplyInformationDataModel>();
|
||||
if (supplies != null)
|
||||
{
|
||||
foreach (var supply in supplies)
|
||||
{
|
||||
var supplyInfo = new SupplyInformationDataModel
|
||||
{
|
||||
SupplyId = supply.Id,
|
||||
SupplyDate = supply.DeliveryDate,
|
||||
StorageId = supply.StorageId,
|
||||
Ingredients = supply.Ingredients.Select(c => new SupplyIngredientReportDataModel(
|
||||
supplyId: c.SupplyId,
|
||||
ingredientId: c.IngredientId,
|
||||
count: c.Count
|
||||
)).ToList()
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
supplyInfo.Validate(_localizer);
|
||||
_logger.LogInformation("Validation passed for supply {SupplyId}", supplyInfo.SupplyId);
|
||||
}
|
||||
catch (ValidationException ex)
|
||||
{
|
||||
_logger.LogError(ex, "Validation failed for supply {SupplyId}: {Message}", supplyInfo.SupplyId, ex.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
result.Add(supplyInfo);
|
||||
}
|
||||
}
|
||||
return result.OrderBy(x => x.SupplyDate).ToList();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentSupplyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report Supply from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
var supplies = await GetDataSupplyAsync(dateStart, dateFinish, ct)
|
||||
?? throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
if (!supplies.Any())
|
||||
{
|
||||
_logger.LogInformation("No supply records found from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
}
|
||||
|
||||
var tableRows = new List<string[]>
|
||||
{
|
||||
_supplyTableHeader // ["DocumentDocSupplyCaptionDate", "DocumentDocSupplyCaptionStorage", "DocumentDocSupplyCaptionIngredient", "DocumentDocSupplyCaptionCount"]
|
||||
};
|
||||
|
||||
// Группируем комплектующие по поставкам
|
||||
var groupedSupplies = supplies
|
||||
.OrderBy(s => s.SupplyDate)
|
||||
.GroupBy(s => new { s.SupplyId, s.SupplyDate, s.StorageId })
|
||||
.ToList();
|
||||
|
||||
for (int groupIndex = 0; groupIndex < groupedSupplies.Count; groupIndex++)
|
||||
{
|
||||
var group = groupedSupplies[groupIndex];
|
||||
var supply = group.First();
|
||||
var storage = await _storageContract.GetByIdAsync(supply.StorageId, ct);
|
||||
if (storage == null)
|
||||
{
|
||||
_logger.LogWarning("Storage with ID {StorageId} not found for supply {SupplyId}", supply.StorageId, supply.SupplyId);
|
||||
}
|
||||
|
||||
// Получаем все комплектующие для данной поставки
|
||||
var ingredients = group.SelectMany(s => s.Ingredients).ToList();
|
||||
for (int i = 0; i < ingredients.Count; i++)
|
||||
{
|
||||
var ingredient = ingredients[i];
|
||||
var comp = await _ingredientStorageContract.GetElementByIdAsync(ingredient.IngredientId, ct);
|
||||
if (comp == null)
|
||||
{
|
||||
_logger.LogWarning("Ingredient with ID {IngredientId} not found for supply {SupplyId}", ingredient.IngredientId, supply.SupplyId);
|
||||
}
|
||||
|
||||
// Если это первая строка для данной поставки, показываем дату и склад
|
||||
// Для остальных строк оставляем эти колонки пустыми
|
||||
string dateCell = i == 0 ? supply.SupplyDate.ToLocalTime().ToString("d", CultureInfo.CurrentCulture) : "";
|
||||
string storageCell = i == 0 ? (storage?.Address ?? _localizer["NotFoundDataMessage"]) : "";
|
||||
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
dateCell,
|
||||
storageCell,
|
||||
comp?.IngredientName ?? ingredient.IngredientId,
|
||||
ingredient.Count.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
// Добавляем пустую строку как разделитель между поставками (если это не последняя поставка)
|
||||
if (groupIndex < groupedSupplies.Count - 1)
|
||||
{
|
||||
tableRows.Add(new[] { "", "", "", "" });
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем итоговую строку
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
_localizer["DocumentExcelCaptionTotal"], // "Итого"
|
||||
"",
|
||||
"",
|
||||
supplies.Sum(s => s.Ingredients.Sum(c => c.Count)).ToString()
|
||||
});
|
||||
|
||||
return _baseWordBuilder
|
||||
.AddHeader(_localizer["DocumentSupplyHeader"]) // "Отчёт по поставке"
|
||||
.AddParagraph(string.Format(_localizer["DocumentSupplySubHeader"], dateStart.ToLocalTime().ToString("d", CultureInfo.CurrentCulture), dateFinish.ToLocalTime().ToString("d", CultureInfo.CurrentCulture)))
|
||||
.AddTable(new[] { 2000, 2000, 3000, 1500 }, tableRows)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public async Task<List<IngredientMoveDataModel>> GetDataIngredientMovementAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data IngredientMovement from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
if (dateStart.IsDateNotOlder(dateFinish))
|
||||
{
|
||||
_logger.LogError("Invalid date range: start date {DateStart} is not older than finish date {DateFinish}", dateStart, dateFinish);
|
||||
throw new IncorrectDatesException(dateStart, dateFinish, _localizer);
|
||||
}
|
||||
var movements = new List<IngredientMoveDataModel>();
|
||||
|
||||
// Получаем поставки
|
||||
var supplies = await _supplyStorageContract.GetListAsync(dateStart, dateFinish, ct);
|
||||
if (supplies != null)
|
||||
{
|
||||
foreach (var supply in supplies)
|
||||
{
|
||||
foreach (var ingredient in supply.Ingredients)
|
||||
{
|
||||
var comp = await _ingredientStorageContract.GetElementByIdAsync(ingredient.IngredientId, ct);
|
||||
if (comp == null)
|
||||
{
|
||||
_logger.LogWarning("Ingredient with ID {IngredientId} not found for supply {SupplyId}", ingredient.IngredientId, supply.Id);
|
||||
}
|
||||
movements.Add(new IngredientMoveDataModel
|
||||
{
|
||||
Date = supply.DeliveryDate,
|
||||
OperationType = _localizer["DocumentMovementOperationArrival"].Value, // "Приход"
|
||||
IngredientId = ingredient.IngredientId,
|
||||
IngredientName = comp?.IngredientName ?? ingredient.IngredientId,
|
||||
Count = ingredient.Count,
|
||||
StorageId = supply.StorageId
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Получаем продажи
|
||||
var sales = await _saleStorageContract.GetListAsync(dateStart, dateFinish, ct);
|
||||
if (sales != null)
|
||||
{
|
||||
foreach (var sale in sales)
|
||||
{
|
||||
if (sale.Product?.Ingredients != null)
|
||||
{
|
||||
foreach (var ingredient in sale.Product.Ingredients)
|
||||
{
|
||||
var comp = await _ingredientStorageContract.GetElementByIdAsync(ingredient.IngredientId, ct);
|
||||
if (comp == null)
|
||||
{
|
||||
_logger.LogWarning("Ingredient with ID {IngredientId} not found for sale {SaleId}", ingredient.IngredientId, sale.Id);
|
||||
}
|
||||
movements.Add(new IngredientMoveDataModel
|
||||
{
|
||||
Date = sale.SaleDate,
|
||||
OperationType = _localizer["DocumentMovementOperationDeparture"].Value, // "Уход"
|
||||
IngredientId = ingredient.IngredientId,
|
||||
IngredientName = comp?.IngredientName ?? ingredient.IngredientId,
|
||||
Count = ingredient.Count,
|
||||
StorageId = null
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return movements.OrderBy(m => m.Date).ToList();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentIngredientMovementAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report IngredientMovement from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
var movements = await GetDataIngredientMovementAsync(dateStart, dateFinish, ct)
|
||||
?? throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
if (!movements.Any())
|
||||
{
|
||||
_logger.LogInformation("No movement records found from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
}
|
||||
|
||||
// Логируем содержимое movements
|
||||
_logger.LogInformation("Found {Count} movements", movements.Count);
|
||||
foreach (var movement in movements)
|
||||
{
|
||||
_logger.LogInformation("Movement: Date={Date}, OperationType={OperationType}, IngredientId={IngredientId}, IngredientName={IngredientName}, Count={Count}, StorageId={StorageId}",
|
||||
movement.Date, movement.OperationType, movement.IngredientId, movement.IngredientName, movement.Count, movement.StorageId);
|
||||
}
|
||||
|
||||
var tableRows = new List<string[]>
|
||||
{
|
||||
_movementTableHeader // // ["DocumentExcelMovementCaptionDate", "DocumentExcelMovementCaptionOperation", "DocumentExcelMovementCaptionIngredient", "DocumentExcelMovementCaptionCount", "DocumentExcelMovementCaptionStorage"]
|
||||
};
|
||||
|
||||
foreach (var movement in movements)
|
||||
{
|
||||
var storage = movement.StorageId != null ? await _storageContract.GetByIdAsync(movement.StorageId, ct) : null;
|
||||
if (storage == null && movement.StorageId != null)
|
||||
{
|
||||
_logger.LogWarning("Storage with ID {StorageId} not found for movement of ingredient {IngredientId}", movement.StorageId, movement.IngredientId);
|
||||
}
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
movement.Date.ToLocalTime().ToString("d", CultureInfo.CurrentCulture),
|
||||
movement.OperationType, // "Приход" или "Уход" (локализуется в данных)
|
||||
movement.IngredientName,
|
||||
movement.Count.ToString(),
|
||||
storage?.Address ?? _localizer["NotFoundDataMessage"]
|
||||
});
|
||||
}
|
||||
|
||||
// Вычисляем остаток: приходы увеличивают, уходы уменьшают
|
||||
var totalBalance = movements
|
||||
.Sum(m => m.OperationType == _localizer["DocumentMovementOperationArrival"].Value ? m.Count : -m.Count);
|
||||
|
||||
if (totalBalance < 0)
|
||||
{
|
||||
_logger.LogWarning("Negative balance detected: {TotalBalance}. Possible data inconsistency.", totalBalance);
|
||||
throw new InvalidOperationException(_localizer["NegativeBalanceMessage"]);
|
||||
}
|
||||
|
||||
tableRows.Add(new[]
|
||||
{
|
||||
_localizer["DocumentMovementCaptionTotal"], // "Итого (остаток)"
|
||||
"",
|
||||
"",
|
||||
totalBalance.ToString(),
|
||||
""
|
||||
});
|
||||
|
||||
// Логируем содержимое tableRows
|
||||
_logger.LogInformation("Table rows count: {Count}", tableRows.Count);
|
||||
foreach (var row in tableRows)
|
||||
{
|
||||
_logger.LogInformation("Row: {Row}", string.Join(", ", row));
|
||||
}
|
||||
|
||||
return _baseExcelBuilder
|
||||
.AddHeader(_localizer["DocumentMovementHeader"], 0, 5) // "Движение комплектующих"
|
||||
.AddParagraph(string.Format(_localizer["DocumentMovementSubHeader"], dateStart.ToLocalTime().ToString("d", CultureInfo.CurrentCulture), dateFinish.ToLocalTime().ToString("d", CultureInfo.CurrentCulture)), 0)
|
||||
.AddTable(new[] { 15, 15, 25, 10, 20 }, tableRows)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public async Task<List<StorageIngredientDataModel>> GetDataStorageStockAsync(string storageId, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data StorageStock for storage {storageId}", storageId);
|
||||
var ingredients = await _storageContract.GetIngredientsOnStorageAsync(storageId, ct);
|
||||
return ingredients?.OrderBy(c => c.IngredientId).ToList() ?? new List<StorageIngredientDataModel>();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentStorageStockAsync(string storageId, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report StorageStock for storage {storageId}", storageId);
|
||||
var ingredients = await GetDataStorageStockAsync(storageId, ct)
|
||||
?? throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
if (!ingredients.Any())
|
||||
{
|
||||
_logger.LogInformation("No stock records found for storage {storageId}", storageId);
|
||||
throw new InvalidOperationException(_localizer["NotFoundDataMessage"]);
|
||||
}
|
||||
var storage = await _storageContract.GetByIdAsync(storageId, ct);
|
||||
if (storage == null)
|
||||
{
|
||||
_logger.LogWarning("Storage with ID {StorageId} not found", storageId);
|
||||
}
|
||||
|
||||
// Предварительно загружаем все компоненты для оптимизации
|
||||
var ingredientIds = ingredients.Select(c => c.IngredientId).Distinct().ToList();
|
||||
var ingredientDict = new Dictionary<string, IngredientDataModel>();
|
||||
foreach (var ingredientId in ingredientIds)
|
||||
{
|
||||
var comp = await _ingredientStorageContract.GetElementByIdAsync(ingredientId, ct);
|
||||
if (comp != null)
|
||||
{
|
||||
ingredientDict[ingredientId] = comp;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Ingredient with ID {IngredientId} not found for storage {StorageId}", ingredientId, storageId);
|
||||
}
|
||||
}
|
||||
|
||||
var chartData = ingredients.Select(c => (
|
||||
ingredientDict.TryGetValue(c.IngredientId, out var comp) ? comp.IngredientName : c.IngredientId,
|
||||
(double)c.Count
|
||||
)).ToList();
|
||||
|
||||
return _basePdfBuilder
|
||||
.AddHeader(_localizer["DocumentStockHeader"]) // "Комплектующие на складе"
|
||||
.AddParagraph(string.Format(_localizer["DocumentStockSubHeader"], storage?.Address ?? _localizer["NotFoundDataMessage"]))
|
||||
.AddPieChart(_localizer["DocumentStockChartCaption"], chartData) // "Количество комплектующих"
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.Infrastructure.PostConfigurations;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using CandyHouseContracts.Resources;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
internal class SalaryBusinessLogicContract(ISalaryStorageContract salaryStorageContract, ISaleStorageContract saleStorageContract, IPostStorageContract postStorageContract, IWorkerStorageContract workerStorageContract, IStringLocalizer<Messages> localizer, ILogger logger, IConfigurationSalary сonfiguration) : ISalaryBusinessLogicContract
|
||||
{
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly ISalaryStorageContract _salaryStorageContract = salaryStorageContract;
|
||||
private readonly ISaleStorageContract _saleStorageContract = saleStorageContract;
|
||||
private readonly IPostStorageContract _postStorageContract = postStorageContract;
|
||||
private readonly IWorkerStorageContract _workerStorageContract = workerStorageContract;
|
||||
private readonly IConfigurationSalary _salaryConfiguration = сonfiguration;
|
||||
private readonly IStringLocalizer<Messages> _localizer = localizer;
|
||||
private readonly object _lockObject = new();
|
||||
|
||||
public List<SalaryDataModel> GetAllSalariesByPeriod(DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}",
|
||||
fromDate, toDate);
|
||||
if (fromDate.IsDateNotOlder(toDate))
|
||||
{
|
||||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||||
}
|
||||
return _salaryStorageContract.GetList(fromDate, toDate);
|
||||
}
|
||||
|
||||
public List<SalaryDataModel> GetAllSalariesByPeriodByWorker(DateTime fromDate, DateTime toDate, string workerId)
|
||||
{
|
||||
var fromUtc = fromDate.ToUniversalTime();
|
||||
var toUtc = toDate.ToUniversalTime();
|
||||
if (fromUtc.IsDateNotOlder(toUtc))
|
||||
{
|
||||
throw new IncorrectDatesException(fromUtc, toUtc, _localizer);
|
||||
}
|
||||
if (workerId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workerId));
|
||||
}
|
||||
if (!workerId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "WorkerId"));
|
||||
}
|
||||
_logger.LogInformation("GetAllSalaries params: {fromDate}, {toDate}, {workerId}", fromUtc, toUtc, workerId);
|
||||
return _salaryStorageContract.GetList(fromUtc, toUtc, workerId);
|
||||
}
|
||||
|
||||
public void CalculateSalaryByMonth(DateTime date)
|
||||
{
|
||||
_logger.LogInformation("CalculateSalaryByMounth: {date}", date);
|
||||
var startDate = new DateTime(date.Year, date.Month, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
var finishDate = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month), 23, 59, 59, 999, DateTimeKind.Utc);
|
||||
var workers = _workerStorageContract.GetList();
|
||||
foreach (var worker in workers)
|
||||
{
|
||||
var sales = _saleStorageContract.GetList(startDate, finishDate, workerId: worker.Id);
|
||||
var post = _postStorageContract.GetElementById(worker.PostId);
|
||||
if (post == null)
|
||||
{
|
||||
_logger.LogError("Post with ID {PostId} not found for worker {WorkerId}", worker.PostId, worker.Id);
|
||||
throw new ElementNotFoundException(worker.PostId, _localizer);
|
||||
}
|
||||
var salary = post.ConfigurationModel switch
|
||||
{
|
||||
null => 0,
|
||||
CashierPostConfiguration cpc => CalculateSalaryForCashier(sales, startDate, finishDate, cpc),
|
||||
SupervisorPostConfiguration spc => CalculateSalaryForSupervisor(startDate, finishDate, spc),
|
||||
PostConfiguration pc => pc.Rate,
|
||||
};
|
||||
_logger.LogDebug("The employee {workerId} was paid a salary of {salary}", worker.Id, salary);
|
||||
_salaryStorageContract.AddElement(new SalaryDataModel(worker.Id, finishDate, salary));
|
||||
}
|
||||
}
|
||||
|
||||
private double CalculateSalaryForCashier(List<SaleDataModel> sales, DateTime startDate, DateTime finishDate, CashierPostConfiguration config)
|
||||
{
|
||||
var tasks = new List<Task>();
|
||||
var calcPercent = 0.0;
|
||||
var semaphore = new SemaphoreSlim(_salaryConfiguration.MaxConcurrentThreads); // Ограничение потоков
|
||||
|
||||
// Создаём задачи для каждого дня
|
||||
for (var date = startDate; date <= finishDate; date = date.AddDays(1))
|
||||
{
|
||||
var currentDate = date; // Сохраняем дату для каждой задачи
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
await semaphore.WaitAsync(); // Ждём доступный слот
|
||||
try
|
||||
{
|
||||
var salesInDay = sales.Where(x => x.SaleDate.Date == currentDate.Date && !x.IsCancel).ToArray();
|
||||
if (salesInDay.Length > 0)
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
calcPercent += (salesInDay.Sum(x => x.Sum) / salesInDay.Length) * _salaryConfiguration.CashierSalePercent;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release(); // Освобождаем слот
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// Расчёт бонуса в отдельной задаче
|
||||
var calcBonusTask = Task.Run(() =>
|
||||
{
|
||||
return sales.Where(x => x.Sum > _salaryConfiguration.ExtraSaleSum && !x.IsCancel)
|
||||
.Sum(x => x.Sum) * _salaryConfiguration.CashierBonusForExtraSales;
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks.ToArray()); // Ждём завершения всех задач для процентов
|
||||
var bonus = calcBonusTask.Result; // Получаем результат бонуса
|
||||
return config.Rate + calcPercent + bonus;
|
||||
}
|
||||
catch (AggregateException agEx)
|
||||
{
|
||||
foreach (var ex in agEx.InnerExceptions)
|
||||
{
|
||||
_logger.LogError(ex, "Error in the cashier payroll process");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private double CalculateSalaryForSupervisor(DateTime startDate, DateTime finishDate, SupervisorPostConfiguration config)
|
||||
{
|
||||
try
|
||||
{
|
||||
return config.Rate + _salaryConfiguration.SupervisorTrendPremium * _workerStorageContract.GetWorkerTrend(startDate, finishDate); // Из глобальных настроек
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error in the supervisor payroll process");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.Resources;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using System.Text.Json;
|
||||
|
||||
internal class SaleBusinessLogicContract(ISaleStorageContract saleStorageContract, IStorageContract storageStorageContract, IStringLocalizer<Messages> localizer, ILogger logger) : ISaleBusinessLogicContract{
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly ISaleStorageContract _saleStorageContract = saleStorageContract;
|
||||
private readonly IStorageContract _storageStorageContract = storageStorageContract;
|
||||
private readonly IStringLocalizer<Messages> _localizer = localizer;
|
||||
|
||||
public List<SaleDataModel> GetAllSalesByPeriod(DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
_logger.LogInformation("GetAllSales params: {fromDate}, {toDate}",
|
||||
fromDate, toDate);
|
||||
if (fromDate.IsDateNotOlder(toDate))
|
||||
{
|
||||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||||
}
|
||||
return _saleStorageContract.GetList(fromDate, toDate);
|
||||
}
|
||||
|
||||
public List<SaleDataModel> GetAllSalesByWorkerByPeriod(string workerId, DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
_logger.LogInformation("GetAllSales params: {workerId}, {fromDate}, {toDate}", workerId, fromDate, toDate);
|
||||
if (fromDate.IsDateNotOlder(toDate))
|
||||
{
|
||||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||||
}
|
||||
if (workerId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workerId));
|
||||
}
|
||||
if (!workerId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "WorkerId"));
|
||||
}
|
||||
return _saleStorageContract.GetList(fromDate, toDate, workerId:
|
||||
workerId);
|
||||
}
|
||||
|
||||
public List<SaleDataModel> GetAllSalesByCustomerByPeriod(string customerId,
|
||||
DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
_logger.LogInformation("GetAllSales params: {customerId}, {fromDate}, {toDate}", customerId, fromDate, toDate);
|
||||
if (fromDate.IsDateNotOlder(toDate))
|
||||
{
|
||||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||||
}
|
||||
if (customerId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(customerId));
|
||||
}
|
||||
if (!customerId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "CustomerId"));
|
||||
}
|
||||
return _saleStorageContract.GetList(fromDate, toDate, customerId:
|
||||
customerId);
|
||||
}
|
||||
|
||||
public List<SaleDataModel> GetAllSalesByProductByPeriod(string productId, DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
_logger.LogInformation("GetAllSales params: {productId}, {fromDate}, {toDate}", productId, fromDate, toDate);
|
||||
if (fromDate.IsDateNotOlder(toDate))
|
||||
{
|
||||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||||
}
|
||||
if (productId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(productId));
|
||||
}
|
||||
if (!productId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "ProductId"));
|
||||
}
|
||||
return _saleStorageContract.GetList(fromDate, toDate, productId: productId);
|
||||
}
|
||||
|
||||
public SaleDataModel GetSaleByData(string data)
|
||||
{
|
||||
_logger.LogInformation("Get element by data: {data}", data);
|
||||
if (data.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
if (!data.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
return _saleStorageContract.GetElementById(data) ?? throw new
|
||||
ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
|
||||
public void InsertSale(SaleDataModel saleDataModel)
|
||||
{
|
||||
_logger.LogInformation("New data: {json}",
|
||||
JsonSerializer.Serialize(saleDataModel));
|
||||
ArgumentNullException.ThrowIfNull(saleDataModel);
|
||||
saleDataModel.Validate(_localizer);
|
||||
|
||||
if (!_storageStorageContract.CheckAndWriteOffСomponentsFromStorage(saleDataModel))
|
||||
{
|
||||
throw new InsufficientStockException(_localizer);
|
||||
}
|
||||
|
||||
_saleStorageContract.AddElement(saleDataModel);
|
||||
}
|
||||
|
||||
public void CancelSale(string id)
|
||||
{
|
||||
_logger.LogInformation("Cancel by id: {id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
_saleStorageContract.DelElement(id);
|
||||
}
|
||||
|
||||
public double CalculateSalesRevenue(DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
if (fromDate > toDate)
|
||||
throw new ValidationException("fromDate cannot be later than toDate");
|
||||
|
||||
_logger.LogInformation("Calculating sales revenue from {fromDate} to {toDate}", fromDate, toDate);
|
||||
|
||||
var sales = GetAllSalesByPeriod(fromDate, toDate);
|
||||
if (sales == null || !sales.Any())
|
||||
{
|
||||
_logger.LogWarning("No sales found for the period {fromDate} to {toDate}", fromDate, toDate);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double totalRevenue = 0.0;
|
||||
object lockObject = new object();
|
||||
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
|
||||
|
||||
try
|
||||
{
|
||||
Parallel.ForEach(sales, parallelOptions, sale =>
|
||||
{
|
||||
if (!sale.IsCancel)
|
||||
{
|
||||
double saleRevenue = sale.Sum - sale.Discount;
|
||||
lock (lockObject)
|
||||
{
|
||||
totalRevenue += saleRevenue;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error occurred while calculating sales revenue");
|
||||
throw new StorageException(ex, _localizer);
|
||||
}
|
||||
|
||||
_logger.LogInformation("Total sales revenue: {totalRevenue}", totalRevenue);
|
||||
return totalRevenue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Resources;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
|
||||
internal class StorageBusinessLogicContract : IStorageBusinessLogicContract
|
||||
{
|
||||
private readonly IStorageContract _storageContract;
|
||||
private readonly ISupplyStorageContract _supplyStorageContract;
|
||||
private readonly ILogger<StorageBusinessLogicContract> _logger;
|
||||
private readonly IStringLocalizer<Messages> _localizer;
|
||||
|
||||
public StorageBusinessLogicContract(IStorageContract storageContract, ISupplyStorageContract supplyStorageContract, IStringLocalizer<Messages> localizer, ILogger<StorageBusinessLogicContract> logger)
|
||||
{
|
||||
_storageContract = storageContract ?? throw new ArgumentNullException(nameof(storageContract));
|
||||
_supplyStorageContract = supplyStorageContract ?? throw new ArgumentNullException(nameof(supplyStorageContract));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
public List<StorageDataModel> GetAllStorages()
|
||||
{
|
||||
var storages = _storageContract.GetAllStorages();
|
||||
return storages;
|
||||
}
|
||||
|
||||
public void CreateStorage(string id, string address, int count, List<StorageIngredientDataModel> ingredients)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "id"));
|
||||
|
||||
if (string.IsNullOrEmpty(address))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "address"));
|
||||
|
||||
// Проверка существования склада с таким ID
|
||||
if (_storageContract.GetStorageById(id) != null)
|
||||
throw new ElementExistsException("Id", id, _localizer);
|
||||
|
||||
var storage = new StorageDataModel(id, address, count, ingredients ?? new List<StorageIngredientDataModel>());
|
||||
storage.Validate(_localizer);
|
||||
_storageContract.AddStorage(storage);
|
||||
}
|
||||
|
||||
public void UpdateStorage(StorageDataModel storage)
|
||||
{
|
||||
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(storage));
|
||||
ArgumentNullException.ThrowIfNull(storage);
|
||||
storage.Validate(_localizer);
|
||||
var existingStorage = _storageContract.GetStorageById(storage.Id);
|
||||
if (existingStorage == null)
|
||||
throw new ElementNotFoundException($"Storage with ID {storage.Id} not found", _localizer);
|
||||
|
||||
_storageContract.UpdateStorage(storage);
|
||||
}
|
||||
|
||||
public void AddIngredientToStorage(string storageId, StorageIngredientDataModel ingredient)
|
||||
{
|
||||
if (string.IsNullOrEmpty(storageId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "storageId"));
|
||||
|
||||
if (ingredient == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "ingredient"));
|
||||
|
||||
var storage = _storageContract.GetStorageById(storageId);
|
||||
if (storage == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "storage"));
|
||||
|
||||
ingredient.Validate(_localizer);
|
||||
var existingIngredient = _storageContract.GetIngredientOnStorage(storageId, ingredient.IngredientId);
|
||||
var updatedCount = existingIngredient?.Count + ingredient.Count ?? ingredient.Count;
|
||||
var updatedIngredient = new StorageIngredientDataModel(storageId, ingredient.IngredientId, updatedCount);
|
||||
_storageContract.AddOrUpdateIngredientOnStorage(updatedIngredient);
|
||||
}
|
||||
|
||||
public void UpdateIngredientCount(string storageId, string ingredientId, int newCount)
|
||||
{
|
||||
if (string.IsNullOrEmpty(storageId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "storageId"));
|
||||
|
||||
if (string.IsNullOrEmpty(ingredientId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "ingredientId"));
|
||||
|
||||
if (newCount < 0)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageLessOrEqualZero"], "newCount"));
|
||||
|
||||
var storage = _storageContract.GetStorageById(storageId);
|
||||
if (storage == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "storage"));
|
||||
|
||||
_storageContract.UpdateIngredientCount(storageId, ingredientId, newCount);
|
||||
}
|
||||
|
||||
public int GetIngredientCountFromStorage(string storageId, string ingredientId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(storageId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "storageId"));
|
||||
|
||||
if (string.IsNullOrEmpty(ingredientId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "ingredientId"));
|
||||
|
||||
var ingredient = _storageContract.GetIngredientOnStorage(storageId, ingredientId);
|
||||
if (ingredient == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "ingredient"));
|
||||
|
||||
return ingredient.Count;
|
||||
}
|
||||
|
||||
public List<StorageIngredientDataModel> GetIngredientsFromStorage(string storageId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(storageId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "storageId"));
|
||||
|
||||
var storage = _storageContract.GetStorageById(storageId);
|
||||
if (storage == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "storage"));
|
||||
|
||||
return _storageContract.GetIngredientsOnStorage(storageId);
|
||||
}
|
||||
|
||||
public StorageDataModel GetStorageById(string storageId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(storageId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "storageId"));
|
||||
|
||||
var storage = _storageContract.GetStorageById(storageId);
|
||||
if (storage == null)
|
||||
throw new ElementNotFoundException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "storage"), _localizer);
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
public Dictionary<string, int> CalculateRemainingIngredients(string storageId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(storageId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "storageId"));
|
||||
|
||||
var storage = _storageContract.GetStorageById(storageId);
|
||||
if (storage == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "storage"));
|
||||
|
||||
_logger.LogInformation("Calculating remaining ingredients for storage {storageId}", storageId);
|
||||
|
||||
var remainingIngredients = new Dictionary<string, int>();
|
||||
|
||||
try
|
||||
{
|
||||
var supplyTask = Task.Run(() =>
|
||||
{
|
||||
var supplies = _supplyStorageContract.GetSuppliesByStorageId(storageId);
|
||||
var suppliedIngredients = new Dictionary<string, int>();
|
||||
foreach (var supply in supplies)
|
||||
{
|
||||
if (supply.Ingredients != null)
|
||||
{
|
||||
foreach (var ingredient in supply.Ingredients)
|
||||
{
|
||||
if (suppliedIngredients.ContainsKey(ingredient.IngredientId))
|
||||
suppliedIngredients[ingredient.IngredientId] += ingredient.Count;
|
||||
else
|
||||
suppliedIngredients[ingredient.IngredientId] = ingredient.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return suppliedIngredients;
|
||||
});
|
||||
|
||||
var writeOffTask = Task.Run(() =>
|
||||
{
|
||||
return _storageContract.GetWrittenOffIngredientsByStorageId(storageId);
|
||||
});
|
||||
|
||||
Task.WhenAll(supplyTask, writeOffTask).GetAwaiter().GetResult();
|
||||
|
||||
var suppliedIngredients = supplyTask.Result;
|
||||
var writtenOffIngredients = writeOffTask.Result;
|
||||
|
||||
foreach (var ingredient in suppliedIngredients)
|
||||
{
|
||||
int writtenOffCount = writtenOffIngredients.ContainsKey(ingredient.Key) ? writtenOffIngredients[ingredient.Key] : 0;
|
||||
int remainingCount = ingredient.Value - writtenOffCount;
|
||||
if (remainingCount > 0)
|
||||
{
|
||||
remainingIngredients[ingredient.Key] = remainingCount;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Remaining ingredients calculated for storage {storageId}: {count} ingredients", storageId, remainingIngredients.Count);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error occurred while calculating remaining ingredients for storage {storageId}", storageId);
|
||||
throw new StorageException(ex, _localizer);
|
||||
}
|
||||
|
||||
return remainingIngredients;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
using DocumentFormat.OpenXml.VariantTypes;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Resources;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
|
||||
internal class SupplyBusinessLogicContract : ISupplyBusinessLogicContract
|
||||
{
|
||||
private readonly ISupplyStorageContract _supplyStorageContract;
|
||||
private readonly IStorageContract _storageContract;
|
||||
private readonly IStringLocalizer<Messages> _localizer;
|
||||
|
||||
public SupplyBusinessLogicContract(ISupplyStorageContract supplyStorageContract, IStorageContract storageContract, IStringLocalizer<Messages> localizer)
|
||||
{
|
||||
_supplyStorageContract = supplyStorageContract ?? throw new ArgumentNullException(nameof(supplyStorageContract));
|
||||
_storageContract = storageContract ?? throw new ArgumentNullException(nameof(storageContract));
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
public void CreateSupply(SupplyDataModel supply)
|
||||
{
|
||||
if (supply == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "supply"));
|
||||
|
||||
// Проверка существования поставки с таким ID
|
||||
if (_supplyStorageContract.GetSupplyById(supply.Id) != null)
|
||||
throw new ElementExistsException("Id", supply.Id, _localizer);
|
||||
|
||||
supply.Validate(_localizer);
|
||||
var storage = _storageContract.GetStorageById(supply.StorageId);
|
||||
if (storage == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "storage"));
|
||||
|
||||
foreach (var ingredient in supply.Ingredients)
|
||||
{
|
||||
ingredient.Validate(_localizer);
|
||||
}
|
||||
|
||||
_supplyStorageContract.AddSupply(supply);
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var ingredient in supply.Ingredients)
|
||||
{
|
||||
var storageIngredient = _storageContract.GetIngredientOnStorage(supply.StorageId, ingredient.IngredientId)
|
||||
?? new StorageIngredientDataModel(supply.StorageId, ingredient.IngredientId, 0);
|
||||
var updatedIngredient = new StorageIngredientDataModel(
|
||||
storageIngredient.StorageId,
|
||||
storageIngredient.IngredientId,
|
||||
storageIngredient.Count + ingredient.Count
|
||||
);
|
||||
_storageContract.AddOrUpdateIngredientOnStorage(updatedIngredient);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_supplyStorageContract.RemoveSupply(supply.Id);
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageUnexpectedError"], ex));
|
||||
}
|
||||
}
|
||||
|
||||
public List<SupplyDataModel> GetAllSupplies()
|
||||
{
|
||||
var supplies = _supplyStorageContract.GetAllSupplies();
|
||||
if (supplies is null || supplies.Count == 0)
|
||||
{
|
||||
throw new ElementNotFoundException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "supplyId"), _localizer);
|
||||
}
|
||||
return supplies;
|
||||
}
|
||||
|
||||
public SupplyDataModel GetSupplyById(string supplyId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(supplyId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "supplyId"));
|
||||
|
||||
var supply = _supplyStorageContract.GetSupplyById(supplyId);
|
||||
if (supply == null)
|
||||
throw new ElementNotFoundException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "supply"), _localizer);
|
||||
|
||||
return supply;
|
||||
}
|
||||
|
||||
public List<SupplyDataModel> GetSuppliesByStorageId(string storageId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(storageId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "storageId"));
|
||||
|
||||
var storage = _storageContract.GetStorageById(storageId);
|
||||
if (storage == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "storage"));
|
||||
|
||||
return _supplyStorageContract.GetSuppliesByStorageId(storageId);
|
||||
}
|
||||
|
||||
public void AddOrUpdateIngredientInSupply(SupplyIngredientDataModel ingredient)
|
||||
{
|
||||
if (ingredient == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "ingredient"));
|
||||
|
||||
ingredient.Validate(_localizer);
|
||||
_supplyStorageContract.AddOrUpdateIngredientInSupply(ingredient);
|
||||
}
|
||||
|
||||
public void UpdateIngredientCountInSupply(string supplyId, string ingredientId, int newCount)
|
||||
{
|
||||
if (string.IsNullOrEmpty(supplyId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "supplyId"));
|
||||
|
||||
if (string.IsNullOrEmpty(ingredientId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "ingredientId"));
|
||||
|
||||
if (newCount <= 0)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageLessOrEqualZero"], "newCount"));
|
||||
|
||||
var supply = _supplyStorageContract.GetSupplyById(supplyId);
|
||||
if (supply == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "supply"));
|
||||
|
||||
_supplyStorageContract.UpdateIngredientCountInSupply(supplyId, ingredientId, newCount);
|
||||
}
|
||||
|
||||
public void RemoveIngredientFromSupply(string supplyId, string ingredientId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(supplyId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "supplyId"));
|
||||
|
||||
if (string.IsNullOrEmpty(ingredientId))
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageEmptyField"], "ingredientId"));
|
||||
|
||||
var supply = _supplyStorageContract.GetSupplyById(supplyId);
|
||||
if (supply == null)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotInitialized"], "supply"));
|
||||
|
||||
_supplyStorageContract.RemoveIngredientFromSupply(supplyId, ingredientId);
|
||||
}
|
||||
|
||||
public int CalculateSuppliedIngredientsCount(DateTime fromDate, DateTime toDate)
|
||||
{
|
||||
if (fromDate > toDate)
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageDeliveryDateInFuture"], fromDate.ToShortDateString()));
|
||||
|
||||
var supplies = _supplyStorageContract.GetSuppliesByPeriod(fromDate, toDate);
|
||||
if (supplies == null || !supplies.Any())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int totalCount = 0;
|
||||
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
|
||||
|
||||
try
|
||||
{
|
||||
Parallel.ForEach(supplies, parallelOptions, supply =>
|
||||
{
|
||||
if (supply.Ingredients != null)
|
||||
{
|
||||
int supplyCount = supply.Ingredients.Sum(c => c.Count);
|
||||
Interlocked.Add(ref totalCount, supplyCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
throw new StorageException(ex, _localizer);
|
||||
}
|
||||
|
||||
return totalCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using CandyHouseContracts.BusinessLogicsContracts;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using CandyHouseContracts.Exceptions;
|
||||
using CandyHouseContracts.Extensions;
|
||||
using CandyHouseContracts.StoragesContracts;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using CandyHouseContracts.Resources;
|
||||
|
||||
namespace CandyHouseBusinessLogic.Implementations;
|
||||
internal class WorkerBusinessLogicContract(IWorkerStorageContract workerStorage, IStringLocalizer<Messages> localizer, ILogger<WorkerBusinessLogicContract> logger) : IWorkerBusinessLogicContract
|
||||
{
|
||||
private readonly ILogger<WorkerBusinessLogicContract> _logger = logger;
|
||||
private readonly IWorkerStorageContract _workerStorage = workerStorage;
|
||||
private readonly IStringLocalizer<Messages> _localizer = localizer;
|
||||
|
||||
public List<WorkerDataModel> GetAllWorkers(bool onlyActive = true)
|
||||
{
|
||||
_logger.LogInformation("GetAllWorkers params: {onlyActive}", onlyActive);
|
||||
return _workerStorage.GetList(onlyActive, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public List<WorkerDataModel> GetAllWorkersByPost(string postId, bool onlyActive = true)
|
||||
{
|
||||
_logger.LogInformation("GetAllWorkers params: {postId}, {onlyActive}", postId, onlyActive);
|
||||
if (postId.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(postId));
|
||||
}
|
||||
if (!postId.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "PostId"));
|
||||
}
|
||||
return _workerStorage.GetList(onlyActive, postId, null, null, null, null);
|
||||
}
|
||||
|
||||
public List<WorkerDataModel> GetAllWorkersByBirthDate(DateTime fromDate, DateTime toDate, bool onlyActive = true)
|
||||
{
|
||||
_logger.LogInformation("GetAllWorkers params: {onlyActive}, {fromDate}, {toDate}", onlyActive, fromDate, toDate);
|
||||
if (fromDate.IsDateNotOlder(toDate))
|
||||
{
|
||||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||||
}
|
||||
return _workerStorage.GetList(onlyActive, null, fromDate, toDate, null, null);
|
||||
}
|
||||
|
||||
public List<WorkerDataModel> GetAllWorkersByEmploymentDate(DateTime fromDate, DateTime toDate, bool onlyActive = true)
|
||||
{
|
||||
_logger.LogInformation("GetAllWorkers params: {onlyActive}, {fromDate}, {toDate}", onlyActive, fromDate, toDate);
|
||||
if (fromDate.IsDateNotOlder(toDate))
|
||||
{
|
||||
throw new IncorrectDatesException(fromDate, toDate, _localizer);
|
||||
}
|
||||
return _workerStorage.GetList(onlyActive, null, null, null, fromDate, toDate);
|
||||
}
|
||||
|
||||
public WorkerDataModel GetWorkerByData(string data)
|
||||
{
|
||||
_logger.LogInformation("Get element by data: {data}", data);
|
||||
if (data.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
if (data.IsGuid())
|
||||
{
|
||||
return _workerStorage.GetElementById(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
return _workerStorage.GetElementByFIO(data) ?? throw new ElementNotFoundException(data, _localizer);
|
||||
}
|
||||
|
||||
public void InsertWorker(WorkerDataModel workerDataModel)
|
||||
{
|
||||
_logger.LogInformation("New data: {json}", JsonSerializer.Serialize(workerDataModel));
|
||||
ArgumentNullException.ThrowIfNull(workerDataModel);
|
||||
workerDataModel.Validate(_localizer);
|
||||
_workerStorage.AddElement(workerDataModel);
|
||||
}
|
||||
|
||||
public void UpdateWorker(WorkerDataModel workerDataModel)
|
||||
{
|
||||
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(workerDataModel));
|
||||
ArgumentNullException.ThrowIfNull(workerDataModel);
|
||||
workerDataModel.Validate(_localizer);
|
||||
_workerStorage.UpdateElement(workerDataModel);
|
||||
}
|
||||
|
||||
public void DeleteWorker(string id)
|
||||
{
|
||||
_logger.LogInformation("Delete by id: {id}", id);
|
||||
if (id.IsEmpty())
|
||||
{
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
}
|
||||
if (!id.IsGuid())
|
||||
{
|
||||
throw new ValidationException(string.Format(_localizer["ValidationExceptionMessageNotAId"], "Id"));
|
||||
}
|
||||
_workerStorage.DeleteElement(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace CandyHouseBusinessLogic.OfficePackage;
|
||||
|
||||
public abstract class BaseExcelBuilder
|
||||
{
|
||||
public abstract BaseExcelBuilder AddHeader(string header, int startIndex, int count);
|
||||
|
||||
public abstract BaseExcelBuilder AddParagraph(string text, int columnIndex);
|
||||
|
||||
public abstract BaseExcelBuilder AddTable(int[] columnsWidths, List<string[]> data);
|
||||
|
||||
public abstract Stream Build();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace CandyHouseBusinessLogic.OfficePackage;
|
||||
|
||||
public abstract class BasePdfBuilder
|
||||
{
|
||||
public abstract BasePdfBuilder AddHeader(string header);
|
||||
|
||||
public abstract BasePdfBuilder AddParagraph(string text);
|
||||
|
||||
public abstract BasePdfBuilder AddPieChart(string title, List<(string Caption, double Value)> data);
|
||||
|
||||
public abstract Stream Build();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace CandyHouseBusinessLogic.OfficePackage;
|
||||
|
||||
public abstract class BaseWordBuilder
|
||||
{
|
||||
public abstract BaseWordBuilder AddHeader(string header);
|
||||
|
||||
public abstract BaseWordBuilder AddParagraph(string text);
|
||||
|
||||
public abstract BaseWordBuilder AddTable(int[] widths, List<string[]> data);
|
||||
|
||||
public abstract Stream Build();
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using MigraDoc.DocumentObjectModel;
|
||||
using MigraDoc.DocumentObjectModel.Shapes.Charts;
|
||||
using MigraDoc.Rendering;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace CandyHouseBusinessLogic.OfficePackage;
|
||||
|
||||
internal class MigraDocPdfBuilder : BasePdfBuilder
|
||||
{
|
||||
private readonly Document _document;
|
||||
|
||||
public MigraDocPdfBuilder()
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
_document = new Document();
|
||||
DefineStyles();
|
||||
}
|
||||
|
||||
public override BasePdfBuilder AddHeader(string header)
|
||||
{
|
||||
_document.AddSection().AddParagraph(header, "NormalBold");
|
||||
return this;
|
||||
}
|
||||
|
||||
public override BasePdfBuilder AddParagraph(string text)
|
||||
{
|
||||
_document.LastSection.AddParagraph(text, "Normal");
|
||||
return this;
|
||||
}
|
||||
|
||||
public override BasePdfBuilder AddPieChart(string title, List<(string Caption, double Value)> data)
|
||||
{
|
||||
if (data == null || data.Count == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
var chart = new Chart(ChartType.Pie2D);
|
||||
var series = chart.SeriesCollection.AddSeries();
|
||||
series.Add(data.Select(x => x.Value).ToArray());
|
||||
|
||||
var xseries = chart.XValues.AddXSeries();
|
||||
xseries.Add(data.Select(x => x.Caption).ToArray());
|
||||
|
||||
chart.DataLabel.Type = DataLabelType.Value;
|
||||
chart.DataLabel.Position = DataLabelPosition.OutsideEnd;
|
||||
|
||||
chart.Width = Unit.FromCentimeter(16);
|
||||
chart.Height = Unit.FromCentimeter(12);
|
||||
|
||||
chart.TopArea.AddParagraph(title);
|
||||
|
||||
chart.XAxis.MajorTickMark = TickMarkType.Outside;
|
||||
|
||||
chart.YAxis.MajorTickMark = TickMarkType.Outside;
|
||||
chart.YAxis.HasMajorGridlines = true;
|
||||
|
||||
chart.PlotArea.LineFormat.Width = 1;
|
||||
chart.PlotArea.LineFormat.Visible = true;
|
||||
|
||||
chart.TopArea.AddLegend();
|
||||
|
||||
_document.LastSection.Add(chart);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override Stream Build()
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var renderer = new PdfDocumentRenderer(true)
|
||||
{
|
||||
Document = _document
|
||||
};
|
||||
renderer.RenderDocument();
|
||||
renderer.PdfDocument.Save(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
private void DefineStyles()
|
||||
{
|
||||
var style = _document.Styles.AddStyle("NormalBold", "Normal");
|
||||
style.Font.Bold = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
using DocumentFormat.OpenXml.Packaging;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using DocumentFormat.OpenXml;
|
||||
|
||||
namespace CandyHouseBusinessLogic.OfficePackage;
|
||||
|
||||
internal class OpenXmlExcelBuilder : BaseExcelBuilder
|
||||
{
|
||||
private readonly SheetData _sheetData;
|
||||
|
||||
private readonly MergeCells _mergeCells;
|
||||
|
||||
private readonly Columns _columns;
|
||||
|
||||
private uint _rowIndex = 0;
|
||||
|
||||
public OpenXmlExcelBuilder()
|
||||
{
|
||||
_sheetData = new SheetData();
|
||||
_mergeCells = new MergeCells();
|
||||
_columns = new Columns();
|
||||
_rowIndex = 1;
|
||||
}
|
||||
|
||||
public override BaseExcelBuilder AddHeader(string header, int startIndex, int count)
|
||||
{
|
||||
CreateCell(startIndex, _rowIndex, header, StyleIndex.BoldTextWithoutBorder);
|
||||
for (int i = startIndex + 1; i < startIndex + count; ++i)
|
||||
{
|
||||
CreateCell(i, _rowIndex, "", StyleIndex.SimpleTextWithoutBorder);
|
||||
}
|
||||
|
||||
_mergeCells.Append(new MergeCell()
|
||||
{
|
||||
Reference =
|
||||
new StringValue($"{GetExcelColumnName(startIndex)}{_rowIndex}:{GetExcelColumnName(startIndex + count - 1)}{_rowIndex}")
|
||||
});
|
||||
|
||||
_rowIndex++;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override BaseExcelBuilder AddParagraph(string text, int columnIndex)
|
||||
{
|
||||
CreateCell(columnIndex, _rowIndex++, text, StyleIndex.SimpleTextWithoutBorder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override BaseExcelBuilder AddTable(int[] columnsWidths, List<string[]> data)
|
||||
{
|
||||
if (columnsWidths == null || columnsWidths.Length == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columnsWidths));
|
||||
}
|
||||
|
||||
if (data == null || data.Count == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
if (data.Any(x => x.Length != columnsWidths.Length))
|
||||
{
|
||||
throw new InvalidOperationException("widths.Length != data.Length");
|
||||
}
|
||||
|
||||
uint counter = 1;
|
||||
int coef = 2;
|
||||
_columns.Append(columnsWidths.Select(x => new Column
|
||||
{
|
||||
Min = counter,
|
||||
Max = counter++,
|
||||
Width = x * coef,
|
||||
CustomWidth = true
|
||||
}));
|
||||
|
||||
for (var j = 0; j < data.First().Length; ++j)
|
||||
{
|
||||
CreateCell(j, _rowIndex, data.First()[j], StyleIndex.BoldTextWithBorder);
|
||||
}
|
||||
|
||||
_rowIndex++;
|
||||
for (var i = 1; i < data.Count - 1; ++i)
|
||||
{
|
||||
for (var j = 0; j < data[i].Length; ++j)
|
||||
{
|
||||
CreateCell(j, _rowIndex, data[i][j], StyleIndex.SimpleTextWithBorder);
|
||||
}
|
||||
|
||||
_rowIndex++;
|
||||
}
|
||||
|
||||
for (var j = 0; j < data.Last().Length; ++j)
|
||||
{
|
||||
CreateCell(j, _rowIndex, data.Last()[j], StyleIndex.BoldTextWithBorder);
|
||||
}
|
||||
|
||||
_rowIndex++;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override Stream Build()
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using var spreadsheetDocument = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook);
|
||||
var workbookpart = spreadsheetDocument.AddWorkbookPart();
|
||||
GenerateStyle(workbookpart);
|
||||
workbookpart.Workbook = new Workbook();
|
||||
var worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
|
||||
worksheetPart.Worksheet = new Worksheet();
|
||||
if (_columns.HasChildren)
|
||||
{
|
||||
worksheetPart.Worksheet.Append(_columns);
|
||||
}
|
||||
|
||||
worksheetPart.Worksheet.Append(_sheetData);
|
||||
var sheets = spreadsheetDocument.WorkbookPart!.Workbook.AppendChild(new Sheets());
|
||||
var sheet = new Sheet()
|
||||
{
|
||||
Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
|
||||
SheetId = 1,
|
||||
Name = "Лист 1"
|
||||
};
|
||||
|
||||
sheets.Append(sheet);
|
||||
if (_mergeCells.HasChildren)
|
||||
{
|
||||
worksheetPart.Worksheet.InsertAfter(_mergeCells, worksheetPart.Worksheet.Elements<SheetData>().First());
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
private static void GenerateStyle(WorkbookPart workbookPart)
|
||||
{
|
||||
var workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
|
||||
workbookStylesPart.Stylesheet = new Stylesheet();
|
||||
|
||||
var fonts = new Fonts() { Count = 2, KnownFonts = BooleanValue.FromBoolean(true) };
|
||||
fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
|
||||
{
|
||||
FontSize = new FontSize() { Val = 11 },
|
||||
FontName = new FontName() { Val = "Calibri" },
|
||||
FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
|
||||
FontScheme = new FontScheme() { Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor) }
|
||||
});
|
||||
fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
|
||||
{
|
||||
FontSize = new FontSize() { Val = 11 },
|
||||
FontName = new FontName() { Val = "Calibri" },
|
||||
FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
|
||||
FontScheme = new FontScheme() { Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor) },
|
||||
Bold = new Bold()
|
||||
});
|
||||
workbookStylesPart.Stylesheet.Append(fonts);
|
||||
|
||||
// Default Fill
|
||||
var fills = new Fills() { Count = 1 };
|
||||
fills.Append(new Fill
|
||||
{
|
||||
PatternFill = new PatternFill() { PatternType = new EnumValue<PatternValues>(PatternValues.None) }
|
||||
});
|
||||
workbookStylesPart.Stylesheet.Append(fills);
|
||||
|
||||
// Default Border
|
||||
var borders = new Borders() { Count = 2 };
|
||||
borders.Append(new Border
|
||||
{
|
||||
LeftBorder = new LeftBorder(),
|
||||
RightBorder = new RightBorder(),
|
||||
TopBorder = new TopBorder(),
|
||||
BottomBorder = new BottomBorder(),
|
||||
DiagonalBorder = new DiagonalBorder()
|
||||
});
|
||||
borders.Append(new Border
|
||||
{
|
||||
LeftBorder = new LeftBorder() { Style = BorderStyleValues.Thin },
|
||||
RightBorder = new RightBorder() { Style = BorderStyleValues.Thin },
|
||||
TopBorder = new TopBorder() { Style = BorderStyleValues.Thin },
|
||||
BottomBorder = new BottomBorder() { Style = BorderStyleValues.Thin }
|
||||
});
|
||||
workbookStylesPart.Stylesheet.Append(borders);
|
||||
|
||||
// Default cell format and a date cell format
|
||||
var cellFormats = new CellFormats() { Count = 4 };
|
||||
cellFormats.Append(new CellFormat
|
||||
{
|
||||
NumberFormatId = 0,
|
||||
FormatId = 0,
|
||||
FontId = 0,
|
||||
BorderId = 0,
|
||||
FillId = 0,
|
||||
Alignment = new Alignment()
|
||||
{
|
||||
Horizontal = HorizontalAlignmentValues.Left,
|
||||
Vertical = VerticalAlignmentValues.Center,
|
||||
WrapText = true
|
||||
}
|
||||
});
|
||||
cellFormats.Append(new CellFormat
|
||||
{
|
||||
NumberFormatId = 0,
|
||||
FormatId = 0,
|
||||
FontId = 0,
|
||||
BorderId = 1,
|
||||
FillId = 0,
|
||||
Alignment = new Alignment()
|
||||
{
|
||||
Horizontal = HorizontalAlignmentValues.Left,
|
||||
Vertical = VerticalAlignmentValues.Center,
|
||||
WrapText = true
|
||||
}
|
||||
});
|
||||
cellFormats.Append(new CellFormat
|
||||
{
|
||||
NumberFormatId = 0,
|
||||
FormatId = 0,
|
||||
FontId = 1,
|
||||
BorderId = 0,
|
||||
FillId = 0,
|
||||
Alignment = new Alignment()
|
||||
{
|
||||
Horizontal = HorizontalAlignmentValues.Center,
|
||||
Vertical = VerticalAlignmentValues.Center,
|
||||
WrapText = true
|
||||
}
|
||||
});
|
||||
cellFormats.Append(new CellFormat
|
||||
{
|
||||
NumberFormatId = 0,
|
||||
FormatId = 0,
|
||||
FontId = 1,
|
||||
BorderId = 1,
|
||||
FillId = 0,
|
||||
Alignment = new Alignment()
|
||||
{
|
||||
Horizontal = HorizontalAlignmentValues.Center,
|
||||
Vertical = VerticalAlignmentValues.Center,
|
||||
WrapText = true
|
||||
}
|
||||
});
|
||||
workbookStylesPart.Stylesheet.Append(cellFormats);
|
||||
}
|
||||
|
||||
private enum StyleIndex
|
||||
{
|
||||
SimpleTextWithoutBorder = 0,
|
||||
SimpleTextWithBorder = 1,
|
||||
BoldTextWithoutBorder = 2,
|
||||
BoldTextWithBorder = 3
|
||||
}
|
||||
|
||||
private void CreateCell(int columnIndex, uint rowIndex, string text, StyleIndex styleIndex)
|
||||
{
|
||||
var columnName = GetExcelColumnName(columnIndex);
|
||||
var cellReference = columnName + rowIndex;
|
||||
var row = _sheetData.Elements<Row>().FirstOrDefault(r => r.RowIndex! == rowIndex);
|
||||
if (row == null)
|
||||
{
|
||||
row = new Row() { RowIndex = rowIndex };
|
||||
_sheetData.Append(row);
|
||||
}
|
||||
|
||||
var newCell = row.Elements<Cell>()
|
||||
.FirstOrDefault(c => c.CellReference != null && c.CellReference.Value == columnName + rowIndex);
|
||||
if (newCell == null)
|
||||
{
|
||||
Cell? refCell = null;
|
||||
foreach (Cell cell in row.Elements<Cell>())
|
||||
{
|
||||
if (cell.CellReference?.Value != null && cell.CellReference.Value.Length == cellReference.Length)
|
||||
{
|
||||
if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
|
||||
{
|
||||
refCell = cell;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
newCell = new Cell() { CellReference = cellReference };
|
||||
row.InsertBefore(newCell, refCell);
|
||||
}
|
||||
|
||||
newCell.CellValue = new CellValue(text);
|
||||
newCell.DataType = CellValues.String;
|
||||
newCell.StyleIndex = (uint)styleIndex;
|
||||
}
|
||||
|
||||
private static string GetExcelColumnName(int columnNumber)
|
||||
{
|
||||
columnNumber += 1;
|
||||
int dividend = columnNumber;
|
||||
string columnName = string.Empty;
|
||||
int modulo;
|
||||
|
||||
while (dividend > 0)
|
||||
{
|
||||
modulo = (dividend - 1) % 26;
|
||||
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
|
||||
dividend = (dividend - modulo) / 26;
|
||||
}
|
||||
|
||||
return columnName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using DocumentFormat.OpenXml;
|
||||
using DocumentFormat.OpenXml.Packaging;
|
||||
using DocumentFormat.OpenXml.Wordprocessing;
|
||||
|
||||
namespace CandyHouseBusinessLogic.OfficePackage;
|
||||
|
||||
internal class OpenXmlWordBuilder : BaseWordBuilder
|
||||
{
|
||||
private readonly Document _document;
|
||||
|
||||
private readonly Body _body;
|
||||
|
||||
public OpenXmlWordBuilder()
|
||||
{
|
||||
_document = new Document();
|
||||
_body = _document.AppendChild(new Body());
|
||||
}
|
||||
|
||||
public override BaseWordBuilder AddHeader(string header)
|
||||
{
|
||||
var paragraph = _body.AppendChild(new Paragraph());
|
||||
var run = paragraph.AppendChild(new Run());
|
||||
run.AppendChild(new RunProperties(new Bold()));
|
||||
run.AppendChild(new Text(header));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override BaseWordBuilder AddParagraph(string text)
|
||||
{
|
||||
var paragraph = _body.AppendChild(new Paragraph());
|
||||
var run = paragraph.AppendChild(new Run());
|
||||
run.AppendChild(new Text(text));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override BaseWordBuilder AddTable(int[] widths, List<string[]> data)
|
||||
{
|
||||
if (widths == null || widths.Length == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(widths));
|
||||
}
|
||||
|
||||
if (data == null || data.Count == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
if (data.Any(x => x.Length != widths.Length))
|
||||
{
|
||||
throw new InvalidOperationException("widths.Length != data.Length");
|
||||
}
|
||||
|
||||
var table = new Table();
|
||||
table.AppendChild(new TableProperties(
|
||||
new TableBorders(
|
||||
new TopBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
|
||||
new BottomBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
|
||||
new LeftBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
|
||||
new RightBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
|
||||
new InsideHorizontalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
|
||||
new InsideVerticalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 }
|
||||
)
|
||||
));
|
||||
|
||||
// Заголовок
|
||||
var tr = new TableRow();
|
||||
for (var j = 0; j < widths.Length; ++j)
|
||||
{
|
||||
tr.Append(new TableCell(
|
||||
new TableCellProperties(new TableCellWidth() { Width = widths[j].ToString() }),
|
||||
new Paragraph(new Run(new RunProperties(new Bold()), new Text(data.First()[j])))));
|
||||
}
|
||||
table.Append(tr);
|
||||
|
||||
// Данные
|
||||
table.Append(data.Skip(1).Select(x =>
|
||||
new TableRow(x.Select(y => new TableCell(new Paragraph(new Run(new Text(y))))))));
|
||||
|
||||
_body.Append(table);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override Stream Build()
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using var wordDocument = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document);
|
||||
var mainPart = wordDocument.AddMainDocumentPart();
|
||||
mainPart.Document = _document;
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface IIngredientAdapter
|
||||
{
|
||||
IngredientOperationResponse GetList(bool includeDeleted);
|
||||
|
||||
IngredientOperationResponse GetManufacturerList(string id, bool includeDeleted);
|
||||
|
||||
IngredientOperationResponse GetHistory(string id);
|
||||
|
||||
IngredientOperationResponse GetElement(string data);
|
||||
|
||||
IngredientOperationResponse RegisterIngredient(IngredientBindingModel productModel);
|
||||
|
||||
IngredientOperationResponse ChangeIngredientInfo(IngredientBindingModel productModel);
|
||||
|
||||
IngredientOperationResponse RemoveIngredient(string id);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface ICustomerAdapter
|
||||
{
|
||||
CustomerOperationResponse GetList();
|
||||
|
||||
CustomerOperationResponse GetElement(string data);
|
||||
|
||||
CustomerOperationResponse RegisterCustomer(CustomerBindingModel customerModel);
|
||||
|
||||
CustomerOperationResponse ChangeCustomerInfo(CustomerBindingModel customerModel);
|
||||
|
||||
CustomerOperationResponse RemoveCustomer(string id);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface IManufacturerAdapter
|
||||
{
|
||||
ManufacturerOperationResponse GetList();
|
||||
|
||||
ManufacturerOperationResponse GetElement(string data);
|
||||
|
||||
ManufacturerOperationResponse RegisterManufacturer(ManufacturerBindingModel manufacturerModel);
|
||||
|
||||
ManufacturerOperationResponse ChangeManufacturerInfo(ManufacturerBindingModel manufacturerModel);
|
||||
|
||||
ManufacturerOperationResponse RemoveManufacturer(string id);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface IPostAdapter
|
||||
{
|
||||
PostOperationResponse GetList();
|
||||
|
||||
PostOperationResponse GetHistory(string id);
|
||||
|
||||
PostOperationResponse GetElement(string data);
|
||||
|
||||
PostOperationResponse RegisterPost(PostBindingModel postModel);
|
||||
|
||||
PostOperationResponse ChangePostInfo(PostBindingModel postModel);
|
||||
|
||||
PostOperationResponse RemovePost(string id);
|
||||
|
||||
PostOperationResponse RestorePost(string id);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
using CandyHouseContracts.DataModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface IProductAdapter
|
||||
{
|
||||
ProductOperationResponse GetList(bool onlyActive = true);
|
||||
|
||||
ProductOperationResponse GetElement(string data);
|
||||
|
||||
ProductOperationResponse RegisterProduct(ProductBindingModel productModel);
|
||||
|
||||
ProductOperationResponse ChangeProductInfo(ProductBindingModel productModel);
|
||||
|
||||
ProductOperationResponse RemoveProduct(string id);
|
||||
|
||||
ProductOperationResponse GetIngredientsList(string id);
|
||||
|
||||
ProductOperationResponse AddIngredient(string productId, IngredientBindingModel ingredient);
|
||||
|
||||
ProductOperationResponse RemoveIngredient(string productId, string ingredientId);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.DataModels;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface IReportAdapter
|
||||
{
|
||||
Task<ReportOperationResponse> GetDataIngredientsWithHistoryAsync(CancellationToken ct); // Переименовал
|
||||
|
||||
Task<ReportOperationResponse> GetDataSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> GetDataSaleByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> CreateDocumentIngredientsWithHistoryAsync(CancellationToken ct); // Переименовал
|
||||
|
||||
Task<ReportOperationResponse> CreateDocumentSalesByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> CreateDocumentSalaryByPeriodAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
// таски для харда
|
||||
Task<ReportOperationResponse> GetDataSupplyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> GetDataIngredientMovementAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> GetDataStorageStockAsync(string storageId, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> CreateDocumentSupplyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> CreateDocumentIngredientMovementAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> CreateDocumentStorageStockAsync(string storageId, CancellationToken ct);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface ISalaryAdapter
|
||||
{
|
||||
SalaryOperationResponse GetListByPeriod(DateTime fromDate, DateTime toDate);
|
||||
|
||||
SalaryOperationResponse GetListByPeriodByWorker(DateTime fromDate, DateTime toDate, string workerId);
|
||||
|
||||
SalaryOperationResponse CalculateSalary(DateTime date);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface ISaleAdapter
|
||||
{
|
||||
SaleOperationResponse GetList(DateTime fromDate, DateTime toDate);
|
||||
SaleOperationResponse GetWorkerList(string id, DateTime fromDate, DateTime toDate);
|
||||
SaleOperationResponse GetCustomerList(string id, DateTime fromDate, DateTime toDate);
|
||||
SaleOperationResponse GetProductList(string id, DateTime fromDate, DateTime toDate);
|
||||
SaleOperationResponse GetElement(string id);
|
||||
SaleOperationResponse MakeSale(SaleBindingModel saleModel);
|
||||
SaleOperationResponse CancelSale(string id);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface IStorageAdapter
|
||||
{
|
||||
StorageOperationResponse GetList();
|
||||
StorageOperationResponse GetElement(string id);
|
||||
StorageOperationResponse RegisterStorage(StorageBindingModel storageModel);
|
||||
StorageOperationResponse UpdateStorage(StorageBindingModel storageModel);
|
||||
StorageOperationResponse AddOrUpdateIngredient(StorageIngredientBindingModel ingredientModel);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface ISupplyAdapter
|
||||
{
|
||||
SupplyOperationResponse GetList();
|
||||
SupplyOperationResponse GetElement(string id);
|
||||
SupplyOperationResponse RegisterSupply(SupplyBindingModel supplyModel);
|
||||
SupplyOperationResponse GetSuppliesByStorage(string storageId);
|
||||
SupplyOperationResponse AddOrUpdateIngredient(SupplyIngredientBindingModel ingredientModel);
|
||||
SupplyOperationResponse UpdateIngredientCount(string supplyId, string ingredientId, int newCount);
|
||||
SupplyOperationResponse RemoveIngredient(string supplyId, string ingredientId);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
using CandyHouseContracts.BindingModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts;
|
||||
|
||||
public interface IWorkerAdapter
|
||||
{
|
||||
WorkerOperationResponse GetList(bool includeDeleted);
|
||||
|
||||
WorkerOperationResponse GetPostList(string id, bool includeDeleted);
|
||||
|
||||
WorkerOperationResponse GetListByBirthDate(DateTime fromDate, DateTime toDate, bool includeDeleted);
|
||||
|
||||
WorkerOperationResponse GetListByEmploymentDate(DateTime fromDate, DateTime toDate, bool includeDeleted);
|
||||
|
||||
WorkerOperationResponse GetElement(string data);
|
||||
|
||||
WorkerOperationResponse RegisterWorker(WorkerBindingModel workerModel);
|
||||
|
||||
WorkerOperationResponse ChangeWorkerInfo(WorkerBindingModel workerModel);
|
||||
|
||||
WorkerOperationResponse RemoveWorker(string id);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class CustomerOperationResponse : OperationResponse
|
||||
{
|
||||
public static CustomerOperationResponse OK(List<CustomerViewModel> data) => OK<CustomerOperationResponse, List<CustomerViewModel>>(data);
|
||||
|
||||
public static CustomerOperationResponse OK(CustomerViewModel data) => OK<CustomerOperationResponse, CustomerViewModel>(data);
|
||||
|
||||
public static CustomerOperationResponse NoContent() => NoContent<CustomerOperationResponse>();
|
||||
|
||||
public static CustomerOperationResponse BadRequest(string message) => BadRequest<CustomerOperationResponse>(message);
|
||||
|
||||
public static CustomerOperationResponse NotFound(string message) => NotFound<CustomerOperationResponse>(message);
|
||||
|
||||
public static CustomerOperationResponse InternalServerError(string message) => InternalServerError<CustomerOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class IngredientOperationResponse : OperationResponse
|
||||
{
|
||||
public static IngredientOperationResponse OK(List<IngredientViewModel> data) => OK<IngredientOperationResponse, List<IngredientViewModel>>(data);
|
||||
|
||||
public static IngredientOperationResponse OK(List<IngredientHistoryViewModel> data) => OK<IngredientOperationResponse, List<IngredientHistoryViewModel>>(data);
|
||||
|
||||
public static IngredientOperationResponse OK(IngredientViewModel data) => OK<IngredientOperationResponse, IngredientViewModel>(data);
|
||||
|
||||
public static IngredientOperationResponse NoContent() => NoContent<IngredientOperationResponse>();
|
||||
|
||||
public static IngredientOperationResponse NotFound(string message) => NotFound<IngredientOperationResponse>(message);
|
||||
|
||||
public static IngredientOperationResponse BadRequest(string message) => BadRequest<IngredientOperationResponse>(message);
|
||||
|
||||
public static IngredientOperationResponse InternalServerError(string message) => InternalServerError<IngredientOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class ManufacturerOperationResponse : OperationResponse
|
||||
{
|
||||
public static ManufacturerOperationResponse OK(List<ManufacturerViewModel> data) => OK<ManufacturerOperationResponse, List<ManufacturerViewModel>>(data);
|
||||
|
||||
public static ManufacturerOperationResponse OK(ManufacturerViewModel data) => OK<ManufacturerOperationResponse, ManufacturerViewModel>(data);
|
||||
|
||||
public static ManufacturerOperationResponse NoContent() => NoContent<ManufacturerOperationResponse>();
|
||||
|
||||
public static ManufacturerOperationResponse NotFound(string message) => NotFound<ManufacturerOperationResponse>(message);
|
||||
|
||||
public static ManufacturerOperationResponse BadRequest(string message) => BadRequest<ManufacturerOperationResponse>(message);
|
||||
|
||||
public static ManufacturerOperationResponse InternalServerError(string message) => InternalServerError<ManufacturerOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class PostOperationResponse : OperationResponse
|
||||
{
|
||||
public static PostOperationResponse OK(List<PostViewModel> data) => OK<PostOperationResponse, List<PostViewModel>>(data);
|
||||
|
||||
public static PostOperationResponse OK(PostViewModel data) => OK<PostOperationResponse, PostViewModel>(data);
|
||||
|
||||
public static PostOperationResponse NoContent() => NoContent<PostOperationResponse>();
|
||||
|
||||
public static PostOperationResponse NotFound(string message) => NotFound<PostOperationResponse>(message);
|
||||
|
||||
public static PostOperationResponse BadRequest(string message) => BadRequest<PostOperationResponse>(message);
|
||||
|
||||
public static PostOperationResponse InternalServerError(string message) => InternalServerError<PostOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class ProductOperationResponse : OperationResponse
|
||||
{
|
||||
public static ProductOperationResponse OK(List<ProductViewModel> data)
|
||||
=> OK<ProductOperationResponse, List<ProductViewModel>>(data);
|
||||
|
||||
public static ProductOperationResponse OK(List<IngredientViewModel> data)
|
||||
=> OK<ProductOperationResponse, List<IngredientViewModel>>(data);
|
||||
|
||||
public static ProductOperationResponse OK(ProductViewModel data)
|
||||
=> OK<ProductOperationResponse, ProductViewModel>(data);
|
||||
|
||||
public static ProductOperationResponse NoContent()
|
||||
=> NoContent<ProductOperationResponse>();
|
||||
|
||||
public static ProductOperationResponse NotFound(string message)
|
||||
=> NotFound<ProductOperationResponse>(message);
|
||||
|
||||
public static ProductOperationResponse BadRequest(string message)
|
||||
=> BadRequest<ProductOperationResponse>(message);
|
||||
|
||||
public static ProductOperationResponse InternalServerError(string message)
|
||||
=> InternalServerError<ProductOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class ReportOperationResponse : OperationResponse
|
||||
{
|
||||
public static ReportOperationResponse OK(List<IngredientWithHistoryViewModel> data) => OK<ReportOperationResponse, List<IngredientWithHistoryViewModel>>(data); // Новый метод
|
||||
|
||||
public static ReportOperationResponse OK(Stream data, string fileName) => OK<ReportOperationResponse, Stream>(data, fileName);
|
||||
|
||||
public static ReportOperationResponse OK(List<SaleViewModel> data) => OK<ReportOperationResponse, List<SaleViewModel>>(data);
|
||||
|
||||
public static ReportOperationResponse OK(List<WorkerSalaryByPeriodViewModel> data) => OK<ReportOperationResponse, List<WorkerSalaryByPeriodViewModel>>(data);
|
||||
|
||||
public static ReportOperationResponse OK(List<SupplyInformationViewModel> data) => OK<ReportOperationResponse, List<SupplyInformationViewModel>>(data);
|
||||
|
||||
public static ReportOperationResponse OK(List<IngredientMoveViewModel> data) => OK<ReportOperationResponse, List<IngredientMoveViewModel>>(data);
|
||||
|
||||
public static ReportOperationResponse OK(List<StorageIngredientViewModel> data) => OK<ReportOperationResponse, List<StorageIngredientViewModel>>(data);
|
||||
|
||||
public static ReportOperationResponse BadRequest(string message) => BadRequest<ReportOperationResponse>(message);
|
||||
|
||||
public static ReportOperationResponse InternalServerError(string message) => InternalServerError<ReportOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class SalaryOperationResponse : OperationResponse
|
||||
{
|
||||
public static SalaryOperationResponse OK(List<SalaryViewModel> data) => OK<SalaryOperationResponse, List<SalaryViewModel>>(data);
|
||||
|
||||
public static SalaryOperationResponse NoContent() => NoContent<SalaryOperationResponse>();
|
||||
|
||||
public static SalaryOperationResponse NotFound(string message) => NotFound<SalaryOperationResponse>(message);
|
||||
|
||||
public static SalaryOperationResponse BadRequest(string message) => BadRequest<SalaryOperationResponse>(message);
|
||||
|
||||
public static SalaryOperationResponse InternalServerError(string message) => InternalServerError<SalaryOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class SaleOperationResponse : OperationResponse
|
||||
{
|
||||
public static SaleOperationResponse OK(List<SaleViewModel> data) =>
|
||||
OK<SaleOperationResponse, List<SaleViewModel>>(data);
|
||||
|
||||
public static SaleOperationResponse OK(SaleViewModel data) =>
|
||||
OK<SaleOperationResponse, SaleViewModel>(data);
|
||||
|
||||
public static SaleOperationResponse NoContent() =>
|
||||
NoContent<SaleOperationResponse>();
|
||||
|
||||
public static SaleOperationResponse NotFound(string message) =>
|
||||
NotFound<SaleOperationResponse>(message);
|
||||
|
||||
public static SaleOperationResponse BadRequest(string message) =>
|
||||
BadRequest<SaleOperationResponse>(message);
|
||||
|
||||
public static SaleOperationResponse InternalServerError(string message) =>
|
||||
InternalServerError<SaleOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class StorageOperationResponse : OperationResponse
|
||||
{
|
||||
public static StorageOperationResponse OK(List<StorageViewModel> data) => OK<StorageOperationResponse, List<StorageViewModel>>(data);
|
||||
public static StorageOperationResponse OK(StorageViewModel data) => OK<StorageOperationResponse, StorageViewModel>(data);
|
||||
public static StorageOperationResponse NoContent() => NoContent<StorageOperationResponse>();
|
||||
public static StorageOperationResponse NotFound(string message) => NotFound<StorageOperationResponse>(message);
|
||||
public static StorageOperationResponse BadRequest(string message) => BadRequest<StorageOperationResponse>(message);
|
||||
public static StorageOperationResponse InternalServerError(string message) => InternalServerError<StorageOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class SupplyOperationResponse : OperationResponse
|
||||
{
|
||||
public static SupplyOperationResponse OK(List<SupplyViewModel> data) => OK<SupplyOperationResponse, List<SupplyViewModel>>(data);
|
||||
public static SupplyOperationResponse OK(SupplyViewModel data) => OK<SupplyOperationResponse, SupplyViewModel>(data);
|
||||
public static SupplyOperationResponse NoContent() => NoContent<SupplyOperationResponse>();
|
||||
public static SupplyOperationResponse NotFound(string message) => NotFound<SupplyOperationResponse>(message);
|
||||
public static SupplyOperationResponse BadRequest(string message) => BadRequest<SupplyOperationResponse>(message);
|
||||
public static SupplyOperationResponse InternalServerError(string message) => InternalServerError<SupplyOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using CandyHouseContracts.Infrastructure;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.AdapterContracts.OperationResponses;
|
||||
|
||||
public class WorkerOperationResponse : OperationResponse
|
||||
{
|
||||
public static WorkerOperationResponse OK(List<WorkerViewModel> data) => OK<WorkerOperationResponse, List<WorkerViewModel>>(data);
|
||||
|
||||
public static WorkerOperationResponse OK(WorkerViewModel data) => OK<WorkerOperationResponse, WorkerViewModel>(data);
|
||||
|
||||
public static WorkerOperationResponse NoContent() => NoContent<WorkerOperationResponse>();
|
||||
|
||||
public static WorkerOperationResponse NotFound(string message) => NotFound<WorkerOperationResponse>(message);
|
||||
|
||||
public static WorkerOperationResponse BadRequest(string message) => BadRequest<WorkerOperationResponse>(message);
|
||||
|
||||
public static WorkerOperationResponse InternalServerError(string message) => InternalServerError<WorkerOperationResponse>(message);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class CustomerBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? FIO { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public double DiscountSize { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using CandyHouseContracts.Enums;
|
||||
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class IngredientBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
public string? IngredientName { get; set; }
|
||||
|
||||
public string? IngredientType { get; set; }
|
||||
|
||||
public string? ManufacturerId { get; set; }
|
||||
|
||||
public double Price { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class ManufacturerBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
public string? ManufacturerName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using CandyHouseContracts.Enums;
|
||||
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class PostBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
public string? PostId => Id;
|
||||
|
||||
public string? PostName { get; set; }
|
||||
|
||||
public string? PostType { get; set; }
|
||||
|
||||
public string? ConfigurationJson { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using CandyHouseContracts.Enums;
|
||||
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class ProductBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
public string? ProductName { get; set; }
|
||||
|
||||
public int? Count { get; set; }
|
||||
|
||||
public double? TotalPrice { get; set; }
|
||||
|
||||
public List<ProductIngredientBindingModel>? Ingredients { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class ProductIngredientBindingModel
|
||||
{
|
||||
public string? ProductId { get; set; }
|
||||
public string? IngredientId { get; set; }
|
||||
public int Count { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using CandyHouseContracts.Enums;
|
||||
using CandyHouseContracts.ViewModels;
|
||||
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class SaleBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
public string? WorkerId { get; set; }
|
||||
|
||||
public string? CustomerId { get; set; }
|
||||
|
||||
public int DiscountType { get; set; }
|
||||
|
||||
public ProductBindingModel? Product { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class StorageBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public required string Address { get; set; }
|
||||
public int Count { get; set; }
|
||||
public List<StorageIngredientBindingModel> Ingredients { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class StorageIngredientBindingModel
|
||||
{
|
||||
public required string StorageId { get; set; }
|
||||
public required string IngredientId { get; set; }
|
||||
public int Count { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class SupplyBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public required string StorageId { get; set; }
|
||||
public DateTime DeliveryDate { get; set; }
|
||||
public int Count { get; set; }
|
||||
public List<SupplyIngredientBindingModel> Ingredients { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class SupplyIngredientBindingModel
|
||||
{
|
||||
public required string SupplyId { get; set; }
|
||||
public required string IngredientId { get; set; }
|
||||
public int Count { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace CandyHouseContracts.BindingModels;
|
||||
|
||||
public class WorkerBindingModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
public string? FIO { get; set; }
|
||||
|
||||
public string? PostId { get; set; }
|
||||
|
||||
public DateTime? BirthDate { get; set; }
|
||||
|
||||
public DateTime? EmploymentDate { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using CandyHouseContracts.DataModels;
|
||||
|
||||
namespace CandyHouseContracts.BusinessLogicsContracts;
|
||||
|
||||
internal interface IIngredientBusinessLogicContract
|
||||
{
|
||||
List<IngredientDataModel> GetAllIngredients(bool onlyActive = true);
|
||||
List<IngredientDataModel> GetAllIngredientsByManufacturer(string manufacturerId, bool onlyActive = true);
|
||||
List<IngredientHistoryDataModel> GetIngredientHistory(string ingredientId);
|
||||
IngredientDataModel GetIngredientByData(string data);
|
||||
void InsertIngredient(IngredientDataModel ingredientDataModel);
|
||||
void UpdateIngredient(IngredientDataModel ingredientDataModel);
|
||||
void DeleteIngredient(string id);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using CandyHouseContracts.DataModels;
|
||||
|
||||
namespace CandyHouseContracts.BusinessLogicsContracts;
|
||||
|
||||
internal interface ICustomerBusinessLogicContract
|
||||
{
|
||||
List<CustomerDataModel> GetAllCustomers();
|
||||
CustomerDataModel GetCustomerByData(string data);
|
||||
void InsertCustomer(CustomerDataModel customerDataModel);
|
||||
void UpdateCustomer(CustomerDataModel customerDataModel);
|
||||
void DeleteCustomer(string id);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using CandyHouseContracts.DataModels;
|
||||
|
||||
namespace CandyHouseContracts.BusinessLogicsContracts;
|
||||
|
||||
internal interface IManufacturerBusinessLogicContract
|
||||
{
|
||||
List<ManufacturerDataModel> GetAllManufacturers();
|
||||
ManufacturerDataModel GetManufacturerByData(string data);
|
||||
void InsertManufacturer(ManufacturerDataModel manufacturerDataModel);
|
||||
void UpdateManufacturer(ManufacturerDataModel manufacturerDataModel);
|
||||
void DeleteManufacturer(string id);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using CandyHouseContracts.DataModels;
|
||||
|
||||
namespace CandyHouseContracts.BusinessLogicsContracts;
|
||||
|
||||
internal interface IPostBusinessLogicContract
|
||||
{
|
||||
List<PostDataModel> GetAllPosts();
|
||||
List<PostDataModel> GetAllDataOfPost(string postId);
|
||||
List<PostDataModel> GetPostHistory(string postId);
|
||||
PostDataModel GetPostByData(string data);
|
||||
void InsertPost(PostDataModel postDataModel);
|
||||
void UpdatePost(PostDataModel postDataModel);
|
||||
void DeletePost(string id);
|
||||
void RestorePost(string id);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using CandyHouseContracts.DataModels;
|
||||
|
||||
namespace CandyHouseContracts.BusinessLogicsContracts;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс бизнес-логики
|
||||
/// </summary>
|
||||
internal interface IProductBusinessLogicContract
|
||||
{
|
||||
List<ProductDataModel> GetAllProducts(bool onlyActive = true);
|
||||
ProductDataModel GetProductById(string id);
|
||||
void InsertProduct(ProductDataModel saleProductDataModel);
|
||||
void UpdateProduct(ProductDataModel saleProductDataModel);
|
||||
void DeleteProduct(string id);
|
||||
List<ProductIngredientDataModel> GetIngredientsByProductId(string saleProductId);
|
||||
void AddIngredientToProduct(ProductIngredientDataModel ProductIngredient);
|
||||
void RemoveIngredientFromProduct(string ingredientId, string productId);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user