21 Commits

Author SHA1 Message Date
46965b2d98 Role-specific buttons enabled, front enhancements 2025-09-14 21:21:20 +04:00
86e7895122 Product fix 2025-09-14 18:56:31 +04:00
39927d8961 Validation on entity fields
Reports, email left
2025-09-14 02:29:41 +04:00
ee51e4d1f6 Purchase CRD done, all entities done
Field verifications, reports, email left
2025-09-14 01:07:07 +04:00
4d4fb598cc privacy policy update 2025-09-01 20:05:03 +04:00
b7a5975e03 Typos + can't edit/delete not your comment 2025-08-31 16:24:31 +04:00
611c1dfadc Comments displaying in ProductSets and deleting with them accordingly 2025-08-31 15:06:04 +04:00
16fb3d3870 Comments View done, shit code in progress 2025-08-29 21:30:40 +04:00
6cc1bf8116 ProductSet fixed 2025-08-29 17:47:00 +04:00
f72a5f0f30 ProductSet Components DO NOT WORK 2025-08-27 03:16:40 +04:00
99c34dd9a7 Authorization+Authentification, main page, minor page changes 2025-08-26 22:43:21 +04:00
a1cee42c10 Report logic 2025-08-26 20:39:48 +04:00
9df854e056 OfficePackage 2025-08-26 20:05:47 +04:00
d57d326eeb Components + Products Views done, Migrations, fixes 2025-08-26 19:29:42 +04:00
97cd727a93 missed errors 2025-08-25 23:49:45 +04:00
bce23f4a5e WebAPI -> WebApp, controllers + adapters 2025-08-25 23:22:16 +04:00
338070c5d8 ProductOrder without controller 2025-08-24 21:03:51 +04:00
7ea4bfad28 WebAPI user adapters & controllers, binding + view models 2025-08-24 19:27:25 +04:00
6781609da3 Storekeeper ViewModels 2025-08-24 17:49:49 +04:00
3178a4d40b Worker view models 2025-08-23 20:15:51 +04:00
769e042dc4 WebAPI project, binding models 2025-08-23 19:26:37 +04:00
256 changed files with 93358 additions and 159 deletions

View File

@@ -40,6 +40,22 @@ namespace YAPBusinessLogic.Implementations
return comment ?? throw new ElementNotFoundException(data);
}
public List<CommentDataModel> GetCommentsByProductSet(string productSetId)
{
_logger.LogInformation("GetCommentsByProductSet method called with productSetId: {productSetId}", productSetId);
if (productSetId.IsEmpty())
{
throw new ArgumentNullException(nameof(productSetId));
}
if (!productSetId.IsGuid())
{
throw new ValidationException("ProductSetId is not a unique identifier");
}
var comments = _commentStorageContract.GetList(productSetId: productSetId);
return comments ?? throw new NullListException();
}
public List<CommentDataModel> GetCommentsByProductSetByPeriod(string productSetId, DateTime fromDate, DateTime toDate)
{
_logger.LogInformation("GetCommentsByProductSetByPeriod method called with productSetId: {productSetId}, fromDate: {fromDate}, toDate: {toDate}", productSetId, fromDate, toDate);

View File

@@ -35,7 +35,7 @@ internal class ProductOrderBusinessLogicContract(IProductOrderStorageContract pr
{
return _productOrderStorageContract.GetElementById(data) ?? throw new ElementNotFoundException(data);
}
return _productOrderStorageContract.GetElementByName(data) ??
return _productOrderStorageContract.GetElementByDealerName(data) ??
throw new ElementNotFoundException(data);
}
@@ -92,12 +92,4 @@ internal class ProductOrderBusinessLogicContract(IProductOrderStorageContract pr
productOrderDataModel.Validate();
_productOrderStorageContract.AddElement(productOrderDataModel);
}
public void UpdateProductOrder(ProductOrderDataModel productOrderDataModel)
{
_logger.LogInformation("Update data: {json}", JsonSerializer.Serialize(productOrderDataModel));
ArgumentNullException.ThrowIfNull(productOrderDataModel);
productOrderDataModel.Validate();
_productOrderStorageContract.UpdElement(productOrderDataModel);
}
}

View File

@@ -0,0 +1,235 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPBusinessLogic.OfficePackage;
using YAPContracts.StorageContracts;
using YAPDatabase.Implementations;
namespace YAPBusinessLogic.Implementations
{
internal class ReportBusinessLogicContract
{
private readonly ProductStorageContract _productStorageContract;
private readonly PurchaseStorageContract _purchaseStorageContract;
private readonly ProductSetStorageContract _productSetStorageContract;
private readonly ComponentStorageContract _componentStorageContract;
private readonly BasePdfBuilder _pdfBuilder;
public ReportBusinessLogicContract(ProductStorageContract productStorageContract, PurchaseStorageContract purchaseStorageContract, ProductSetStorageContract productSetStorageContract, ComponentStorageContract componentStorageContract, BasePdfBuilder pdfBuilder)
{
_productStorageContract = productStorageContract;
_purchaseStorageContract = purchaseStorageContract;
_productSetStorageContract = productSetStorageContract;
_componentStorageContract = componentStorageContract;
_pdfBuilder = pdfBuilder;
}
/// <summary>
/// Список товаров по выбранным сборкам в формате текстового документа или электронной таблицы
/// </summary>
/// <param name="setsIds">Id соборок</param>
/// <param name="format">doc/xls</param>
/// <param name="outputPath">Пусть, куда сохранить файл</param>
public void MakeReportProductsByProductSets(List<string> setsIds, string format, string outputPath)
{
// Получаем продукты по сборкам
var products = _productStorageContract.GetListProductsByProductSet(setsIds);
if (string.Equals(format, "xls", StringComparison.OrdinalIgnoreCase))
{
var excel = new OpenXmlExcelBuilder();
// Заголовок
excel.AddHeader("Изделия - Сборки", 0, 4);
// контент: изделие и под ним сборки
foreach (var prod in products)
{
excel.AddParagraph(prod.Product.Name, 0);
foreach (var wm in prod.Sets)
excel.AddParagraph($" {wm.SetName}", 1);
}
using var st = excel.Build();
File.WriteAllBytes(outputPath, ((MemoryStream)st).ToArray());
}
else if (string.Equals(format, "doc", StringComparison.OrdinalIgnoreCase))
{
var word = new OpenXmlWordBuilder();
// Добавляем заголовок
word.AddHeader("Изделия - Сборки");
// Добавляем контент: название изделия + список сборок
foreach (var prod in products)
{
word.AddParagraph(prod.Product.Name);
foreach (var wm in prod.Sets)
{
word.AddParagraph($" {wm.SetName}");
}
}
// Генерируем и сохраняем
using var stream = word.Build();
// Убедимся, что позиция в потоке в начале
if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin);
File.WriteAllBytes(outputPath, ((MemoryStream)stream).ToArray());
}
else
{
throw new ArgumentException("Поддерживаются только форматы «doc» и «xls»", nameof(format));
}
}
/// <summary>
/// Список сборок по выбранным товарам в формате текстового документа или электронной таблицы
/// </summary>
/// <param name="productIds">Id товаров</param>
/// <param name="format">doc/xls</param>
/// <param name="outputPath">Пусть, куда сохранить файл</param>
public void MakeReportProductSetsByProducts(List<string> productIds, string format, string outputPath)
{
// Получаем продукты по сборкам
var productSets = _productSetStorageContract.GetListProductSetsByProducts(productIds);
if (string.Equals(format, "xls", StringComparison.OrdinalIgnoreCase))
{
var excel = new OpenXmlExcelBuilder();
// Заголовок
excel.AddHeader("Сборки - Изделия", 0, 4);
// контент: Сборки и под ними изделия
foreach (var prod in productSets)
{
excel.AddParagraph(prod.Set.SetName, 0);
foreach (var wm in prod.Products)
excel.AddParagraph($" {wm.Name}", 1);
}
using var st = excel.Build();
File.WriteAllBytes(outputPath, ((MemoryStream)st).ToArray());
}
else if (string.Equals(format, "doc", StringComparison.OrdinalIgnoreCase))
{
var word = new OpenXmlWordBuilder();
// Добавляем заголовок
word.AddHeader("Изделия - Сборки");
// Добавляем контент: название изделия + список сборок
foreach (var prod in productSets)
{
word.AddParagraph(prod.Set.SetName);
foreach (var wm in prod.Products)
{
word.AddParagraph($" {wm.Name}");
}
}
// Генерируем и сохраняем
using var stream = word.Build();
// Убедимся, что позиция в потоке в начале
if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin);
File.WriteAllBytes(outputPath, ((MemoryStream)stream).ToArray());
}
else
{
throw new ArgumentException("Поддерживаются только форматы «doc» и «xls»", nameof(format));
}
}
/// <summary>
/// Отчет по продажам за период с расшифровкой по комментариям и комплектющим
/// </summary>
/// <param name="dateStart">Начало периода</param>
/// <param name="dateEnd">Конец периода</param>
public Stream MakeReportByPurchases(DateTime dateStart, DateTime dateEnd)
{
_pdfBuilder.AddHeader("Отчет по продажам");
var reportData = _purchaseStorageContract.GetDataForReport(dateStart, dateEnd);
_pdfBuilder.AddParagraph($"Период: {dateStart} — {dateEnd}");
foreach (var sale in reportData)
{
_pdfBuilder.AddParagraph($"----------------------------------");
_pdfBuilder.AddParagraph($"Дата продажи: {sale.Purchase.PurchaseDate}");
_pdfBuilder.AddParagraph($"Сумма: {sale.Purchase.TotalPrice}");
_pdfBuilder.AddParagraph($"");
_pdfBuilder.AddParagraph($"Комплектующие");
if (sale.Components is { Count: > 0 })
{
_pdfBuilder.AddTable(
new[] { "Название", "Тип" },
sale.Components.Select(p => new[] { p.Name, p.ComponentType.ToString() }).ToList()
);
}
else
{
_pdfBuilder.AddParagraph("Комплектующих не найдено.");
}
_pdfBuilder.AddParagraph($"Комментарии");
if (sale.Comments is { Count: > 0 })
{
_pdfBuilder.AddTable(
new[] { "Текст", "Дата" },
sale.Comments.Select(p => new[] { p.Text, p.Date.ToString("dd.MM.yyyy") }).ToList()
);
}
else
{
_pdfBuilder.AddParagraph("Комментариев не найдено.");
}
}
return _pdfBuilder.Build();
}
/// <summary>
/// Отчет по комплектующим за период с расшифровкой по покупкам и заказам
/// </summary>
/// <param name="dateStart">Начало периода</param>
/// <param name="dateEnd">Конец периода</param>
public Stream MakeReportByComponents(DateTime dateStart, DateTime dateEnd)
{
_pdfBuilder.AddHeader("Отчет по комплектующим");
var reportData = _componentStorageContract.GetDataForReport(dateStart, dateEnd);
_pdfBuilder.AddParagraph($"Период: {dateStart} — {dateEnd}");
foreach (var comp in reportData)
{
_pdfBuilder.AddParagraph($"----------------------------------");
_pdfBuilder.AddParagraph($"Имя: {comp.Component.Name}");
_pdfBuilder.AddParagraph($"Тип: {comp.Component.ComponentType}");
_pdfBuilder.AddParagraph($"");
_pdfBuilder.AddParagraph($"Покупки");
if (comp.Purchases is { Count: > 0 })
{
_pdfBuilder.AddTable(
new[] { "Дата", "Сумма" },
comp.Purchases.Select(p => new[] { p.PurchaseDate.ToString("MM/dd/yy"), p.TotalPrice.ToString() }).ToList()
);
}
else
{
_pdfBuilder.AddParagraph("Покупок не найдено.");
}
_pdfBuilder.AddParagraph($"Заказы");
if (comp.Orders is { Count: > 0 })
{
_pdfBuilder.AddTable(
new[] { "Дата", "Имя" },
comp.Orders.Select(p => new[] { p.OrderDate.ToString("dd.MM.yyyy"), p.DealerName }).ToList()
);
}
else
{
_pdfBuilder.AddParagraph("Заказов не найдено.");
}
}
return _pdfBuilder.Build();
}
}
}

View File

@@ -0,0 +1,12 @@
namespace YAPBusinessLogic.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();
}

View File

@@ -0,0 +1,14 @@
namespace YAPBusinessLogic.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 BasePdfBuilder AddTable(string[] headers, List<string[]> rows, int[]? columnsWidths = null);
public abstract Stream Build();
}

View File

@@ -0,0 +1,12 @@
namespace YAPBusinessLogic.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();
}

View File

@@ -0,0 +1,124 @@
using System.Text;
using MigraDocCore.DocumentObjectModel;
using MigraDocCore.DocumentObjectModel.Shapes.Charts;
using MigraDocCore.DocumentObjectModel.Tables;
using MigraDocCore.Rendering;
using Document = MigraDocCore.DocumentObjectModel.Document;
namespace YAPBusinessLogic.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 AddTable(string[] headers, List<string[]> rows, int[]? columnsWidths = null)
{
var section = _document.LastSection ?? _document.AddSection();
var table = section.AddTable();
table.Format.Font.Size = 10;
for (int i = 0; i < headers.Length; i++)
{
var column = table.AddColumn(Unit.FromCentimeter(columnsWidths != null && i < columnsWidths.Length ? columnsWidths[i] / 10.0 : 5.0));
column.Format.Alignment = ParagraphAlignment.Left;
}
var headerRow = table.AddRow();
headerRow.Shading.Color = Colors.LightGray;
headerRow.Format.Font.Bold = true;
for (int i = 0; i < headers.Length; i++)
{
headerRow.Cells[i].AddParagraph(headers[i]);
headerRow.Cells[i].Format.Alignment = ParagraphAlignment.Left;
headerRow.Cells[i].VerticalAlignment = VerticalAlignment.Center;
}
foreach (var row in rows)
{
var tableRow = table.AddRow();
for (int i = 0; i < headers.Length; i++)
{
string cellText = i < row.Length ? row[i] : string.Empty;
tableRow.Cells[i].AddParagraph(cellText);
tableRow.Cells[i].Format.Alignment = ParagraphAlignment.Left;
tableRow.Cells[i].VerticalAlignment = VerticalAlignment.Center;
}
}
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.Percent;
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;
}
}

View File

@@ -0,0 +1,303 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
namespace YAPBusinessLogic.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;
}
}

View File

@@ -0,0 +1,94 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace YAPBusinessLogic.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;
}
}

View File

@@ -8,13 +8,19 @@
<ItemGroup>
<InternalsVisibleTo Include="YAPTests" />
<InternalsVisibleTo Include="YAPWebApplication" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.5" />
<PackageReference Include="MigraDocCore.DocumentObjectModel" Version="1.3.67" />
<PackageReference Include="MigraDocCore.Rendering" Version="1.3.67" />
<PackageReference Include="PdfSharpCore" Version="1.3.67" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\YAPContracts\YAPContracts.csproj" />
<ProjectReference Include="..\YAPDatabase\YAPDatabase.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.BindingModels;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPContracts.AdapterContracts
{
public interface ICommentAdapter
{
List<CommentViewModel>? GetList();
CommentViewModel? GetCommentById(string id);
List<CommentViewModel>? GetCommentsByProductSetAndPeriod(string productSetId, DateTime fromDate, DateTime toDate);
List<CommentViewModel>? GetCommentsByUserAndPeriod(string userId, DateTime fromDate, DateTime toDate);
List<CommentViewModel>? GetCommentsByPeriod(DateTime fromDate, DateTime toDate);
void Create(CommentBindingModel comment);
void Update(CommentBindingModel comment);
void Delete(string id);
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.BindingModels;
using YAPContracts.ViewModels;
namespace YAPContracts.AdapterContracts
{
public interface IComponentAdapter
{
List<ComponentViewModel>? GetList(bool onlyActual);
ComponentViewModel? GetComponentByData(string data);
void Insert(ComponentBindingModel component);
void Update(ComponentBindingModel component);
void Delete(string id);
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.BindingModels;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPContracts.AdapterContracts
{
public interface IProductAdapter
{
List<ProductViewModel>? GetList(bool onlyActual = true);
ProductViewModel? GetProductByData(string data);
void Insert(ProductBindingModel product);
void Update(ProductBindingModel product);
void Delete(string id);
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.BindingModels;
using YAPContracts.ViewModels;
namespace YAPContracts.AdapterContracts;
public interface IProductOrderAdapter
{
List<ProductOrderViewModel>? GetList();
List<ProductOrderViewModel>? GetListByPeriod(DateTime fromDate, DateTime toDate);
List<ProductOrderViewModel>? GetListByProductAndPeriod(string productId, DateTime fromDate, DateTime toDate);
ProductOrderViewModel? GetElement(string data);
void RegisterProductOrder(ProductOrderBindingModel productOrderModel);
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.BindingModels;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPContracts.AdapterContracts
{
public interface IProductSetAdapter
{
List<ProductSetViewModel>? GetList();
ProductSetViewModel? GetProductSetByData(string data);
void Insert(ProductSetBindingModel productSet);
void Update(ProductSetBindingModel productSet);
void Delete(string id);
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.BindingModels;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPContracts.AdapterContracts
{
public interface IPurchaseAdapter
{
List<PurchaseViewModel>? GetList();
PurchaseViewModel? GetElement(string id);
List<PurchaseViewModel>? GetByUserAndPeriod(string userId, DateTime fromDate, DateTime toDate);
List<PurchaseViewModel>? GetByPeriod(DateTime fromDate, DateTime toDate);
void Register(PurchaseBindingModel purchase);
void Update(PurchaseBindingModel purchase);
void Delete(string id);
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.BindingModels;
using YAPContracts.ViewModels;
namespace YAPContracts.AdapterContracts
{
public interface IStorekeeperAdapter
{
List<StorekeeperViewModel>? GetList();
StorekeeperViewModel? GetElement(string id);
void Register(StorekeeperBindingModel storekeeper);
void Update(StorekeeperBindingModel storekeeper);
void Delete(string id);
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.BindingModels;
using YAPContracts.ViewModels;
namespace YAPContracts.AdapterContracts
{
public interface IWorkerAdapter
{
List<WorkerViewModel>? GetList();
WorkerViewModel? GetElement(string id);
void Register(WorkerBindingModel worker);
void Update(WorkerBindingModel worker);
void Delete(string id);
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace YAPContracts.BindingModels
{
public class CommentBindingModel
{
public string? Id { get; set; }
[Required(ErrorMessage = "This field is required")]
public string? ProductSetId { get; set; }
public string? UserId { get; set; }
public DateTime Date { get; set; }
[Required(ErrorMessage = "This field is required")]
[StringLength(400, MinimumLength = 4, ErrorMessage = "Atleast 4 symbols")]
public string? Text { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using YAPContracts.Enums;
namespace YAPContracts.BindingModels
{
public class ComponentBindingModel
{
public string? Id { get; set; }
[Required(ErrorMessage = "This field is required")]
[Display(Name = "Component Name")]
public string? Name { get; set; }
[Required(ErrorMessage = "This field is required")]
[Display(Name = "Component Type")]
public string? ComponentType { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.BindingModels
{
public class ComponentInProductSetBindingModel
{
public string? ComponentId { get; private set; }
public string? ProductSetId { get; private set; }
public int Amount { get; private set; }
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace YAPContracts.BindingModels
{
public class ProductBindingModel
{
public string? Id { get; set; }
[Required(ErrorMessage = "This field is required")]
[Display(Name = "Product Name")]
public string? Name { get; set; }
[Required(ErrorMessage = "This field is required")]
[Range(1, double.MaxValue, ErrorMessage = "Price must be greater than 0")]
[Display(Name = "Price")]
public double Price { get; set; }
[Required(ErrorMessage = "This field is required")]
[Display(Name = "Components")]
public List<string> ComponentIds { get; set; } = new List<string>();
public List<ProductOrderBindingModel> ProductOrders { get; set; } = new List<ProductOrderBindingModel>();
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.BindingModels
{
public class ProductInPurchaseBindingModel
{
public string? PurchaseId { get; set; }
public string? ProductId { get; set; }
public int Amount { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.Infrastructure;
namespace YAPContracts.BindingModels
{
public class ProductOrderBindingModel
{
public string? Id { get; set; }
public string? UserId { get; set; }
[FutureDate]
public DateTime OrderDate { get; set; }
[Required(ErrorMessage = "This field is required")]
[StringLength(30, MinimumLength = 2, ErrorMessage = "Atleast 2 symbols")]
public string? DealerName { get; set; }
[Required(ErrorMessage = "This field is required")]
public string? ProductId { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.BindingModels
{
public class ProductSetBindingModel
{
public string? Id { get; set; }
[Required(ErrorMessage = "This field is required")]
[Display(Name = "Set Name")]
public string? SetName { get; set; }
[Required(ErrorMessage = "This field is required")]
[Range(1, double.MaxValue, ErrorMessage = "Total Price must be greater than 0")]
[Display(Name = "Total Price")]
public double? TotalPrice { get; set; }
[Required(ErrorMessage = "This field is required")]
[MinLength(1, ErrorMessage = "Atleast 1 Component is required")]
[Display(Name = "Components")]
public List<string>? ComponentIds { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.BindingModels
{
public class PurchaseBindingModel
{
public string? Id { get; set; }
public string? UserId { get; set; }
public double TotalPrice { get; set; }
public DateTime PurchaseDate { get; set; }
public List<ProductInPurchaseBindingModel>? Products { get; set; }
public List<string>? ProductSetIds { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.BindingModels
{
public class StorekeeperBindingModel
{
public string? Id { get; set; }
public string? Login { get; set; }
public string? Email { get; set; }
public string? Password { get; set; }
public List<string>? ProductOrderIds { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.BindingModels
{
public class WorkerBindingModel
{
public string? Id { get; set; }
public string? Login { get; set; }
public string? Email { get; set; }
public string? Password { get; set; }
public List<string>? PurchaseIds { get; set; }
public List<string>? CommentIds { get; set; }
}
}

View File

@@ -13,6 +13,8 @@ namespace YAPContracts.BusinessLogicContracts
CommentDataModel? GetCommentByData(string data);
List<CommentDataModel> GetCommentsByProductSet(string productSetId);
List<CommentDataModel> GetCommentsByProductSetByPeriod(string productSetId, DateTime fromDate, DateTime toDate);
List<CommentDataModel> GetCommentsByUserByPeriod(string userId, DateTime fromDate, DateTime toDate);

View File

@@ -9,7 +9,7 @@ namespace YAPContracts.BusinessLogicContracts;
public interface IProductBusinessLogicContract
{
List<ProductDataModel> GetAllProducts(bool onlyActual);
List<ProductDataModel> GetAllProducts(bool onlyActual = true);
ProductDataModel GetProductByData(string data);

View File

@@ -13,12 +13,8 @@ public interface IProductOrderBusinessLogicContract
ProductOrderDataModel GetProductOrderByData(string data);
List<ProductOrderDataModel> GetProductOrdersByProductByPeriod(string productId, DateTime fromDate, DateTime toDate, bool onlyActual = true);
List<ProductOrderDataModel> GetProductOrdersByDealerByPeriod(string dealerId, DateTime fromDate, DateTime toDate, bool onlyActual = true);
List<ProductOrderDataModel> GetProductOrdersByDealerByPeriod(string dealerName, DateTime fromDate, DateTime toDate, bool onlyActual = true);
List<ProductOrderDataModel> GetProductOrdersByPeriod(DateTime fromDate, DateTime toDate, bool onlyActual = true);
void InsertProductOrder(ProductOrderDataModel productDataModel);
void UpdateProductOrder(ProductOrderDataModel productDataModel);
}

View File

@@ -9,13 +9,31 @@ using YAPContracts.Infrastructure;
namespace YAPContracts.DataModels
{
public class CommentDataModel(string id, string productSetId, string userId, string text, DateTime date) : IValidation
public class CommentDataModel : IValidation
{
public string Id { get; private set; } = id;
public string ProductSetId { get; private set; } = productSetId;
public string UserId { get; private set; } = userId;
public string Text { get; private set; } = text;
public DateTime Date { get; private set; } = date;
public string Id { get; private set; }
public string ProductSetId { get; private set; }
public string UserId { get; private set; }
public string Text { get; private set; }
public DateTime Date { get; private set; }
public CommentDataModel(string id, string productSetId, string userId, string text, DateTime date)
{
Id = id;
ProductSetId = productSetId;
UserId = userId;
Text = text;
Date = date;
}
public CommentDataModel()
{
Id = Guid.NewGuid().ToString();
ProductSetId = string.Empty;
UserId = string.Empty;
Text = string.Empty;
Date = DateTime.UtcNow;
}
public void Validate()
{

View File

@@ -10,14 +10,31 @@ using YAPContracts.Infrastructure;
namespace YAPContracts.DataModels;
public class ComponentDataModel(string id, string name, ComponentType componentType, bool IsDeleted, List<ComponentInProductDataModel> products, List<ComponentInProductSetDataModel> productSets) : IValidation
public class ComponentDataModel : IValidation
{
public string Id { get; private set; } = id;
public string Name { get; private set; } = name;
public ComponentType ComponentType { get; private set; } = componentType;
public bool IsDeleted { get; private set; } = IsDeleted;
public List<ComponentInProductDataModel> Products = products;
public List<ComponentInProductSetDataModel> ProductSets = productSets;
public string Id { get; private set; }
public string Name { get; private set; }
public ComponentType ComponentType { get; private set; }
public bool IsDeleted { get; private set; }
// public List<ComponentInProductDataModel> Products = products;
// public List<ComponentInProductSetDataModel> ProductSets = productSets;
public ComponentDataModel(string id, string name, ComponentType componentType, bool isDeleted)
{
Id = id;
Name = name;
ComponentType = componentType;
IsDeleted = isDeleted;
}
public ComponentDataModel()
{
Id = Guid.NewGuid().ToString();
Name = string.Empty;
ComponentType = ComponentType.None;
IsDeleted = false;
}
public void Validate()
{
@@ -33,7 +50,7 @@ public class ComponentDataModel(string id, string name, ComponentType componentT
{
throw new ValidationException("Name is empty");
}
if (componentType == ComponentType.None)
if (ComponentType == ComponentType.None)
{
throw new ValidationException("Product type is empty");
}

View File

@@ -9,11 +9,25 @@ using YAPContracts.Infrastructure;
namespace YAPContracts.DataModels
{
public class ComponentInProductSetDataModel(string componentId, string productSetId, int amount) : IValidation
public class ComponentInProductSetDataModel : IValidation
{
public string ComponentId { get; private set; } = componentId;
public string ProductSetId { get; private set; } = productSetId;
public int Amount { get; private set; } = amount;
public string ComponentId { get; private set; }
public string ProductSetId { get; private set; }
public int Price { get; private set; }
public ComponentInProductSetDataModel(string componentId, string productSetId, int price)
{
ComponentId = componentId;
ProductSetId = productSetId;
Price = price;
}
public ComponentInProductSetDataModel()
{
ComponentId = string.Empty;
ProductSetId = string.Empty;
Price = 0;
}
public void Validate()
{
@@ -33,7 +47,7 @@ namespace YAPContracts.DataModels
{
throw new ValidationException("ProductSetId value is not valid");
}
if (Amount <= 0)
if (Price <= 0)
{
throw new ValidationException("Amount is less than or equal to 0");
}

View File

@@ -10,14 +10,36 @@ using YAPContracts.Infrastructure;
namespace YAPContracts.DataModels;
public class ProductDataModel(string id, string name, double price, bool isDeleted, List<ComponentInProductDataModel> componentProducts, List<ProductInPurchaseDataModel> purchases) : IValidation
public class ProductDataModel : IValidation
{
public string Id { get; private set; } = id;
public string Name { get; private set; } = name;
public double Price { get; private set; } = price;
public bool IsDeleted { get; private set; } = isDeleted;
public List<ComponentInProductDataModel> Components { get; private set; } = componentProducts;
public List<ProductInPurchaseDataModel> Purchases { get; private set; } = purchases;
public string Id { get; private set; }
public string Name { get; private set; }
public double Price { get; private set; }
public bool IsDeleted { get; private set; }
public List<ComponentInProductDataModel> Components { get; private set; }
public List<ProductInPurchaseDataModel> Purchases { get; private set; }
public ProductDataModel(string id, string name, double price, bool isDeleted,
List<ComponentInProductDataModel> componentProducts, List<ProductInPurchaseDataModel> purchases)
{
Id = id;
Name = name;
Price = price;
IsDeleted = isDeleted;
Components = componentProducts;
Purchases = purchases;
}
public ProductDataModel()
{
Id = string.Empty;
Name = string.Empty;
Price = 0;
IsDeleted = false;
Components = new List<ComponentInProductDataModel>();
Purchases = new List<ProductInPurchaseDataModel>();
}
public void Validate()
{
if (!Id.IsGuid())

View File

@@ -9,13 +9,35 @@ using YAPContracts.Infrastructure;
namespace YAPContracts.DataModels;
public class ProductOrderDataModel(string id, DateTime orderDate, string dealerName, string productId, string userId) : IValidation
public class ProductOrderDataModel : IValidation
{
public string Id { get; private set; } = id;
public DateTime OrderDate { get; private set;} = orderDate;
public string DealerName { get; private set; } = dealerName;
public string ProductId { get; private set;} = productId;
public string UserId { get; private set; } = userId;
public ProductDataModel? _product;
public string Id { get; private set; }
public DateTime OrderDate { get; private set;}
public string DealerName { get; private set; }
public string ProductId { get; private set;}
public string UserId { get; private set; }
public string ProductName => _product?.Name ?? string.Empty;
public ProductOrderDataModel(string id, DateTime orderDate, string dealerName, string productId, string userId)
{
Id = id;
OrderDate = orderDate;
DealerName = dealerName;
ProductId = productId;
UserId = userId;
}
public ProductOrderDataModel()
{
Id = Guid.NewGuid().ToString();
OrderDate = DateTime.Now;
DealerName = string.Empty;
ProductId = string.Empty;
UserId = string.Empty;
}
public void Validate()
{
if (Id.IsEmpty())

View File

@@ -9,13 +9,37 @@ using YAPContracts.Infrastructure;
namespace YAPContracts.DataModels
{
public class ProductSetDataModel(string id, string setName, double totalPrice, bool isDeleted) : IValidation
public class ProductSetDataModel : IValidation
{
public string Id { get; private set; } = id;
public string SetName { get; private set; } = setName;
public string Id { get; private set; }
public string SetName { get; private set; }
public double TotalPrice { get; private set; } = totalPrice;
public bool IsDeleted { get; private set; } = isDeleted;
public double TotalPrice { get; private set; }
public bool IsDeleted { get; private set; }
public List<ComponentInProductSetDataModel> Components { get; private set; }
public List<CommentDataModel>? Comments { get; set; }
public ProductSetDataModel(string id, string setName, double totalPrice, bool isDeleted, List<ComponentInProductSetDataModel> components, List<CommentDataModel>? comments)
{
Id = id;
SetName = setName;
TotalPrice = totalPrice;
IsDeleted = isDeleted;
Components = components;
Comments = comments;
}
public ProductSetDataModel()
{
Id = Guid.NewGuid().ToString();
SetName = string.Empty;
TotalPrice = 0;
IsDeleted = false;
Components = new List<ComponentInProductSetDataModel>();
Comments = new List<CommentDataModel>();
}
public void Validate()
{

View File

@@ -9,16 +9,12 @@ using YAPContracts.Exceptions;
namespace YAPContracts.DataModels
{
public class ProductSetInPurchaseDataModel(string purchaseId, string productSetId, int amount, double? discount) : IValidation
public class ProductSetInPurchaseDataModel(string purchaseId, string productSetId) : IValidation
{
public string PurchaseId { get; private set; } = purchaseId;
public string ProductSetId { get; private set; } = productSetId;
public int Amount { get; private set; } = amount;
public double? Discount { get; private set; } = discount;
public void Validate()
{
if (PurchaseId.IsEmpty())
@@ -37,14 +33,6 @@ namespace YAPContracts.DataModels
{
throw new ValidationException("ProductSetId value is not valid");
}
if (Amount <= 0)
{
throw new ValidationException("Amount is less than or equal to 0");
}
if (Discount.HasValue && Discount < 0)
{
throw new ValidationException("Discount is less than 0");
}
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.DataModels
{
/// <summary>
/// Сущность для отчета по продуктам по сборкам
/// </summary>
public class ProductWithSetsDataModel
{
public ProductDataModel? Product { get; set; } = null!;
public List<ProductSetDataModel> Sets { get; set; } = new();
}
/// <summary>
/// Сущность для отчета по сборкам по продуктам
/// </summary>
public class SetWithProductsDataModel
{
public List<ProductDataModel> Products { get; set; } = new();
public ProductSetDataModel? Set { get; set; } = null!;
}
/// <summary>
/// Сущность для отчета по продажам с расшифровкой по комплектующим и комментариям
/// </summary>
public class PurchasesReportModel
{
public PurchaseDataModel? Purchase { get; set; } = null;
public List<ComponentDataModel>? Components { get; set; } = new();
public List<CommentDataModel>? Comments { get; set; } = new();
}
/// <summary>
/// Сущность для отчета по комплектующим с расшифровкой по покупкам и заказам на товары за период.
/// </summary>
public class ComponentReportModel
{
public ComponentDataModel? Component { get; set; } = null;
public List<PurchaseDataModel>? Purchases { get; set; } = new();
public List<ProductOrderDataModel>? Orders { get; set; } = new();
}
}

View File

@@ -9,19 +9,39 @@ using YAPContracts.Infrastructure;
namespace YAPContracts.DataModels
{
public class PurchaseDataModel(string id, string userId, double totalPrice, DateTime purchaseDate, List<ProductSetInPurchaseDataModel> productSets, List<ProductInPurchaseDataModel> products) : IValidation
public class PurchaseDataModel : IValidation
{
public string Id { get; private set; } = id;
public string Id { get; private set; }
public string UserId { get; private set; } = userId;
public string UserId { get; private set; }
public double TotalPrice { get; private set; } = totalPrice;
public double TotalPrice { get; private set; }
public DateTime PurchaseDate { get; private set; } = purchaseDate;
public DateTime PurchaseDate { get; private set; }
public List<ProductSetInPurchaseDataModel> ProductSets = productSets;
public List<ProductSetInPurchaseDataModel> ProductSets { get; private set; }
public List<ProductInPurchaseDataModel> Products = products;
public List<ProductInPurchaseDataModel> Products { get; private set; }
public PurchaseDataModel(string id, string userId, double totalPrice, DateTime purchaseDate, List<ProductSetInPurchaseDataModel> productSets, List<ProductInPurchaseDataModel> products)
{
Id = id;
UserId = userId;
TotalPrice = totalPrice;
PurchaseDate = purchaseDate;
ProductSets = productSets;
Products = products;
}
public PurchaseDataModel()
{
Id = string.Empty;
UserId = string.Empty;
TotalPrice = 0;
PurchaseDate = DateTime.UtcNow;
ProductSets = new List<ProductSetInPurchaseDataModel>();
Products = new List<ProductInPurchaseDataModel>();
}
public void Validate()
{
@@ -41,10 +61,6 @@ namespace YAPContracts.DataModels
{
throw new ValidationException("UserId is empty");
}
if (TotalPrice <= 0)
{
throw new ValidationException("TotalPrice is less than or equal to 0");
}
foreach (var productSet in ProductSets)
{
productSet.Validate();

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.Infrastructure
{
public class FutureDateAttribute : ValidationAttribute
{
public FutureDateAttribute()
{
ErrorMessage = "Date must be later than today";
}
public override bool IsValid(object? value)
{
if (value is DateTime date)
{
return date.Date >= DateTime.Today;
}
return false;
}
}
}

View File

@@ -13,6 +13,4 @@ public interface IProductOrderStorageContract
ProductOrderDataModel? GetElementById(string id);
ProductOrderDataModel? GetElementByDealerName(string name);
void AddElement(ProductOrderDataModel ProductOrderDataModel);
void UpdElement(ProductOrderDataModel ProductOrderDataModel);
void DelElement(string id);
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.ViewModels
{
public class CommentViewModel
{
public string Id { get; set; } = default!;
public string Text { get; set; } = default!;
public DateTime CommentDate { get; set; }
public string? AuthorId { get; set; }
public string? ProductSetId { get; set; }
public string? UserLogin { get; set; }
public string? ProductSetName { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.ViewModels
{
public class ComponentInProductSetViewModel
{
public string ComponentId { get; set; } = default!;
public string ComponentName { get; set; } = default!;
public double Price { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.ViewModels
{
public class ComponentInProductViewModel
{
public string ComponentId { get; set; } = default!;
public string ComponentName { get; set; } = default!;
}
}

View File

@@ -0,0 +1,10 @@
using YAPContracts.Enums;
namespace YAPContracts.ViewModels;
public class ComponentViewModel
{
public string Id { get; set; } = default!;
public string Name { get; set; } = default!;
public ComponentType ComponentType { get; set; }
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.ViewModels
{
public class ProductInPurchaseViewModel
{
public string ProductId { get; set; } = default!;
public string PurchaseId { get; set; } = default!;
public int Amount { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.ViewModels
{
public class ProductOrderViewModel
{
public string Id { get; set; } = default!;
public DateTime OrderDate { get; set; }
public string DealerName { get; set; } = default!;
public string ProductName { get; set; } = default!;
public StorekeeperViewModel? Author { get; set; } // вырезать по мере необходимости
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.ViewModels
{
public class ProductSetViewModel
{
public string Id { get; set; } = default!;
public string SetName { get; set; } = default!;
public double TotalPrice { get; set; }
public List<string>? ComponentIds { get; set; }
public List<CommentViewModel>? Comments { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.ViewModels
{
public class ProductViewModel
{
public string Id { get; set; } = default!;
public string Name { get; set; } = default!;
public double Price { get; set; }
public List<string>? ComponentIds { get; set; }
public List<ProductOrderViewModel>? ProductOrders { get; set; }
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YAPContracts.ViewModels
{
public class PurchaseViewModel
{
public string Id { get; set; } = default!;
public string UserId { get; set; } = default!;
public double TotalPrice { get; set; }
public DateTime PurchaseDate { get; set; }
public WorkerViewModel? User { get; set; }
public List<ProductInPurchaseViewModel>? Products { get; set; }
public List<string>? ProductSetIds { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.Enums;
namespace YAPContracts.ViewModels
{
public class StorekeeperViewModel
{
public string Id { get; set; } = default!;
public string Login { get; set; } = default!;
public string Email { get; set; } = default!;
public UserType Role { get; } = UserType.Worker;
public List<ProductOrderViewModel>? ProductOrders { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YAPContracts.Enums;
namespace YAPContracts.ViewModels
{
public class WorkerViewModel
{
public string Id { get; set; } = default!;
public string Login { get; set; } = default!;
public string Email { get; set; } = default!;
public UserType Role { get; } = UserType.Worker;
public List<PurchaseViewModel>? Purchases { get; set; }
public List<CommentViewModel>? Comments { get; set; }
}
}

View File

@@ -6,4 +6,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
</ItemGroup>
</Project>

View File

@@ -23,8 +23,10 @@ namespace YAPDatabase.Implementations
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Comment, CommentDataModel>();
cfg.CreateMap<CommentDataModel, Comment>();
cfg.CreateMap<Comment, CommentDataModel>()
.ForMember(dest => dest.Date, opt => opt.MapFrom(src => src.CommentDate));
cfg.CreateMap<CommentDataModel, Comment>()
.ForMember(dest => dest.CommentDate, opt => opt.MapFrom(src => src.Date));
});
_mapper = new Mapper(config);
}

View File

@@ -27,10 +27,13 @@ internal class ComponentStorageContract : IComponentStorageContract
cfg.CreateMap<ComponentInProductSet, ComponentInProductSetDataModel>();
cfg.CreateMap<ComponentInProductSetDataModel, ComponentInProductSet>();
cfg.CreateMap<ComponentDataModel, Component>()
.ForMember(dest => dest.Products, opt => opt.MapFrom(src => src.Products))
.ForMember(dest => dest.ProductSets, opt => opt.MapFrom(src => src.ProductSets));
cfg.CreateMap<ComponentDataModel, Component>();
cfg.CreateMap<Component, ComponentDataModel>();
cfg.CreateMap<Purchase, PurchaseDataModel>() //Для отчета
.ForMember(dest => dest.Products, opt => opt.MapFrom(src => src.ProductsInPurchase))
.ForMember(dest => dest.ProductSets, opt => opt.MapFrom(src => src.ProductSetsInPurchase));;
cfg.CreateMap<ProductOrder, ProductOrderDataModel>(); //Для отчета
});
_mapper = new Mapper(config);
}
@@ -128,6 +131,33 @@ internal class ComponentStorageContract : IComponentStorageContract
throw new StorageException(ex);
}
}
private Component? GetComponentById(string id) => _dbContext.Components.FirstOrDefault(x => x.Id == id);
public List<ComponentReportModel>? GetDataForReport(DateTime start, DateTime finish)
{
try
{
var data = _dbContext.Components
.Select(c => new ComponentReportModel
{
Component = _mapper.Map<ComponentDataModel>(c),
Purchases = c.Products
.SelectMany(cp => cp.Product.ProductsInPurchace)
.Select(pip => _mapper.Map<PurchaseDataModel>(pip.Purchase))
.ToList(),
Orders = c.Products
.SelectMany(p => p.Product.ProductOrders)
.Select(ord => _mapper.Map<ProductOrderDataModel>(ord))
.ToList()
})
.ToList();
return data;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
}

View File

@@ -23,6 +23,8 @@ internal class ProductOrderStorageContract : IProductOrderStorageContract
{
cfg.CreateMap<ProductOrder, ProductOrderDataModel>();
cfg.CreateMap<ProductOrderDataModel, ProductOrder>();
cfg.CreateMap<Product, ProductDataModel>();
});
_mapper = new Mapper(config);
}
@@ -40,31 +42,16 @@ internal class ProductOrderStorageContract : IProductOrderStorageContract
}
}
public void DelElement(string id)
{
try
{
var productOrder = GetProductOrderById(id) ?? throw new ElementNotFoundException(id);
_dbContext.ProductOrders.Remove(productOrder);
_dbContext.SaveChanges();
}
catch (ElementNotFoundException ex)
{
_dbContext.ChangeTracker.Clear();
throw;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public ProductOrderDataModel? GetElementById(string id)
{
try
{
return _mapper.Map<ProductOrderDataModel>(GetProductOrderById(id));
var order = _mapper.Map<ProductOrderDataModel>(GetProductOrderById(id));
if (!String.IsNullOrEmpty(order.ProductId))
{
order._product = _mapper.Map<ProductDataModel>(_dbContext.Products.FirstOrDefault(x => x.Id == order.ProductId));
}
return order;
}
catch (Exception ex)
{
@@ -90,6 +77,7 @@ internal class ProductOrderStorageContract : IProductOrderStorageContract
{
try
{
List<ProductOrderDataModel> result = new List<ProductOrderDataModel>();
var query = _dbContext.ProductOrders.AsQueryable();
if (fromDate is not null && toDate is not null)
{
@@ -103,27 +91,16 @@ internal class ProductOrderStorageContract : IProductOrderStorageContract
{
query = query.Where(x => x.ProductId == productId);
}
return [.. query.Select(x => _mapper.Map<ProductOrderDataModel>(x))];
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
public void UpdElement(ProductOrderDataModel productOrder)
{
try
{
var newProductOrder = GetProductOrderById(productOrder.Id) ?? throw new ElementNotFoundException(productOrder.Id);
_dbContext.ProductOrders.Update(_mapper.Map(productOrder, newProductOrder));
_dbContext.SaveChanges();
}
catch (ElementNotFoundException)
{
_dbContext.ChangeTracker.Clear();
throw;
result = [.. query.Select(x => _mapper.Map<ProductOrderDataModel>(x))];
foreach (var order in result)
{
if (!String.IsNullOrEmpty(order.ProductId))
{
order._product = _mapper.Map<ProductDataModel>(_dbContext.Products.FirstOrDefault(x => x.Id == order.ProductId));
}
}
return result;
}
catch (Exception ex)
{

View File

@@ -23,12 +23,19 @@ namespace YAPDatabase.Implementations
_dbContext = dbContext;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ComponentInProductSet, ComponentInProductSetDataModel>();
cfg.CreateMap<ComponentInProductSetDataModel, ComponentInProductSet>();
cfg.CreateMap<ComponentInProductSet, ComponentInProductSetDataModel>();
cfg.CreateMap<Comment, CommentDataModel>().ForMember(dest => dest.Date, opt => opt.MapFrom(src => src.CommentDate));
cfg.CreateMap<CommentDataModel, Comment>().ForMember(dest => dest.CommentDate, opt => opt.MapFrom(src => src.Date));
cfg.CreateMap<ProductSetDataModel, ProductSet>()
.ForMember(dest => dest.ComponentsInProductSet, opt => opt.MapFrom(src => src.Components))
.ForMember(dest => dest.IsDeleted, opt => opt.MapFrom(src => false));
cfg.CreateMap<ProductSet, ProductSetDataModel>();
cfg.CreateMap<ProductSet, ProductSetDataModel>()
.ForMember(dest => dest.Components, opt => opt.MapFrom(src => src.ComponentsInProductSet));
cfg.CreateMap<Product, ProductDataModel>();
});
_mapper = new Mapper(config);
}
@@ -63,10 +70,7 @@ namespace YAPDatabase.Implementations
{
throw new ElementDeletedException(productSet.Id);
}
element.IsDeleted = true;
_dbContext.SaveChanges();
var newElement = _mapper.Map<ProductSet>(productSet);
_dbContext.ProductSets.Add(newElement);
_dbContext.ProductSets.Update(_mapper.Map(productSet, element));
_dbContext.SaveChanges();
transaction.Commit();
}
@@ -103,6 +107,14 @@ namespace YAPDatabase.Implementations
{
throw new ElementDeletedException(id);
}
if (element.Comments != null)
{
foreach (var comment in element.Comments)
{
_dbContext.Comments.Remove(comment);
}
}
element.IsDeleted = true;
_dbContext.SaveChanges();
}
@@ -117,7 +129,8 @@ namespace YAPDatabase.Implementations
{
try
{
return _mapper.Map<ProductSetDataModel>(GetProductSetById(id));
var model = GetProductSetById(id);
return _mapper.Map<ProductSetDataModel>(model);
}
catch (Exception ex)
{
@@ -149,7 +162,34 @@ namespace YAPDatabase.Implementations
return [.. query.Select(x => _mapper.Map<ProductSetDataModel>(x))];
}
private ProductSet? GetProductSetById(string id) => _dbContext.ProductSets.FirstOrDefault(x => x.Id == id && x.IsDeleted != true);
public List<SetWithProductsDataModel> GetListProductSetsByProducts(List<string> prodIds)
{
try
{
return _dbContext.ProductSets
.Where(p => p.ComponentsInProductSet
.Any(cp => cp.Component.Products
.Any(cps => prodIds.Contains(cps.ProductId))))
.Select(p => new SetWithProductsDataModel()
{
Set = _mapper.Map<ProductSetDataModel>(p),
Products = p.ComponentsInProductSet
.Select(cp => cp.Component)
.SelectMany(c => c.Products)
.Where(cps => prodIds.Contains(cps.ProductId))
.Select(cps => cps.Product)
.Distinct()
.Select(x => _mapper.Map<ProductDataModel>(x)).ToList()
}).ToList();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
private ProductSet? GetProductSetById(string id) => _dbContext.ProductSets.Include(x => x.ComponentsInProductSet).Include(x => x.Comments).FirstOrDefault(x => x.Id == id && x.IsDeleted != true);
}
}

View File

@@ -31,7 +31,11 @@ internal class ProductStorageContract : IProductStorageContract
.ForMember(dest => dest.ComponentsInProduct, opt => opt.MapFrom(src => src.Components))
.ForMember(dest => dest.ProductsInPurchace, opt => opt.MapFrom(src => src.Purchases));
;
cfg.CreateMap<Product, ProductDataModel>();
cfg.CreateMap<Product, ProductDataModel>()
.ForMember(dest => dest.Components, opt => opt.MapFrom(src => src.ComponentsInProduct))
.ForMember(dest => dest.Purchases, opt => opt.MapFrom(src => src.ProductsInPurchace)); ;
cfg.CreateMap<ProductSet, ProductSetDataModel>();
});
_mapper = new Mapper(config);
}
@@ -39,7 +43,8 @@ internal class ProductStorageContract : IProductStorageContract
{
try
{
_dbContext.Products.Add(_mapper.Map<Product>(product));
var prod = _mapper.Map<Product>(product);
_dbContext.Products.Add(prod);
_dbContext.SaveChanges();
}
catch (Exception ex)
@@ -73,7 +78,8 @@ internal class ProductStorageContract : IProductStorageContract
{
try
{
return _mapper.Map<ProductDataModel>(GetProductById(id));
var prod = GetProductById(id);
return _mapper.Map<ProductDataModel>(prod);
}
catch (Exception ex)
{
@@ -129,5 +135,32 @@ internal class ProductStorageContract : IProductStorageContract
}
}
private Product? GetProductById(string id) => _dbContext.Products.FirstOrDefault(x => x.Id == id);
private Product? GetProductById(string id) => _dbContext.Products.Include(x => x.ComponentsInProduct).FirstOrDefault(x => x.Id == id);
public List<ProductWithSetsDataModel> GetListProductsByProductSet(List<string> setsIds)
{
try
{
return _dbContext.Products
.Where(p => p.ComponentsInProduct
.Any(cp => cp.Component.ProductSets
.Any(cps => setsIds.Contains(cps.ProductSetId))))
.Select(p => new ProductWithSetsDataModel()
{
Product = _mapper.Map<ProductDataModel>(p),
Sets = p.ComponentsInProduct
.Select(cp => cp.Component)
.SelectMany(c => c.ProductSets)
.Where(cps => setsIds.Contains(cps.ProductSetId))
.Select(cps => cps.ProductSet)
.Distinct()
.Select(x => _mapper.Map<ProductSetDataModel>(x)).ToList()
}).ToList();
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
}

View File

@@ -31,9 +31,13 @@ namespace YAPDatabase.Implementations
cfg.CreateMap<ProductSetInPurchaseDataModel, ProductSetInPurchase>();
cfg.CreateMap<PurchaseDataModel, Purchase>()
.ForMember(dest => dest.ProductsInPurchase, opt => opt.MapFrom(src => src.Products))
.ForMember(dest => dest.ProductSetsInPurchase, opt => opt.MapFrom(src => src.ProductSets));
cfg.CreateMap<Purchase, PurchaseDataModel>();
.ForMember(dest => dest.ProductsInPurchase, opt => opt.MapFrom(src => src.Products))
.ForMember(dest => dest.ProductSetsInPurchase, opt => opt.MapFrom(src => src.ProductSets));
cfg.CreateMap<Purchase, PurchaseDataModel>()
.ForMember(dest => dest.Products, opt => opt.MapFrom(src => src.ProductsInPurchase))
.ForMember(dest => dest.ProductSets, opt => opt.MapFrom(src => src.ProductSetsInPurchase));;
cfg.CreateMap<Component, ComponentDataModel>();
});
_mapper = new Mapper(config);
}
@@ -42,7 +46,10 @@ namespace YAPDatabase.Implementations
{
try
{
_dbContext.Purchases.Add(_mapper.Map<Purchase>(purchase));
var entity = _mapper.Map<Purchase>(purchase);
entity.TotalPrice = CalculateTotalPrice(entity);
if (entity.TotalPrice <= 0) throw new ValidationException("Total price must be greater than zero.");
_dbContext.Purchases.Add(entity);
_dbContext.SaveChanges();
}
catch (Exception ex)
@@ -56,8 +63,11 @@ namespace YAPDatabase.Implementations
{
try
{
var newPurchase = GetPurchaseById(purchase.Id) ?? throw new ElementNotFoundException(purchase.Id);
_dbContext.Purchases.Update(_mapper.Map(purchase, newPurchase));
var oldPurchase = GetPurchaseById(purchase.Id) ?? throw new ElementNotFoundException(purchase.Id);
var newEntity = _mapper.Map(purchase, oldPurchase);
newEntity.TotalPrice = CalculateTotalPrice(newEntity);
if (newEntity.TotalPrice <= 0) throw new ValidationException("Total price must be greater than zero.");
_dbContext.Purchases.Update(newEntity);
_dbContext.SaveChanges();
}
catch (ElementNotFoundException ex)
@@ -126,11 +136,89 @@ namespace YAPDatabase.Implementations
throw new StorageException(ex);
}
}
private Purchase? GetPurchaseById(string id)
{
return _dbContext.Purchases.FirstOrDefault(p => p.Id == id);
return _dbContext.Purchases.Include(x => x.ProductsInPurchase).Include(x => x.ProductSetsInPurchase).FirstOrDefault(p => p.Id == id);
}
private double CalculateTotalPrice(Purchase entity)
{
double total = 0;
// Products
if (entity.ProductsInPurchase != null && entity.ProductsInPurchase.Any())
{
var productIds = entity.ProductsInPurchase.Select(p => p.ProductId).ToList();
var productsFromDb = _dbContext.Products
.Where(p => productIds.Contains(p.Id))
.ToDictionary(p => p.Id, p => p.Price);
foreach (var product in entity.ProductsInPurchase)
{
if (productsFromDb.TryGetValue(product.ProductId, out var price))
{
total += price * product.Amount;
}
}
}
// ProductSets
if (entity.ProductSetsInPurchase != null && entity.ProductSetsInPurchase.Any())
{
var setIds = entity.ProductSetsInPurchase.Select(ps => ps.ProductSetId).ToList();
var setsFromDb = _dbContext.ProductSets
.Where(s => setIds.Contains(s.Id))
.ToDictionary(s => s.Id, s => s.TotalPrice);
foreach (var set in entity.ProductSetsInPurchase)
{
if (setsFromDb.TryGetValue(set.ProductSetId, out var price))
{
total += price;
}
}
}
return total;
}
/// <summary>
/// Метод для получения отчета по продажам с расшифровкой
/// по комплектующим и комментариям за период.
/// </summary>
/// <param name="start"></param>
/// <param name="finish"></param>
/// <returns></returns>
public List<PurchasesReportModel>? GetDataForReport(DateTime start, DateTime finish)
{
try
{
var report = _dbContext.Purchases
.Where(p => p.PurchaseDate >= start && p.PurchaseDate <= finish)
.Select(p => new PurchasesReportModel
{
Purchase = _mapper.Map<PurchaseDataModel>(p),
Components = p.ProductSetsInPurchase
.SelectMany(pps => pps.ProductSet.ComponentsInProductSet)
.Select(cps => cps.Component)
.Select(comp => _mapper.Map<ComponentDataModel>(comp))
.ToList(),
Comments = p.ProductSetsInPurchase
.SelectMany(pps => pps.ProductSet.Comments)
.Select(c => new CommentDataModel(c.Id, c.ProductSetId, c.UserId, c.Text, c.CommentDate))
.ToList()
})
.ToList();
return report;
}
catch (Exception ex)
{
_dbContext.ChangeTracker.Clear();
throw new StorageException(ex);
}
}
}
}

View File

@@ -0,0 +1,466 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using YAPDatabase;
#nullable disable
namespace YAPDatabase.Migrations
{
[DbContext(typeof(YAPDbContext))]
[Migration("20250826085148_InitMigration")]
partial class InitMigration
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("YAPDatabase.Models.Comment", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<DateTime>("CommentDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("ProductSetId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ProductSetId");
b.HasIndex("UserId");
b.ToTable("Comments");
});
modelBuilder.Entity("YAPDatabase.Models.Component", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("ComponentType")
.HasColumnType("integer");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false);
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Name", "IsDeleted")
.IsUnique()
.HasFilter("\"IsDeleted\" = FALSE");
b.ToTable("Components");
});
modelBuilder.Entity("YAPDatabase.Models.ComponentInProduct", b =>
{
b.Property<string>("ComponentId")
.HasColumnType("text");
b.Property<string>("ProductId")
.HasColumnType("text");
b.HasKey("ComponentId", "ProductId");
b.HasIndex("ProductId");
b.ToTable("ComponentsInProduct");
});
modelBuilder.Entity("YAPDatabase.Models.ComponentInProductSet", b =>
{
b.Property<string>("ComponentId")
.HasColumnType("text");
b.Property<string>("ProductSetId")
.HasColumnType("text");
b.Property<double>("Price")
.HasColumnType("double precision");
b.HasKey("ComponentId", "ProductSetId");
b.HasIndex("ProductSetId");
b.ToTable("ComponentsInProductSet");
});
modelBuilder.Entity("YAPDatabase.Models.Product", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false);
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<double>("Price")
.HasColumnType("double precision");
b.HasKey("Id");
b.HasIndex("Name", "IsDeleted")
.IsUnique()
.HasFilter("\"IsDeleted\" = FALSE");
b.ToTable("Products");
});
modelBuilder.Entity("YAPDatabase.Models.ProductInPurchase", b =>
{
b.Property<string>("ProductId")
.HasColumnType("text");
b.Property<string>("PurchaseId")
.HasColumnType("text");
b.Property<int>("Amount")
.HasColumnType("integer");
b.HasKey("ProductId", "PurchaseId");
b.HasIndex("PurchaseId");
b.ToTable("ProductsInPurchase");
});
modelBuilder.Entity("YAPDatabase.Models.ProductOrder", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("DealerName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("OrderDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("ProductId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ProductId");
b.HasIndex("UserId");
b.ToTable("ProductOrders");
});
modelBuilder.Entity("YAPDatabase.Models.ProductSet", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false);
b.Property<string>("SetName")
.IsRequired()
.HasColumnType("text");
b.Property<double>("TotalPrice")
.HasColumnType("double precision");
b.HasKey("Id");
b.HasIndex("SetName", "IsDeleted")
.IsUnique()
.HasFilter("\"IsDeleted\" = FALSE");
b.ToTable("ProductSets");
});
modelBuilder.Entity("YAPDatabase.Models.ProductSetInPurchase", b =>
{
b.Property<string>("ProductSetId")
.HasColumnType("text");
b.Property<string>("PurchaseId")
.HasColumnType("text");
b.HasKey("ProductSetId", "PurchaseId");
b.HasIndex("PurchaseId");
b.ToTable("ProductSetsInPurchase");
});
modelBuilder.Entity("YAPDatabase.Models.Purchase", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<DateTime>("PurchaseDate")
.HasColumnType("timestamp with time zone");
b.Property<double>("TotalPrice")
.HasColumnType("double precision");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Purchases");
});
modelBuilder.Entity("YAPDatabase.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Login")
.IsRequired()
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<int>("Role")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("Users");
b.HasDiscriminator<int>("Role");
b.UseTphMappingStrategy();
});
modelBuilder.Entity("YAPDatabase.Models.Storekeeper", b =>
{
b.HasBaseType("YAPDatabase.Models.User");
b.HasDiscriminator().HasValue(2);
});
modelBuilder.Entity("YAPDatabase.Models.Worker", b =>
{
b.HasBaseType("YAPDatabase.Models.User");
b.HasDiscriminator().HasValue(1);
});
modelBuilder.Entity("YAPDatabase.Models.Comment", b =>
{
b.HasOne("YAPDatabase.Models.ProductSet", "ProductSet")
.WithMany("Comments")
.HasForeignKey("ProductSetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Worker", "User")
.WithMany("Comments")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ProductSet");
b.Navigation("User");
});
modelBuilder.Entity("YAPDatabase.Models.ComponentInProduct", b =>
{
b.HasOne("YAPDatabase.Models.Component", "Component")
.WithMany("Products")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Product", "Product")
.WithMany("ComponentsInProduct")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("Product");
});
modelBuilder.Entity("YAPDatabase.Models.ComponentInProductSet", b =>
{
b.HasOne("YAPDatabase.Models.Component", "Component")
.WithMany("ProductSets")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.ProductSet", "ProductSet")
.WithMany("ComponentsInProductSet")
.HasForeignKey("ProductSetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("ProductSet");
});
modelBuilder.Entity("YAPDatabase.Models.ProductInPurchase", b =>
{
b.HasOne("YAPDatabase.Models.Product", "Product")
.WithMany("ProductsInPurchace")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Purchase", "Purchase")
.WithMany("ProductsInPurchase")
.HasForeignKey("PurchaseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
b.Navigation("Purchase");
});
modelBuilder.Entity("YAPDatabase.Models.ProductOrder", b =>
{
b.HasOne("YAPDatabase.Models.Product", "Product")
.WithMany("ProductOrders")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Storekeeper", "Storekeeper")
.WithMany("ProductOrders")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
b.Navigation("Storekeeper");
});
modelBuilder.Entity("YAPDatabase.Models.ProductSetInPurchase", b =>
{
b.HasOne("YAPDatabase.Models.ProductSet", "ProductSet")
.WithMany("ProductSetsInPurchase")
.HasForeignKey("ProductSetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Purchase", "Purchase")
.WithMany("ProductSetsInPurchase")
.HasForeignKey("PurchaseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ProductSet");
b.Navigation("Purchase");
});
modelBuilder.Entity("YAPDatabase.Models.Purchase", b =>
{
b.HasOne("YAPDatabase.Models.Worker", "User")
.WithMany("Purchases")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("YAPDatabase.Models.Component", b =>
{
b.Navigation("ProductSets");
b.Navigation("Products");
});
modelBuilder.Entity("YAPDatabase.Models.Product", b =>
{
b.Navigation("ComponentsInProduct");
b.Navigation("ProductOrders");
b.Navigation("ProductsInPurchace");
});
modelBuilder.Entity("YAPDatabase.Models.ProductSet", b =>
{
b.Navigation("Comments");
b.Navigation("ComponentsInProductSet");
b.Navigation("ProductSetsInPurchase");
});
modelBuilder.Entity("YAPDatabase.Models.Purchase", b =>
{
b.Navigation("ProductSetsInPurchase");
b.Navigation("ProductsInPurchase");
});
modelBuilder.Entity("YAPDatabase.Models.Storekeeper", b =>
{
b.Navigation("ProductOrders");
});
modelBuilder.Entity("YAPDatabase.Models.Worker", b =>
{
b.Navigation("Comments");
b.Navigation("Purchases");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,347 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace YAPDatabase.Migrations
{
/// <inheritdoc />
public partial class InitMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Components",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
ComponentType = table.Column<int>(type: "integer", nullable: false),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Components", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Products",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Price = table.Column<double>(type: "double precision", nullable: false),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Products", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ProductSets",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
SetName = table.Column<string>(type: "text", nullable: false),
TotalPrice = table.Column<double>(type: "double precision", nullable: false),
IsDeleted = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProductSets", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Login = table.Column<string>(type: "text", nullable: false),
Email = table.Column<string>(type: "text", nullable: false),
PasswordHash = table.Column<string>(type: "text", nullable: false),
Role = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ComponentsInProduct",
columns: table => new
{
ComponentId = table.Column<string>(type: "text", nullable: false),
ProductId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ComponentsInProduct", x => new { x.ComponentId, x.ProductId });
table.ForeignKey(
name: "FK_ComponentsInProduct_Components_ComponentId",
column: x => x.ComponentId,
principalTable: "Components",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ComponentsInProduct_Products_ProductId",
column: x => x.ProductId,
principalTable: "Products",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ComponentsInProductSet",
columns: table => new
{
ComponentId = table.Column<string>(type: "text", nullable: false),
ProductSetId = table.Column<string>(type: "text", nullable: false),
Price = table.Column<double>(type: "double precision", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ComponentsInProductSet", x => new { x.ComponentId, x.ProductSetId });
table.ForeignKey(
name: "FK_ComponentsInProductSet_Components_ComponentId",
column: x => x.ComponentId,
principalTable: "Components",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ComponentsInProductSet_ProductSets_ProductSetId",
column: x => x.ProductSetId,
principalTable: "ProductSets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Comments",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
ProductSetId = table.Column<string>(type: "text", nullable: false),
UserId = table.Column<string>(type: "text", nullable: false),
Text = table.Column<string>(type: "text", nullable: false),
CommentDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Comments", x => x.Id);
table.ForeignKey(
name: "FK_Comments_ProductSets_ProductSetId",
column: x => x.ProductSetId,
principalTable: "ProductSets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Comments_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ProductOrders",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
UserId = table.Column<string>(type: "text", nullable: false),
OrderDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DealerName = table.Column<string>(type: "text", nullable: false),
ProductId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProductOrders", x => x.Id);
table.ForeignKey(
name: "FK_ProductOrders_Products_ProductId",
column: x => x.ProductId,
principalTable: "Products",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProductOrders_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Purchases",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
UserId = table.Column<string>(type: "text", nullable: false),
TotalPrice = table.Column<double>(type: "double precision", nullable: false),
PurchaseDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Purchases", x => x.Id);
table.ForeignKey(
name: "FK_Purchases_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ProductSetsInPurchase",
columns: table => new
{
ProductSetId = table.Column<string>(type: "text", nullable: false),
PurchaseId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProductSetsInPurchase", x => new { x.ProductSetId, x.PurchaseId });
table.ForeignKey(
name: "FK_ProductSetsInPurchase_ProductSets_ProductSetId",
column: x => x.ProductSetId,
principalTable: "ProductSets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProductSetsInPurchase_Purchases_PurchaseId",
column: x => x.PurchaseId,
principalTable: "Purchases",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ProductsInPurchase",
columns: table => new
{
PurchaseId = table.Column<string>(type: "text", nullable: false),
ProductId = table.Column<string>(type: "text", nullable: false),
Amount = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProductsInPurchase", x => new { x.ProductId, x.PurchaseId });
table.ForeignKey(
name: "FK_ProductsInPurchase_Products_ProductId",
column: x => x.ProductId,
principalTable: "Products",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProductsInPurchase_Purchases_PurchaseId",
column: x => x.PurchaseId,
principalTable: "Purchases",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Comments_ProductSetId",
table: "Comments",
column: "ProductSetId");
migrationBuilder.CreateIndex(
name: "IX_Comments_UserId",
table: "Comments",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Components_Name_IsDeleted",
table: "Components",
columns: new[] { "Name", "IsDeleted" },
unique: true,
filter: "\"IsDeleted\" = FALSE");
migrationBuilder.CreateIndex(
name: "IX_ComponentsInProduct_ProductId",
table: "ComponentsInProduct",
column: "ProductId");
migrationBuilder.CreateIndex(
name: "IX_ComponentsInProductSet_ProductSetId",
table: "ComponentsInProductSet",
column: "ProductSetId");
migrationBuilder.CreateIndex(
name: "IX_ProductOrders_ProductId",
table: "ProductOrders",
column: "ProductId");
migrationBuilder.CreateIndex(
name: "IX_ProductOrders_UserId",
table: "ProductOrders",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Products_Name_IsDeleted",
table: "Products",
columns: new[] { "Name", "IsDeleted" },
unique: true,
filter: "\"IsDeleted\" = FALSE");
migrationBuilder.CreateIndex(
name: "IX_ProductSets_SetName_IsDeleted",
table: "ProductSets",
columns: new[] { "SetName", "IsDeleted" },
unique: true,
filter: "\"IsDeleted\" = FALSE");
migrationBuilder.CreateIndex(
name: "IX_ProductSetsInPurchase_PurchaseId",
table: "ProductSetsInPurchase",
column: "PurchaseId");
migrationBuilder.CreateIndex(
name: "IX_ProductsInPurchase_PurchaseId",
table: "ProductsInPurchase",
column: "PurchaseId");
migrationBuilder.CreateIndex(
name: "IX_Purchases_UserId",
table: "Purchases",
column: "UserId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Comments");
migrationBuilder.DropTable(
name: "ComponentsInProduct");
migrationBuilder.DropTable(
name: "ComponentsInProductSet");
migrationBuilder.DropTable(
name: "ProductOrders");
migrationBuilder.DropTable(
name: "ProductSetsInPurchase");
migrationBuilder.DropTable(
name: "ProductsInPurchase");
migrationBuilder.DropTable(
name: "Components");
migrationBuilder.DropTable(
name: "ProductSets");
migrationBuilder.DropTable(
name: "Products");
migrationBuilder.DropTable(
name: "Purchases");
migrationBuilder.DropTable(
name: "Users");
}
}
}

View File

@@ -0,0 +1,463 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using YAPDatabase;
#nullable disable
namespace YAPDatabase.Migrations
{
[DbContext(typeof(YAPDbContext))]
partial class YAPDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("YAPDatabase.Models.Comment", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<DateTime>("CommentDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("ProductSetId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ProductSetId");
b.HasIndex("UserId");
b.ToTable("Comments", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.Component", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("ComponentType")
.HasColumnType("integer");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false);
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("Name", "IsDeleted")
.IsUnique()
.HasFilter("\"IsDeleted\" = FALSE");
b.ToTable("Components", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.ComponentInProduct", b =>
{
b.Property<string>("ComponentId")
.HasColumnType("text");
b.Property<string>("ProductId")
.HasColumnType("text");
b.HasKey("ComponentId", "ProductId");
b.HasIndex("ProductId");
b.ToTable("ComponentsInProduct", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.ComponentInProductSet", b =>
{
b.Property<string>("ComponentId")
.HasColumnType("text");
b.Property<string>("ProductSetId")
.HasColumnType("text");
b.Property<double>("Price")
.HasColumnType("double precision");
b.HasKey("ComponentId", "ProductSetId");
b.HasIndex("ProductSetId");
b.ToTable("ComponentsInProductSet", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.Product", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false);
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<double>("Price")
.HasColumnType("double precision");
b.HasKey("Id");
b.HasIndex("Name", "IsDeleted")
.IsUnique()
.HasFilter("\"IsDeleted\" = FALSE");
b.ToTable("Products", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.ProductInPurchase", b =>
{
b.Property<string>("ProductId")
.HasColumnType("text");
b.Property<string>("PurchaseId")
.HasColumnType("text");
b.Property<int>("Amount")
.HasColumnType("integer");
b.HasKey("ProductId", "PurchaseId");
b.HasIndex("PurchaseId");
b.ToTable("ProductsInPurchase", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.ProductOrder", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("DealerName")
.IsRequired()
.HasColumnType("text");
b.Property<DateTime>("OrderDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("ProductId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("ProductId");
b.HasIndex("UserId");
b.ToTable("ProductOrders", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.ProductSet", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(false);
b.Property<string>("SetName")
.IsRequired()
.HasColumnType("text");
b.Property<double>("TotalPrice")
.HasColumnType("double precision");
b.HasKey("Id");
b.HasIndex("SetName", "IsDeleted")
.IsUnique()
.HasFilter("\"IsDeleted\" = FALSE");
b.ToTable("ProductSets", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.ProductSetInPurchase", b =>
{
b.Property<string>("ProductSetId")
.HasColumnType("text");
b.Property<string>("PurchaseId")
.HasColumnType("text");
b.HasKey("ProductSetId", "PurchaseId");
b.HasIndex("PurchaseId");
b.ToTable("ProductSetsInPurchase", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.Purchase", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<DateTime>("PurchaseDate")
.HasColumnType("timestamp with time zone");
b.Property<double>("TotalPrice")
.HasColumnType("double precision");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Purchases", (string)null);
});
modelBuilder.Entity("YAPDatabase.Models.User", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Login")
.IsRequired()
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<int>("Role")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("Users", (string)null);
b.HasDiscriminator<int>("Role");
b.UseTphMappingStrategy();
});
modelBuilder.Entity("YAPDatabase.Models.Storekeeper", b =>
{
b.HasBaseType("YAPDatabase.Models.User");
b.HasDiscriminator().HasValue(2);
});
modelBuilder.Entity("YAPDatabase.Models.Worker", b =>
{
b.HasBaseType("YAPDatabase.Models.User");
b.HasDiscriminator().HasValue(1);
});
modelBuilder.Entity("YAPDatabase.Models.Comment", b =>
{
b.HasOne("YAPDatabase.Models.ProductSet", "ProductSet")
.WithMany("Comments")
.HasForeignKey("ProductSetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Worker", "User")
.WithMany("Comments")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ProductSet");
b.Navigation("User");
});
modelBuilder.Entity("YAPDatabase.Models.ComponentInProduct", b =>
{
b.HasOne("YAPDatabase.Models.Component", "Component")
.WithMany("Products")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Product", "Product")
.WithMany("ComponentsInProduct")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("Product");
});
modelBuilder.Entity("YAPDatabase.Models.ComponentInProductSet", b =>
{
b.HasOne("YAPDatabase.Models.Component", "Component")
.WithMany("ProductSets")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.ProductSet", "ProductSet")
.WithMany("ComponentsInProductSet")
.HasForeignKey("ProductSetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("ProductSet");
});
modelBuilder.Entity("YAPDatabase.Models.ProductInPurchase", b =>
{
b.HasOne("YAPDatabase.Models.Product", "Product")
.WithMany("ProductsInPurchace")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Purchase", "Purchase")
.WithMany("ProductsInPurchase")
.HasForeignKey("PurchaseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
b.Navigation("Purchase");
});
modelBuilder.Entity("YAPDatabase.Models.ProductOrder", b =>
{
b.HasOne("YAPDatabase.Models.Product", "Product")
.WithMany("ProductOrders")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Storekeeper", "Storekeeper")
.WithMany("ProductOrders")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
b.Navigation("Storekeeper");
});
modelBuilder.Entity("YAPDatabase.Models.ProductSetInPurchase", b =>
{
b.HasOne("YAPDatabase.Models.ProductSet", "ProductSet")
.WithMany("ProductSetsInPurchase")
.HasForeignKey("ProductSetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("YAPDatabase.Models.Purchase", "Purchase")
.WithMany("ProductSetsInPurchase")
.HasForeignKey("PurchaseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ProductSet");
b.Navigation("Purchase");
});
modelBuilder.Entity("YAPDatabase.Models.Purchase", b =>
{
b.HasOne("YAPDatabase.Models.Worker", "User")
.WithMany("Purchases")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("YAPDatabase.Models.Component", b =>
{
b.Navigation("ProductSets");
b.Navigation("Products");
});
modelBuilder.Entity("YAPDatabase.Models.Product", b =>
{
b.Navigation("ComponentsInProduct");
b.Navigation("ProductOrders");
b.Navigation("ProductsInPurchace");
});
modelBuilder.Entity("YAPDatabase.Models.ProductSet", b =>
{
b.Navigation("Comments");
b.Navigation("ComponentsInProductSet");
b.Navigation("ProductSetsInPurchase");
});
modelBuilder.Entity("YAPDatabase.Models.Purchase", b =>
{
b.Navigation("ProductSetsInPurchase");
b.Navigation("ProductsInPurchase");
});
modelBuilder.Entity("YAPDatabase.Models.Storekeeper", b =>
{
b.Navigation("ProductOrders");
});
modelBuilder.Entity("YAPDatabase.Models.Worker", b =>
{
b.Navigation("Comments");
b.Navigation("Purchases");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

View File

@@ -11,6 +11,6 @@ internal class ProductInPurchase
public required string PurchaseId { get; set; }
public required string ProductId { get; set; }
public int Amount { get; set; }
public Component? Component { get; set; }
public ProductSet? ProductSet { get; set; }
public Purchase? Purchase { get; set; }
public Product? Product { get; set; }
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -15,6 +16,5 @@ internal class ProductOrder
public required string ProductId { get; set; }
public Product? Product { get; set; }
public Storekeeper? Storekeeper { get; set; }
}

View File

@@ -16,7 +16,6 @@ namespace YAPDatabase.Models
public double TotalPrice { get; set; }
public DateTime PurchaseDate { get; set; }
public Worker? User { get; set; }
[ForeignKey("PurchaseId")]

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -10,7 +11,7 @@ namespace YAPDatabase.Models
internal class Storekeeper : User
{
public Storekeeper() => Role = UserType.Storekeeper;
[ForeignKey("UserId")]
public List<ProductOrder>? ProductOrders { get; set; }
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Linq;
using System.Text;
@@ -11,8 +12,9 @@ namespace YAPDatabase.Models
internal class Worker : User
{
public Worker() => Role = UserType.Worker;
[ForeignKey("UserId")]
public List<Purchase>? Purchases { get; set; }
[ForeignKey("UserId")]
public List<Comment>? Comments { get; set; }
}
}

View File

@@ -18,6 +18,8 @@
<ItemGroup>
<InternalsVisibleTo Include="YAPTests" />
<InternalsVisibleTo Include="YAPBusinessLogic" />
<InternalsVisibleTo Include="YAPWebApplication" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
</ItemGroup>

View File

@@ -75,21 +75,27 @@ namespace YAPDatabase
.HasFilter("\"IsDeleted\" = FALSE"); // unique index for non-deleted components
// User relationships
// Worker can create Purchases and Comments here
modelBuilder.Entity<Purchase>()
.HasOne<Worker>() // only Worker can create Purchase
.HasOne<Worker>(c => c.User) // only Worker can create Purchase
.WithMany(w => w.Purchases)
.HasForeignKey(p => p.UserId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Comment>()
.HasOne<Worker>()
.HasOne<Worker>(c => c.User)
.WithMany(w => w.Comments)
.HasForeignKey(c => c.UserId)
.OnDelete(DeleteBehavior.Cascade);
// TODO: Storekeeper can manage Components and ProductOrders here
modelBuilder.Entity<Comment>().HasOne<ProductSet>(c => c.ProductSet)
.WithMany(ps => ps.Comments)
.HasForeignKey(c => c.ProductSetId)
.OnDelete(DeleteBehavior.Cascade); // deleting a ProductSet will delete its Comments
// Storekeeper can manage Components and ProductOrders here
modelBuilder.Entity<ProductOrder>()
.HasOne<Storekeeper>() // only Storekeeper can create ProductOrder
.HasOne<Storekeeper>(c => c.Storekeeper) // only Storekeeper can create ProductOrder
.WithMany(w => w.ProductOrders)
.HasForeignKey(p => p.UserId)
.OnDelete(DeleteBehavior.Cascade);

View File

@@ -13,8 +13,6 @@ namespace YAPTests.Infrastructure
{
internal static class YAPDbContextExtentions
{
// TODO: допилить этот кал, добавление матрешкой Purchase -> ... -> Component
// ---------- USERS ----------
public static Worker InsertWorker(this YAPDbContext db, string? id = null, string login = "worker", string email = "worker@test.com")
{

View File

@@ -0,0 +1,146 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPWebAPI.Adapters
{
public class CommentAdapter : ICommentAdapter
{
private readonly ICommentBusinessLogicContract _commentBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public CommentAdapter(ICommentBusinessLogicContract commentBL, ILogger<CommentAdapter> logger)
{
_commentBL = commentBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<CommentBindingModel, CommentDataModel>();
cfg.CreateMap<CommentDataModel, CommentViewModel>();
cfg.CreateMap<CommentViewModel, CommentDataModel>();
});
_mapper = new Mapper(config);
}
public List<CommentViewModel>? GetList()
{
try
{
return _commentBL.GetAllComments()
.Select(x => _mapper.Map<CommentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetList");
return null;
}
}
public CommentViewModel? GetCommentById(string id)
{
try
{
var data = _commentBL.GetCommentByData(id);
return data != null ? _mapper.Map<CommentViewModel>(data) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetCommentById");
return null;
}
}
public List<CommentViewModel>? GetCommentsByProductSetAndPeriod(string productSetId, DateTime fromDate, DateTime toDate)
{
try
{
return _commentBL.GetCommentsByProductSetByPeriod(productSetId, fromDate, toDate)
.Select(x => _mapper.Map<CommentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetCommentsByProductSetAndPeriod");
return null;
}
}
public List<CommentViewModel>? GetCommentsByUserAndPeriod(string userId, DateTime fromDate, DateTime toDate)
{
try
{
return _commentBL.GetCommentsByUserByPeriod(userId, fromDate, toDate)
.Select(x => _mapper.Map<CommentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetCommentsByUserAndPeriod");
return null;
}
}
public List<CommentViewModel>? GetCommentsByPeriod(DateTime fromDate, DateTime toDate)
{
try
{
return _commentBL.GetCommentsByPeriod(fromDate, toDate)
.Select(x => _mapper.Map<CommentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetCommentsByPeriod");
return null;
}
}
public void Create(CommentBindingModel comment)
{
try
{
var data = _mapper.Map<CommentDataModel>(comment);
_commentBL.InsertComment(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.Create");
throw;
}
}
public void Update(CommentBindingModel comment)
{
try
{
var data = _mapper.Map<CommentDataModel>(comment);
_commentBL.UpdateComment(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.Update");
throw;
}
}
public void Delete(string id)
{
try
{
_commentBL.DeleteComment(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.Delete");
throw;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPWebAPI.Adapters
{
public class ComponentAdapter : IComponentAdapter
{
private readonly IComponentBusinessLogicContract _productBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public ComponentAdapter(IComponentBusinessLogicContract productBL, ILogger<ComponentAdapter> logger)
{
_productBL = productBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ComponentBindingModel, ComponentDataModel>();
cfg.CreateMap<ComponentDataModel, ComponentViewModel>();
cfg.CreateMap<ComponentViewModel, ComponentDataModel>();
});
_mapper = new Mapper(config);
}
public List<ComponentViewModel>? GetList(bool onlyActual = true)
{
try
{
return _productBL.GetAllComponents(onlyActual)
.Select(x => _mapper.Map<ComponentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.GetList");
return null;
}
}
public ComponentViewModel? GetComponentByData(string data)
{
try
{
var model = _productBL.GetComponentByData(data);
return model != null ? _mapper.Map<ComponentViewModel>(model) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.GetComponentByData");
return null;
}
}
public void Insert(ComponentBindingModel product)
{
try
{
var data = _mapper.Map<ComponentDataModel>(product);
_productBL.InsertComponent(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.Insert");
throw;
}
}
public void Update(ComponentBindingModel product)
{
try
{
var data = _mapper.Map<ComponentDataModel>(product);
_productBL.UpdateComponent(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.Update");
throw;
}
}
public void Delete(string id)
{
try
{
_productBL.DeleteComponent(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.Delete");
throw;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPWebAPI.Adapters
{
public class ProductAdapter : IProductAdapter
{
private readonly IProductBusinessLogicContract _productBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public ProductAdapter(IProductBusinessLogicContract productBL, ILogger<ProductAdapter> logger)
{
_productBL = productBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ProductBindingModel, ProductDataModel>();
cfg.CreateMap<ProductDataModel, ProductViewModel>();
cfg.CreateMap<ProductViewModel, ProductDataModel>();
});
_mapper = new Mapper(config);
}
public List<ProductViewModel>? GetList(bool onlyActual = true)
{
try
{
return _productBL.GetAllProducts(onlyActual)
.Select(x => _mapper.Map<ProductViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.GetList");
return null;
}
}
public ProductViewModel? GetProductByData(string data)
{
try
{
var model = _productBL.GetProductByData(data);
return model != null ? _mapper.Map<ProductViewModel>(model) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.GetProductByData");
return null;
}
}
public void Insert(ProductBindingModel product)
{
try
{
var data = _mapper.Map<ProductDataModel>(product);
_productBL.InsertProduct(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.Insert");
throw;
}
}
public void Update(ProductBindingModel product)
{
try
{
var data = _mapper.Map<ProductDataModel>(product);
_productBL.UpdateProduct(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.Update");
throw;
}
}
public void Delete(string id)
{
try
{
_productBL.DeleteProduct(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.Delete");
throw;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.Exceptions;
using YAPContracts.ViewModels;
using YAPDatabase.Models;
namespace YAPWebAPI.Adapters;
public class ProductOrderAdapter : IProductOrderAdapter
{
private readonly IProductOrderBusinessLogicContract _productOrderBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public ProductOrderAdapter(IProductOrderBusinessLogicContract productOrderBL, ILogger logger)
{
_productOrderBL = productOrderBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ProductOrderBindingModel, ProductOrderDataModel>();
cfg.CreateMap<ProductOrderDataModel, ProductOrderViewModel>();
cfg.CreateMap<ProductOrderViewModel, ProductOrderDataModel>();
});
_mapper = new Mapper(config);
}
public List<ProductOrderViewModel>? GetList()
{
try
{
var list = _productOrderBL.GetAllProductOrders();
return list?.Select(x => _mapper.Map<ProductOrderViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder GetList");
throw new Exception("Error retrieving ProductOrders", ex);
}
}
public List<ProductOrderViewModel>? GetListByPeriod(DateTime fromDate, DateTime toDate)
{
try
{
var list = _productOrderBL.GetProductOrdersByPeriod(fromDate, toDate);
return list?.Select(x => _mapper.Map<ProductOrderViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder GetListByPeriod");
throw new Exception("Error retrieving ProductOrders by period", ex);
}
}
public List<ProductOrderViewModel>? GetListByProductAndPeriod(string productId, DateTime fromDate, DateTime toDate)
{
try
{
var list = _productOrderBL.GetProductOrdersByProductByPeriod(productId, fromDate, toDate);
return list?.Select(x => _mapper.Map<ProductOrderViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder GetListByProductAndPeriod");
throw new Exception("Error retrieving ProductOrders by product and period", ex);
}
}
public ProductOrderViewModel? GetElement(string data)
{
try
{
var order = _productOrderBL.GetProductOrderByData(data);
return order != null ? _mapper.Map<ProductOrderViewModel>(order) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder GetElement");
throw new Exception("Error retrieving ProductOrder", ex);
}
}
public void RegisterProductOrder(ProductOrderBindingModel productOrderModel)
{
try
{
var dataModel = _mapper.Map<ProductOrderDataModel>(productOrderModel);
_productOrderBL.InsertProductOrder(dataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder Register");
throw new Exception("Error registering ProductOrder", ex);
}
}
}

View File

@@ -0,0 +1,101 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPWebAPI.Adapters
{
public class ProductSetAdapter : IProductSetAdapter
{
private readonly IProductSetBusinessLogicContract _productSetBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public ProductSetAdapter(IProductSetBusinessLogicContract productSetBL, ILogger<ProductSetAdapter> logger)
{
_productSetBL = productSetBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ProductSetBindingModel, ProductSetDataModel>();
cfg.CreateMap<ProductSetDataModel, ProductSetViewModel>();
cfg.CreateMap<ProductSetViewModel, ProductSetDataModel>();
});
_mapper = new Mapper(config);
}
public List<ProductSetViewModel>? GetList()
{
try
{
return _productSetBL.GetAllProductSets()
.Select(x => _mapper.Map<ProductSetViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductSetAdapter.GetList");
return null;
}
}
public ProductSetViewModel? GetProductSetByData(string data)
{
try
{
var model = _productSetBL.GetProductSetByData(data);
return model != null ? _mapper.Map<ProductSetViewModel>(model) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductSetAdapter.GetProductSetByData");
return null;
}
}
public void Insert(ProductSetBindingModel productSet)
{
try
{
var data = _mapper.Map<ProductSetDataModel>(productSet);
_productSetBL.InsertProductSet(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductSetAdapter.Insert");
throw;
}
}
public void Update(ProductSetBindingModel productSet)
{
try
{
var data = _mapper.Map<ProductSetDataModel>(productSet);
_productSetBL.UpdateProductSet(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductSetAdapter.Update");
throw;
}
}
public void Delete(string id)
{
try
{
_productSetBL.DeleteProductSet(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductSetAdapter.Delete");
throw;
}
}
}
}

View File

@@ -0,0 +1,131 @@
using AutoMapper;
using Microsoft.Extensions.Logging;
using YAPContracts.BindingModels;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.Exceptions;
using YAPContracts.AdapterContracts;
namespace YAPWebAPI.Adapters
{
public class PurchaseAdapter : IPurchaseAdapter
{
private readonly IPurchaseBusinessLogicContract _purchaseBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public PurchaseAdapter(IPurchaseBusinessLogicContract purchaseBL, ILogger logger)
{
_purchaseBL = purchaseBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<PurchaseBindingModel, PurchaseDataModel>();
cfg.CreateMap<PurchaseDataModel, PurchaseViewModel>();
cfg.CreateMap<PurchaseViewModel, PurchaseDataModel>();
});
_mapper = new Mapper(config);
}
public List<PurchaseViewModel> GetList()
{
try
{
var purchases = _purchaseBL.GetAllPurchases();
return purchases.Select(x => _mapper.Map<PurchaseViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Purchase GetList");
throw new Exception("Error retrieving purchases list", ex);
}
}
public PurchaseViewModel? GetElement(string id)
{
try
{
var purchase = _purchaseBL.GetPurchaseByData(id);
return purchase != null ? _mapper.Map<PurchaseViewModel>(purchase) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Purchase GetElement");
throw new Exception("Error retrieving purchase", ex);
}
}
public void Register(PurchaseBindingModel model)
{
try
{
var dataModel = _mapper.Map<PurchaseDataModel>(model);
_purchaseBL.InsertPurchase(dataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Purchase Register");
throw new Exception("Error creating purchase", ex);
}
}
public void Update(PurchaseBindingModel model)
{
try
{
var dataModel = _mapper.Map<PurchaseDataModel>(model);
_purchaseBL.UpdatePurchase(dataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Purchase Update");
throw new Exception("Error updating purchase", ex);
}
}
public void Delete(string id)
{
try
{
_purchaseBL.DeletePurchase(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Purchase Delete");
throw new Exception("Error deleting purchase", ex);
}
}
public List<PurchaseViewModel> GetByUserAndPeriod(string userId, DateTime fromDate, DateTime toDate)
{
try
{
var purchases = _purchaseBL.GetPurchasesByUserByPeriod(userId, fromDate, toDate);
return purchases.Select(x => _mapper.Map<PurchaseViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Purchase GetByUserAndPeriod");
throw new Exception("Error retrieving purchases list by user and period", ex);
}
}
public List<PurchaseViewModel> GetByPeriod(DateTime fromDate, DateTime toDate)
{
try
{
var purchases = _purchaseBL.GetPurchasesByPeriod(fromDate, toDate);
return purchases.Select(x => _mapper.Map<PurchaseViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Purchase GetByPeriod");
throw new Exception("Error retrieving purchases list by period", ex);
}
}
}
}
}

View File

@@ -0,0 +1,110 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels.UserRoles;
using YAPContracts.Extentions;
using YAPContracts.ViewModels;
namespace YAPWebAPI.Adapters
{
public class StorekeeperAdapter : IStorekeeperAdapter
{
private readonly IStorekeeperBusinessLogicContract _storekeeperBusinessLogic;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public StorekeeperAdapter(IStorekeeperBusinessLogicContract storekeeperBusinessLogic, ILogger logger)
{
_storekeeperBusinessLogic = storekeeperBusinessLogic;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<StorekeeperBindingModel, StorekeeperDataModel>();
cfg.CreateMap<StorekeeperDataModel, StorekeeperViewModel>();
cfg.CreateMap<StorekeeperViewModel, StorekeeperDataModel>();
});
_mapper = new Mapper(config);
}
public List<StorekeeperViewModel> GetList()
{
try
{
return _storekeeperBusinessLogic.GetAllStorekeepers()
.Select(x => _mapper.Map<StorekeeperViewModel>(x)).ToList();
}
catch (Exception ex)
{
// Handle exceptions as needed, e.g., log them or rethrow
_logger.LogError(ex, "Error in Storekeeper GetList");
throw new Exception("Error retrieving users list", ex);
}
}
public StorekeeperViewModel? GetElement(string data)
{
try
{
var dataModel = _storekeeperBusinessLogic.GetStorekeeperByData(data);
return dataModel != null ? _mapper.Map<StorekeeperViewModel>(dataModel) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Storekeeper GetElement");
throw new Exception($"Error retrieving user with data {data}", ex);
}
}
public void Register(StorekeeperBindingModel model)
{
try
{
if (model == null)
{
throw new ArgumentNullException(nameof(model), "User data model cannot be null");
}
var dataModel = _mapper.Map<StorekeeperDataModel>(model);
_storekeeperBusinessLogic.InsertStorekeeper(dataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Storekeeper Register");
throw new Exception("Error adding user data model", ex);
}
}
public void Update(StorekeeperBindingModel model)
{
try
{
if (model == null)
{
throw new ArgumentNullException(nameof(model), "User data model cannot be null");
}
var dataModel = _mapper.Map<StorekeeperDataModel>(model);
_storekeeperBusinessLogic.UpdateStorekeeper(dataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Storekeeper Update");
throw new Exception("Error adding user data model", ex);
}
}
public void Delete(string id)
{
try
{
if (!id.IsGuid()) throw new ArgumentException(nameof(id), "Incorrect Id");
_storekeeperBusinessLogic.DeleteStorekeeper(id);
}
catch (Exception ex)
{
// Handle exceptions as needed, e.g., log them or rethrow
_logger.LogError(ex, "Error in Storekeeper Delete");
throw new Exception($"Error deleting purchase with ID {id}", ex);
}
}
}
}

View File

@@ -0,0 +1,112 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.DataModels.UserRoles;
using YAPContracts.Extentions;
using YAPContracts.ViewModels;
using YAPDatabase.Models;
namespace YAPWebAPI.Adapters
{
public class WorkerAdapter : IWorkerAdapter
{
private readonly IWorkerBusinessLogicContract _workerBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public WorkerAdapter(IWorkerBusinessLogicContract workerBL, ILogger logger)
{
_logger = logger;
_workerBL = workerBL;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<WorkerBindingModel, WorkerDataModel>();
cfg.CreateMap<WorkerDataModel, WorkerViewModel>();
cfg.CreateMap<WorkerViewModel, WorkerDataModel>();
});
_mapper = new Mapper(config);
}
public List<WorkerViewModel> GetList()
{
try
{
return _workerBL.GetAllWorkers()
.Select(x => _mapper.Map<WorkerViewModel>(x)).ToList();
}
catch (Exception ex)
{
// Handle exceptions as needed, e.g., log them or rethrow
_logger.LogError(ex, "Error in Worker GetList");
throw new Exception("Error retrieving users list", ex);
}
}
public WorkerViewModel? GetElement(string data)
{
try
{
var dataModel = _workerBL.GetWorkerByData(data);
return dataModel != null ? _mapper.Map<WorkerViewModel>(dataModel) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Worker GetElement");
throw new Exception($"Error retrieving user with data {data}", ex);
}
}
public void Register(WorkerBindingModel model)
{
try
{
if (model == null)
{
throw new ArgumentNullException(nameof(model), "User data model cannot be null");
}
var dataModel = _mapper.Map<WorkerDataModel>(model);
_workerBL.InsertWorker(dataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Worker Register");
throw new Exception("Error adding user data model", ex);
}
}
public void Update(WorkerBindingModel model)
{
try
{
if (model == null)
{
throw new ArgumentNullException(nameof(model), "User data model cannot be null");
}
var dataModel = _mapper.Map<WorkerDataModel>(model);
_workerBL.UpdateWorker(dataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in Worker Update");
throw new Exception("Error adding user data model", ex);
}
}
public void Delete(string id)
{
try
{
if (!id.IsGuid()) throw new ArgumentException(nameof(id), "Incorrect Id");
_workerBL.DeleteWorker(id);
}
catch (Exception ex)
{
// Handle exceptions as needed, e.g., log them or rethrow
_logger.LogError(ex, "Error in Worker Delete");
throw new Exception($"Error deleting purchase with ID {id}", ex);
}
}
}
}

View File

@@ -0,0 +1,13 @@
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace YAPWebAPI
{
public static class AuthOptions
{
public const string ISSUER = "YAP_AuthServer"; // издатель токена
public const string AUDIENCE = "YAP_AuthClient"; // потребитель токена
const string KEY = "yapsecret_secretsecretsecretkey!123"; // ключ для шифрования
public static SymmetricSecurityKey GetSymmetricSecurityKey() => new(Encoding.UTF8.GetBytes(KEY));
}
}

View File

@@ -0,0 +1,99 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
namespace YAPWebAPI.Controllers
{
[Authorize]
public class CommentController : Controller
{
private readonly ICommentAdapter _commentAdapter;
public CommentController(ICommentAdapter commentAdapter)
{
_commentAdapter = commentAdapter;
}
// GET: /Comment/
public IActionResult Index()
{
var comments = _commentAdapter.GetList();
return View(comments);
}
// GET: /Comment/Details/{id}
public IActionResult Details(string id)
{
var comment = _commentAdapter.GetCommentById(id);
if (comment == null)
{
return NotFound();
}
return View(comment);
}
// GET: /Comment/Create
public IActionResult Create()
{
return View();
}
// POST: /Comment/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(CommentBindingModel model)
{
if (ModelState.IsValid)
{
_commentAdapter.Create(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: /Comment/Edit/{id}
public IActionResult Edit(string id)
{
var comment = _commentAdapter.GetCommentById(id);
if (comment == null)
{
return NotFound();
}
return View(comment);
}
// POST: /Comment/Edit
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(CommentBindingModel model)
{
if (ModelState.IsValid)
{
_commentAdapter.Update(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: /Comment/Delete/{id}
public IActionResult Delete(string id)
{
var comment = _commentAdapter.GetCommentById(id);
if (comment == null)
{
return NotFound();
}
return View(comment);
}
// POST: /Comment/Delete
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(string id)
{
_commentAdapter.Delete(id);
return RedirectToAction(nameof(Index));
}
}
}

View File

@@ -0,0 +1,97 @@
using Microsoft.AspNetCore.Mvc;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
namespace YAPWebAPI.Controllers
{
public class ProductController : Controller
{
private readonly IProductAdapter _productAdapter;
public ProductController(IProductAdapter productAdapter)
{
_productAdapter = productAdapter;
}
// GET: /Product/
public IActionResult Index()
{
var sets = _productAdapter.GetList();
return View(sets);
}
// GET: /Product/Details/{id}
public IActionResult Details(string id)
{
var set = _productAdapter.GetProductByData(id);
if (set == null)
{
return NotFound();
}
return View(set);
}
// GET: /Product/Create
public IActionResult Create()
{
return View();
}
// POST: /Product/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(ProductBindingModel model)
{
if (ModelState.IsValid)
{
_productAdapter.Insert(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: /Product/Edit/{id}
public IActionResult Edit(string id)
{
var set = _productAdapter.GetProductByData(id);
if (set == null)
{
return NotFound();
}
return View(set);
}
// POST: /Product/Edit
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(ProductBindingModel model)
{
if (ModelState.IsValid)
{
_productAdapter.Update(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: /Product/Delete/{id}
public IActionResult Delete(string id)
{
var set = _productAdapter.GetProductByData(id);
if (set == null)
{
return NotFound();
}
return View(set);
}
// POST: /Product/Delete
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(string id)
{
_productAdapter.Delete(id);
return RedirectToAction(nameof(Index));
}
}
}

View File

@@ -0,0 +1,68 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
namespace YAPWebAPI.Controllers
{
[Authorize]
public class ProductOrderController : Controller
{
private readonly IProductOrderAdapter _adapter;
public ProductOrderController(IProductOrderAdapter adapter)
{
_adapter = adapter;
}
// список всех заказов
public IActionResult Index()
{
var orders = _adapter.GetList();
return View(orders);
}
// просмотр деталей
public IActionResult Details(string id)
{
var order = _adapter.GetElement(id);
if (order == null)
{
return NotFound();
}
return View(order);
}
// форма создания
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(ProductOrderBindingModel model)
{
if (ModelState.IsValid)
{
_adapter.RegisterProductOrder(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// заказы за период
public IActionResult ByPeriod(DateTime fromDate, DateTime toDate)
{
var orders = _adapter.GetListByPeriod(fromDate, toDate);
return View("Index", orders); // можно отдельное представление
}
// заказы по продукту за период
public IActionResult ByProductAndPeriod(string productId, DateTime fromDate, DateTime toDate)
{
var orders = _adapter.GetListByProductAndPeriod(productId, fromDate, toDate);
return View("Index", orders);
}
}
}

View File

@@ -0,0 +1,99 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
namespace YAPWebAPI.Controllers
{
[Authorize]
public class ProductSetController : Controller
{
private readonly IProductSetAdapter _productSetAdapter;
public ProductSetController(IProductSetAdapter productSetAdapter)
{
_productSetAdapter = productSetAdapter;
}
// GET: /ProductSet/
public IActionResult Index()
{
var sets = _productSetAdapter.GetList();
return View(sets);
}
// GET: /ProductSet/Details/{id}
public IActionResult Details(string id)
{
var set = _productSetAdapter.GetProductSetByData(id);
if (set == null)
{
return NotFound();
}
return View(set);
}
// GET: /ProductSet/Create
public IActionResult Create()
{
return View();
}
// POST: /ProductSet/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(ProductSetBindingModel model)
{
if (ModelState.IsValid)
{
_productSetAdapter.Insert(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: /ProductSet/Edit/{id}
public IActionResult Edit(string id)
{
var set = _productSetAdapter.GetProductSetByData(id);
if (set == null)
{
return NotFound();
}
return View(set);
}
// POST: /ProductSet/Edit
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(ProductSetBindingModel model)
{
if (ModelState.IsValid)
{
_productSetAdapter.Update(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: /ProductSet/Delete/{id}
public IActionResult Delete(string id)
{
var set = _productSetAdapter.GetProductSetByData(id);
if (set == null)
{
return NotFound();
}
return View(set);
}
// POST: /ProductSet/Delete
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(string id)
{
_productSetAdapter.Delete(id);
return RedirectToAction(nameof(Index));
}
}
}

View File

@@ -0,0 +1,110 @@
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPWebAPI.Controllers
{
[Authorize]
public class PurchaseController : Controller
{
private readonly IPurchaseAdapter _purchaseAdapter;
public PurchaseController(IPurchaseAdapter purchaseAdapter)
{
_purchaseAdapter = purchaseAdapter;
}
// список всех покупок
public IActionResult Index()
{
var purchases = _purchaseAdapter.GetList();
return View(purchases);
}
// просмотр деталей
public IActionResult Details(string id)
{
var purchase = _purchaseAdapter.GetElement(id);
if (purchase == null)
{
return NotFound();
}
return View(purchase);
}
// форма добавления
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(PurchaseBindingModel model)
{
if (ModelState.IsValid)
{
_purchaseAdapter.Register(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// форма редактирования
public IActionResult Edit(string id)
{
var purchase = _purchaseAdapter.GetElement(id);
if (purchase == null)
{
return NotFound();
}
var bindingModel = new PurchaseBindingModel
{
Id = purchase.Id,
UserId = purchase.UserId,
PurchaseDate = purchase.PurchaseDate,
TotalPrice = purchase.TotalPrice,
// сюда можно маппить связанные продукты/сборки
};
return View(bindingModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(PurchaseBindingModel model)
{
if (ModelState.IsValid)
{
_purchaseAdapter.Update(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// удаление
public IActionResult Delete(string id)
{
var purchase = _purchaseAdapter.GetElement(id);
if (purchase == null)
{
return NotFound();
}
return View(purchase);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(string id)
{
_purchaseAdapter.Delete(id);
return RedirectToAction(nameof(Index));
}
}
}

View File

@@ -0,0 +1,109 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
namespace YAPWebAPI.Controllers
{
[Authorize]
public class StorekeeperController : Controller
{
private readonly IStorekeeperAdapter _storekeeperAdapter;
public StorekeeperController(IStorekeeperAdapter storekeeperAdapter)
{
_storekeeperAdapter = storekeeperAdapter;
}
// список всех работников
public IActionResult Index()
{
var storekeepers = _storekeeperAdapter.GetList();
return View(storekeepers);
}
// просмотр деталей конкретного работника
public IActionResult Details(string id)
{
var storekeeper = _storekeeperAdapter.GetElement(id);
if (storekeeper == null)
{
return NotFound();
}
return View(storekeeper);
}
// GET: форма создания
public IActionResult Create()
{
return View();
}
// POST: создание нового работника
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(StorekeeperBindingModel model)
{
if (ModelState.IsValid)
{
_storekeeperAdapter.Register(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: форма редактирования
public IActionResult Edit(string id)
{
var storekeeper = _storekeeperAdapter.GetElement(id);
if (storekeeper == null)
{
return NotFound();
}
// для редактирования можно заполнить BindingModel из ViewModel
var bindingModel = new StorekeeperBindingModel
{
Id = storekeeper.Id,
Login = storekeeper.Login,
Email = storekeeper.Email,
Password = "", // пароль редактируется отдельно
};
return View(bindingModel);
}
// POST: обновление данных
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(StorekeeperBindingModel model)
{
if (ModelState.IsValid)
{
_storekeeperAdapter.Update(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: форма удаления
public IActionResult Delete(string id)
{
var storekeeper = _storekeeperAdapter.GetElement(id);
if (storekeeper == null)
{
return NotFound();
}
return View(storekeeper);
}
// POST: подтверждение удаления
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(string id)
{
_storekeeperAdapter.Delete(id);
return RedirectToAction(nameof(Index));
}
}
}

View File

@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc;
namespace YAPWebAPI.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

View File

@@ -0,0 +1,119 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
namespace YAPWebAPI.Controllers
{
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using YAPWebAPI.Adapters;
using YAPContracts.BindingModels;
using YAPContracts.ViewModels;
namespace YAPWebUI.Controllers
{
[Authorize]
public class WorkerController : Controller
{
private readonly IWorkerAdapter _workerAdapter;
public WorkerController(IWorkerAdapter workerAdapter)
{
_workerAdapter = workerAdapter;
}
// список всех работников
public IActionResult Index()
{
var workers = _workerAdapter.GetList();
return View(workers);
}
// просмотр деталей конкретного работника
public IActionResult Details(string id)
{
var worker = _workerAdapter.GetElement(id);
if (worker == null)
{
return NotFound();
}
return View(worker);
}
// GET: форма создания
public IActionResult Create()
{
return View();
}
// POST: создание нового работника
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(WorkerBindingModel model)
{
if (ModelState.IsValid)
{
_workerAdapter.Register(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: форма редактирования
public IActionResult Edit(string id)
{
var worker = _workerAdapter.GetElement(id);
if (worker == null)
{
return NotFound();
}
// для редактирования можно заполнить BindingModel из ViewModel
var bindingModel = new WorkerBindingModel
{
Id = worker.Id,
Login = worker.Login,
Email = worker.Email,
Password = "", // пароль редактируется отдельно
};
return View(bindingModel);
}
// POST: обновление данных
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(WorkerBindingModel model)
{
if (ModelState.IsValid)
{
_workerAdapter.Update(model);
return RedirectToAction(nameof(Index));
}
return View(model);
}
// GET: форма удаления
public IActionResult Delete(string id)
{
var worker = _workerAdapter.GetElement(id);
if (worker == null)
{
return NotFound();
}
return View(worker);
}
// POST: подтверждение удаления
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(string id)
{
_workerAdapter.Delete(id);
return RedirectToAction(nameof(Index));
}
}
}
}

View File

@@ -0,0 +1,94 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Serilog;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using YAPDatabase;
using YAPWebAPI;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
using var loggerFactory = new LoggerFactory();
loggerFactory.AddSerilog(new LoggerConfiguration().ReadFrom.Configuration(builder.Configuration).CreateLogger());
builder.Services.AddSingleton(loggerFactory.CreateLogger("Any"));
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ValidateIssuer = true,
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ValidIssuer = AuthOptions.ISSUER,
// <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ValidateAudience = true,
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ValidAudience = AuthOptions.AUDIENCE,
// <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ValidateLifetime = true,
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ValidateIssuerSigningKey = true,
};
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Console.WriteLine("KEY BYTES (VALIDATE): " + string.Join(",", AuthOptions.GetSymmetricSecurityKey().Key));
Console.WriteLine("JWT Error: " + context.Exception.Message);
return Task.CompletedTask;
}
};
});
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
if (app.Environment.IsProduction())
{
var dbContext = app.Services.GetRequiredService<YAPDbContext>();
if (dbContext.Database.CanConnect())
{
dbContext.Database.EnsureCreated();
dbContext.Database.Migrate();
}
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.Map("/login/{username}", (string username) =>
{
Console.WriteLine("KEY BYTES (CREATE): " + string.Join(",", AuthOptions.GetSymmetricSecurityKey().Key));
return new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken(
issuer: AuthOptions.ISSUER,
audience: AuthOptions.AUDIENCE,
claims: [new(ClaimTypes.Name, username)],
expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(2)),
signingCredentials: new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256)));
});
app.MapControllers();
app.Run();

View File

@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5275",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7227;http://localhost:5275",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,13 @@
namespace YAPWebAPI
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.8" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\YAPBusinessLogic\YAPBusinessLogic.csproj" />
<ProjectReference Include="..\YAPContracts\YAPContracts.csproj" />
<ProjectReference Include="..\YAPDatabase\YAPDatabase.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
@YAPWebAPI_HostAddress = http://localhost:5275
GET {{YAPWebAPI_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,25 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information"
},
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "../logs/YAP-.log",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} { CorrelationId } { Level: u3 } { Username } { Message: lj } { Exception } { NewLine }"
}
}
]
},
"AllowedHosts": "*"
}

View File

@@ -0,0 +1,191 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPWebApplication.Adapters
{
public class CommentAdapter : ICommentAdapter
{
private readonly ICommentBusinessLogicContract _commentBL;
private readonly IWorkerAdapter _workerAdapter;
private readonly IProductSetAdapter _productSetAdapter;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public CommentAdapter(
ICommentBusinessLogicContract commentBL,
IWorkerAdapter workerAdapter,
IProductSetAdapter productSetAdapter,
ILogger<CommentAdapter> logger)
{
_commentBL = commentBL;
_workerAdapter = workerAdapter;
_productSetAdapter = productSetAdapter;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<CommentBindingModel, CommentDataModel>();
cfg.CreateMap<CommentDataModel, CommentViewModel>()
.ForMember(dest => dest.AuthorId, opt => opt.MapFrom(src => src.UserId))
.ForMember(dest => dest.CommentDate, opt => opt.MapFrom(src => src.Date));
cfg.CreateMap<CommentViewModel, CommentDataModel>()
.ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.AuthorId))
.ForMember(dest => dest.Date, opt => opt.MapFrom(src => src.CommentDate));
});
_mapper = new Mapper(config);
}
public List<CommentViewModel>? GetList()
{
try
{
var comments = _commentBL.GetAllComments()
.Select(x => _mapper.Map<CommentViewModel>(x))
.ToList();
foreach (var comment in comments)
{
if (!string.IsNullOrEmpty(comment.AuthorId))
{
var user = _workerAdapter.GetElement(comment.AuthorId);
comment.UserLogin = user?.Login;
}
if (!string.IsNullOrEmpty(comment.ProductSetId))
{
var set = _productSetAdapter.GetProductSetByData(comment.ProductSetId);
comment.ProductSetName = set?.SetName;
}
}
return comments;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetList");
return null;
}
}
public CommentViewModel? GetCommentById(string id)
{
try
{
var data = _commentBL.GetCommentByData(id);
if (data == null) return null;
var comment = _mapper.Map<CommentViewModel>(data);
if (!string.IsNullOrEmpty(comment.AuthorId))
{
var user = _workerAdapter.GetElement(comment.AuthorId);
comment.UserLogin = user?.Login;
}
if (!string.IsNullOrEmpty(comment.ProductSetId))
{
var set = _productSetAdapter.GetProductSetByData(comment.ProductSetId);
comment.ProductSetName = set?.SetName;
}
return comment;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetCommentById");
return null;
}
}
public List<CommentViewModel>? GetCommentsByProductSetAndPeriod(string productSetId, DateTime fromDate, DateTime toDate)
{
try
{
return _commentBL.GetCommentsByProductSetByPeriod(productSetId, fromDate, toDate)
.Select(x => _mapper.Map<CommentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetCommentsByProductSetAndPeriod");
return null;
}
}
public List<CommentViewModel>? GetCommentsByUserAndPeriod(string userId, DateTime fromDate, DateTime toDate)
{
try
{
return _commentBL.GetCommentsByUserByPeriod(userId, fromDate, toDate)
.Select(x => _mapper.Map<CommentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetCommentsByUserAndPeriod");
return null;
}
}
public List<CommentViewModel>? GetCommentsByPeriod(DateTime fromDate, DateTime toDate)
{
try
{
return _commentBL.GetCommentsByPeriod(fromDate, toDate)
.Select(x => _mapper.Map<CommentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.GetCommentsByPeriod");
return null;
}
}
public void Create(CommentBindingModel comment)
{
try
{
var data = _mapper.Map<CommentDataModel>(comment);
_commentBL.InsertComment(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.Create");
throw;
}
}
public void Update(CommentBindingModel comment)
{
try
{
var data = _mapper.Map<CommentDataModel>(comment);
_commentBL.UpdateComment(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.Update");
throw;
}
}
public void Delete(string id)
{
try
{
_commentBL.DeleteComment(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in CommentAdapter.Delete");
throw;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPWebApplication.Adapters
{
public class ComponentAdapter : IComponentAdapter
{
private readonly IComponentBusinessLogicContract _productBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public ComponentAdapter(IComponentBusinessLogicContract productBL, ILogger<ComponentAdapter> logger)
{
_productBL = productBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ComponentBindingModel, ComponentDataModel>();
cfg.CreateMap<ComponentDataModel, ComponentViewModel>();
cfg.CreateMap<ComponentViewModel, ComponentDataModel>();
});
_mapper = new Mapper(config);
}
public List<ComponentViewModel>? GetList(bool onlyActual = true)
{
try
{
return _productBL.GetAllComponents(onlyActual)
.Select(x => _mapper.Map<ComponentViewModel>(x))
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.GetList");
return null;
}
}
public ComponentViewModel? GetComponentByData(string data)
{
try
{
var model = _productBL.GetComponentByData(data);
return model != null ? _mapper.Map<ComponentViewModel>(model) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.GetComponentByData");
return null;
}
}
public void Insert(ComponentBindingModel product)
{
try
{
var data = _mapper.Map<ComponentDataModel>(product);
_productBL.InsertComponent(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.Insert");
throw;
}
}
public void Update(ComponentBindingModel product)
{
try
{
var data = _mapper.Map<ComponentDataModel>(product);
_productBL.UpdateComponent(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.Update");
throw;
}
}
public void Delete(string id)
{
try
{
_productBL.DeleteComponent(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ComponentAdapter.Delete");
throw;
}
}
}
}

View File

@@ -0,0 +1,112 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.ViewModels;
namespace YAPWebApplication.Adapters
{
public class ProductAdapter : IProductAdapter
{
private readonly IProductBusinessLogicContract _productBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public ProductAdapter(IProductBusinessLogicContract productBL, ILogger<ProductAdapter> logger)
{
_productBL = productBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ProductBindingModel, ProductDataModel>()
.ForMember(dest => dest.Components,
opt => opt.MapFrom(src => src.ComponentIds != null
? src.ComponentIds.Select(id => new ComponentInProductDataModel(id, src.Id)).ToList()
: new List<ComponentInProductDataModel>()));
cfg.CreateMap<ProductDataModel, ProductViewModel>()
.ForMember(dest => dest.ComponentIds, opt => opt.MapFrom(src => src.Components.Select(c => c.ComponentId).ToList()));
cfg.CreateMap<ProductViewModel, ProductDataModel>();
});
_mapper = new Mapper(config);
}
public List<ProductViewModel>? GetList(bool onlyActual = true)
{
try
{
var products = _productBL.GetAllProducts(onlyActual)
.Select(x => _mapper.Map<ProductViewModel>(x))
.ToList();
return products;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.GetList");
return null;
}
}
public ProductViewModel? GetProductByData(string data)
{
try
{
var model = _productBL.GetProductByData(data);
return model != null ? _mapper.Map<ProductViewModel>(model) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.GetProductByData");
return null;
}
}
public void Insert(ProductBindingModel product)
{
try
{
var data = _mapper.Map<ProductDataModel>(product);
_productBL.InsertProduct(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.Insert");
throw;
}
}
public void Update(ProductBindingModel product)
{
try
{
var data = _mapper.Map<ProductDataModel>(product);
_productBL.UpdateProduct(data);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.Update");
throw;
}
}
public void Delete(string id)
{
try
{
_productBL.DeleteProduct(id);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductAdapter.Delete");
throw;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using AutoMapper;
using YAPContracts.AdapterContracts;
using YAPContracts.BindingModels;
using YAPContracts.BusinessLogicContracts;
using YAPContracts.DataModels;
using YAPContracts.Exceptions;
using YAPContracts.ViewModels;
using YAPDatabase.Models;
namespace YAPWebApplication.Adapters;
public class ProductOrderAdapter : IProductOrderAdapter
{
private readonly IProductOrderBusinessLogicContract _productOrderBL;
private readonly ILogger _logger;
private readonly Mapper _mapper;
public ProductOrderAdapter(IProductOrderBusinessLogicContract productOrderBL, ILogger logger)
{
_productOrderBL = productOrderBL;
_logger = logger;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ProductOrderBindingModel, ProductOrderDataModel>();
cfg.CreateMap<ProductOrderDataModel, ProductOrderViewModel>().ForMember(dest => dest.ProductName, opt => opt.MapFrom(src => src.ProductName));
cfg.CreateMap<ProductOrderViewModel, ProductOrderDataModel>().ForMember(dest => dest.ProductName, opt => opt.MapFrom(src => src.ProductName));
});
_mapper = new Mapper(config);
}
public List<ProductOrderViewModel>? GetList()
{
try
{
var list = _productOrderBL.GetAllProductOrders();
return list?.Select(x => _mapper.Map<ProductOrderViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder GetList");
throw new Exception("Error retrieving ProductOrders", ex);
}
}
public List<ProductOrderViewModel>? GetListByPeriod(DateTime fromDate, DateTime toDate)
{
try
{
var list = _productOrderBL.GetProductOrdersByPeriod(fromDate, toDate);
return list?.Select(x => _mapper.Map<ProductOrderViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder GetListByPeriod");
throw new Exception("Error retrieving ProductOrders by period", ex);
}
}
public List<ProductOrderViewModel>? GetListByProductAndPeriod(string productId, DateTime fromDate, DateTime toDate)
{
try
{
var list = _productOrderBL.GetProductOrdersByProductByPeriod(productId, fromDate, toDate);
return list?.Select(x => _mapper.Map<ProductOrderViewModel>(x)).ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder GetListByProductAndPeriod");
throw new Exception("Error retrieving ProductOrders by product and period", ex);
}
}
public ProductOrderViewModel? GetElement(string data)
{
try
{
var order = _productOrderBL.GetProductOrderByData(data);
return order != null ? _mapper.Map<ProductOrderViewModel>(order) : null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder GetElement");
throw new Exception("Error retrieving ProductOrder", ex);
}
}
public void RegisterProductOrder(ProductOrderBindingModel productOrderModel)
{
try
{
var dataModel = _mapper.Map<ProductOrderDataModel>(productOrderModel);
_productOrderBL.InsertProductOrder(dataModel);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ProductOrder Register");
throw new Exception("Error registering ProductOrder", ex);
}
}
}

Some files were not shown because too many files have changed in this diff Show More