Compare commits

..

13 Commits

140 changed files with 79065 additions and 9 deletions

View File

@ -4,6 +4,7 @@ using AbstractLawFirmContracts.SearchModels;
using AbstractLawFirmContracts.StoragesContracts;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmDataModels.Enums;
using AbstractLawFirmDataModels.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
@ -17,12 +18,19 @@ namespace AbstractLawFirmBusinessLogic.BusinessLogic
{
private readonly ILogger _logger;
private readonly IOrderStorage _orderStorage;
private readonly IShopStorage _shopStorage;
private readonly IShopLogic _shopLogic;
private readonly IDocumentStorage _documentStorage;
static readonly object locker = new object();
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage, IShopLogic shopLogic, IDocumentStorage documentStorage, IShopStorage shopStorage)
public OrderLogic(ILogger<OrderLogic> logger, IOrderStorage orderStorage)
{
_logger = logger;
_orderStorage = orderStorage;
_shopLogic = shopLogic;
_documentStorage = documentStorage;
_shopStorage = shopStorage;
}
public List<OrderViewModel>? ReadList(OrderSearchModel? model)
@ -62,6 +70,7 @@ namespace AbstractLawFirmBusinessLogic.BusinessLogic
model.Status = OrderStatus.Принят;
if (_orderStorage.Insert(model) == null)
{
model.Status = OrderStatus.Неизвестен;
_logger.LogWarning("Insert operation failed");
return false;
}
@ -82,10 +91,32 @@ namespace AbstractLawFirmBusinessLogic.BusinessLogic
_logger.LogWarning("Status change operation failed");
throw new InvalidOperationException("Текущий статус заказа не может быть переведен в выбранный");
}
if (status == OrderStatus.Готов)
{
var document = _documentStorage.GetElement(new DocumentSearchModel() { Id = model.DocumentId });
if (document == null)
{
_logger.LogWarning("Status change operation failed. Car not found.");
return false;
}
if (!CheckThenSupplyMany(document, model.Count))
{
_logger.LogWarning("Status change operation failed. Shop supply error.");
return false;
}
}
model.Status = status;
if (model.Status == OrderStatus.Выдан) model.DateImplement = DateTime.Now;
if (element.ImplementerId.HasValue) model.ImplementerId = element.ImplementerId;
_orderStorage.Update(model);
if (_orderStorage.Update(model) == null)
{
model.Status--;
_logger.LogWarning("Update operation failed");
return false;
}
return true;
}
@ -118,6 +149,10 @@ true)
{
return;
}
if (model.DocumentId < 0)
{
throw new ArgumentNullException("Некорректный идентификатор документа", nameof(model.DocumentId));
}
if (model.Sum <= 0)
{
throw new ArgumentNullException("Цена заказа должна быть больше 0", nameof(model.Sum));
@ -128,5 +163,67 @@ true)
}
_logger.LogInformation("Order. Sum:{ Cost}. Id: { Id}", model.Sum, model.Id);
}
public bool CheckThenSupplyMany(IDocumentModel document, int count)
{
if (count <= 0)
{
_logger.LogWarning("Check then supply operation error. Car count < 0.");
return false;
}
int freeSpace = 0;
foreach (var shop in _shopStorage.GetFullList())
{
freeSpace += shop.MaxCountDocuments;
foreach (var c in shop.ShopDocuments)
{
freeSpace -= c.Value.Item2;
}
}
if (freeSpace < count)
{
_logger.LogWarning("Check then supply operation error. There's no place for new cars in shops.");
return false;
}
foreach (var shop in _shopStorage.GetFullList())
{
freeSpace = shop.MaxCountDocuments;
foreach (var c in shop.ShopDocuments)
freeSpace -= c.Value.Item2;
if (freeSpace <= 0)
continue;
if (freeSpace >= count)
{
if (_shopLogic.SupplyDocuments(new ShopSearchModel() { Id = shop.Id }, document, count))
count = 0;
else
{
_logger.LogWarning("Supply error");
return false;
}
}
if (freeSpace < count)
{
if (_shopLogic.SupplyDocuments(new ShopSearchModel() { Id = shop.Id }, document, freeSpace))
count -= freeSpace;
else
{
_logger.LogWarning("Supply error");
return false;
}
}
if (count <= 0)
{
return true;
}
}
return false;
}
}
}

View File

@ -18,17 +18,19 @@ namespace AbstractLawFirmBusinessLogic.BusinessLogic
private readonly IComponentStorage _componentStorage;
private readonly IDocumentStorage _documentStorage;
private readonly IOrderStorage _orderStorage;
private readonly IShopStorage _shopStorage;
private readonly AbstractSaveToExcel _saveToExcel;
private readonly AbstractSaveToWord _saveToWord;
private readonly AbstractSaveToPdf _saveToPdf;
public ReportLogic(IDocumentStorage documentStorage, IComponentStorage
componentStorage, IOrderStorage orderStorage,
componentStorage, IOrderStorage orderStorage, IShopStorage shopStorage,
AbstractSaveToExcel saveToExcel, AbstractSaveToWord saveToWord,
AbstractSaveToPdf saveToPdf)
{
_documentStorage = documentStorage;
_componentStorage = componentStorage;
_orderStorage = orderStorage;
_shopStorage = shopStorage;
_saveToExcel = saveToExcel;
_saveToWord = saveToWord;
_saveToPdf = saveToPdf;
@ -122,6 +124,62 @@ namespace AbstractLawFirmBusinessLogic.BusinessLogic
Orders = GetOrders(model)
});
}
public void SaveShopsToWordFile(ReportBindingModel model)
{
_saveToWord.CreateTableDoc(new WordInfo
{
FileName = model.FileName,
Title = "Список магазинов",
Shops = _shopStorage.GetFullList()
});
}
public void SaveShopDocumentsToExcelFile(ReportBindingModel model)
{
_saveToExcel.CreateShopReport(new ExcelInfo
{
FileName = model.FileName,
Title = "Загруженность магазинов",
ShopDocuments = GetShopDocuments()
});
}
public List<ReportShopDocumentsViewModel> GetShopDocuments()
{
var shops = _shopStorage.GetFullList();
var list = new List<ReportShopDocumentsViewModel>();
foreach (var shop in shops)
{
var record = new ReportShopDocumentsViewModel
{
ShopName = shop.ShopName,
Documents = new List<Tuple<string, int>>(),
Count = 0
};
foreach (var docCount in shop.ShopDocuments.Values)
{
record.Documents.Add(new Tuple<string, int>(docCount.Item1.DocumentName, docCount.Item2));
record.Count += docCount.Item2;
}
list.Add(record);
}
return list;
}
public List<ReportDateOrdersViewModel> GetDateOrders()
{
return _orderStorage.GetFullList().GroupBy(x => x.DateCreate.Date).Select(x => new ReportDateOrdersViewModel
{
DateCreate = x.Key,
CountOrders = x.Count(),
SumOrders = x.Sum(y => y.Sum)
}).ToList();
}
public void SaveDateOrdersToPdfFile(ReportBindingModel model)
{
_saveToPdf.CreateReportDateDoc(new PdfInfo
{
FileName = model.FileName,
Title = "Заказы по датам",
DateOrders = GetDateOrders()
});
}
}
}

View File

@ -0,0 +1,177 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.BusinessLogicsContracts;
using AbstractLawFirmContracts.SearchModels;
using AbstractLawFirmContracts.StoragesContracts;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmDataModels.Models;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmBusinessLogic.BusinessLogic
{
public class ShopLogic : IShopLogic
{
private readonly ILogger _logger;
private readonly IShopStorage _shopStorage;
public ShopLogic(ILogger<ShopLogic> logger, IShopStorage shopStorage)
{
_logger = logger;
_shopStorage = shopStorage;
}
public List<ShopViewModel>? ReadList(ShopSearchModel? model)
{
_logger.LogInformation("ReadList. ShopName:{ShopName}.Id:{ Id}", model?.ShopName, model?.Id);
var list = model == null ? _shopStorage.GetFullList() : _shopStorage.GetFilteredList(model);
if (list == null)
{
_logger.LogWarning("ReadList return null list");
return null;
}
_logger.LogInformation("ReadList. Count:{Count}", list.Count);
return list;
}
public ShopViewModel? ReadElement(ShopSearchModel model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
_logger.LogInformation("ReadElement. ShopName:{ShopName}.Id:{ Id}", model.ShopName, model.Id);
var element = _shopStorage.GetElement(model);
if (element == null)
{
_logger.LogWarning("ReadElement element not found");
return null;
}
_logger.LogInformation("ReadElement find. Id:{Id}", element.Id);
return element;
}
public bool Create(ShopBindingModel model)
{
CheckModel(model);
if (_shopStorage.Insert(model) == null)
{
_logger.LogWarning("Insert operation failed");
return false;
}
return true;
}
public bool Update(ShopBindingModel model)
{
CheckModel(model);
if (_shopStorage.Update(model) == null)
{
_logger.LogWarning("Update operation failed");
return false;
}
return true;
}
public bool Delete(ShopBindingModel model)
{
CheckModel(model, false);
_logger.LogInformation("Delete. Id:{Id}", model.Id);
if (_shopStorage.Delete(model) == null)
{
_logger.LogWarning("Delete operation failed");
return false;
}
return true;
}
public bool SupplyDocuments(ShopSearchModel model, IDocumentModel document, int count)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
if (count <= 0)
{
throw new ArgumentException("Количество изделий должно быть больше 0", nameof(count));
}
_logger.LogInformation("AddPlaneInShop. ShopName:{ShopName}.Id:{ Id}", model.ShopName, model.Id);
var element = _shopStorage.GetElement(model);
if (element == null)
{
_logger.LogWarning("AddPlaneInShop element not found");
return false;
}
_logger.LogInformation("AddPlaneInShop find. Id:{Id}", element.Id);
int countDocuments = 0;
foreach (var c in element.ShopDocuments)
countDocuments += c.Value.Item2;
if (count > element.MaxCountDocuments - countDocuments)
{
_logger.LogWarning("Required shop will be overflowed");
return false;
}
else
{
if (element.ShopDocuments.TryGetValue(document.Id, out var pair))
{
element.ShopDocuments[document.Id] = (document, count + pair.Item2);
_logger.LogInformation("AddPlaneInShop. Added {count} {plane} to '{ShopName}' shop", count, document.DocumentName, element.ShopName);
}
else
{
element.ShopDocuments[document.Id] = (document, count);
_logger.LogInformation("AddPlaneInShop. Added {count} new plane {plane} to '{ShopName}' shop", count, document.DocumentName, element.ShopName);
}
_shopStorage.Update(new()
{
Id = element.Id,
Address = element.Address,
ShopName = element.ShopName,
MaxCountDocuments = element.MaxCountDocuments,
OpeningDate = element.OpeningDate,
ShopDocuments = element.ShopDocuments
});
}
return true;
}
private void CheckModel(ShopBindingModel model, bool withParams = true)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
if (!withParams)
{
return;
}
if (string.IsNullOrEmpty(model.ShopName))
{
throw new ArgumentNullException("Нет названия магазина", nameof(model.ShopName));
}
_logger.LogInformation("Shop. ShopName:{ShopName}.Address:{ Address}. Id:{ Id}", model.ShopName, model.Address, model.Id);
var element = _shopStorage.GetElement(new ShopSearchModel
{
ShopName = model.ShopName
});
if (element != null && element.Id != model.Id && element.ShopName == model.ShopName)
{
throw new InvalidOperationException("Магазин с таким названием уже есть");
}
}
public bool SellDocument(IDocumentModel document, int count)
{
return _shopStorage.SellDocument(document, count);
}
}
}

View File

@ -76,6 +76,68 @@ namespace AbstractLawFirmBusinessLogic.OfficePackage
}
SaveExcel(info);
}
public void CreateShopReport(ExcelInfo info)
{
CreateExcel(info);
InsertCellInWorksheet(new ExcelCellParameters
{
ColumnName = "A",
RowIndex = 1,
Text = info.Title,
StyleInfo = ExcelStyleInfoType.Title
});
MergeCells(new ExcelMergeParameters
{
CellFromName = "A1",
CellToName = "C1"
});
uint rowIndex = 2;
foreach (var pc in info.ShopDocuments)
{
InsertCellInWorksheet(new ExcelCellParameters
{
ColumnName = "A",
RowIndex = rowIndex,
Text = pc.ShopName,
StyleInfo = ExcelStyleInfoType.Text
});
rowIndex++;
foreach (var (DocumentName, Count) in pc.Documents)
{
InsertCellInWorksheet(new ExcelCellParameters
{
ColumnName = "B",
RowIndex = rowIndex,
Text = DocumentName,
StyleInfo = ExcelStyleInfoType.TextWithBorder
});
InsertCellInWorksheet(new ExcelCellParameters
{
ColumnName = "C",
RowIndex = rowIndex,
Text = Count.ToString(),
StyleInfo = ExcelStyleInfoType.TextWithBorder
});
rowIndex++;
}
InsertCellInWorksheet(new ExcelCellParameters
{
ColumnName = "A",
RowIndex = rowIndex,
Text = "Итого",
StyleInfo = ExcelStyleInfoType.Text
});
InsertCellInWorksheet(new ExcelCellParameters
{
ColumnName = "C",
RowIndex = rowIndex,
Text = pc.Count.ToString(),
StyleInfo = ExcelStyleInfoType.Text
});
rowIndex++;
}
SaveExcel(info);
}
/// <summary>
/// Создание excel-файла
/// </summary>

View File

@ -50,6 +50,39 @@ order.DateCreate.ToShortDateString(), order.DocumentName, order.Sum.ToString(),
});
SavePdf(info);
}
public void CreateReportDateDoc(PdfInfo info)
{
CreatePdf(info);
CreateParagraph(new PdfParagraph
{
Text = info.Title,
Style = "NormalTitle",
ParagraphAlignment = PdfParagraphAlignmentType.Center
});
CreateTable(new List<string> { "3cm", "3cm", "7cm" });
CreateRow(new PdfRowParameters
{
Texts = new List<string> { "Дата", "Количество", "Сумма" },
Style = "NormalTitle",
ParagraphAlignment = PdfParagraphAlignmentType.Center
});
foreach (var order in info.DateOrders)
{
CreateRow(new PdfRowParameters
{
Texts = new List<string> { order.DateCreate.ToShortDateString(), order.CountOrders.ToString(), order.SumOrders.ToString() },
Style = "Normal",
ParagraphAlignment = PdfParagraphAlignmentType.Left
});
}
CreateParagraph(new PdfParagraph
{
Text = $"Итого: {info.DateOrders.Sum(x => x.SumOrders)}\t",
Style = "Normal",
ParagraphAlignment = PdfParagraphAlignmentType.Center
});
SavePdf(info);
}
/// <summary>
/// Создание doc-файла
/// </summary>

View File

@ -39,6 +39,27 @@ namespace AbstractLawFirmBusinessLogic.OfficePackage
}
SaveWord(info);
}
public void CreateTableDoc(WordInfo wordInfo)
{
CreateWord(wordInfo);
var list = new List<string>();
foreach (var shop in wordInfo.Shops)
{
list.Add(shop.ShopName);
list.Add(shop.Address);
list.Add(shop.OpeningDate.ToString());
}
var wordTable = new WordTable
{
Headers = new List<string> {
"Название",
"Адрес",
"Дата открытия"},
Texts = list
};
CreateTable(wordTable);
SaveWord(wordInfo);
}
/// <summary>
/// Создание doc-файла
/// </summary>
@ -55,5 +76,6 @@ namespace AbstractLawFirmBusinessLogic.OfficePackage
/// </summary>
/// <param name="info"></param>
protected abstract void SaveWord(WordInfo info);
protected abstract void CreateTable(WordTable info);
}
}

View File

@ -16,6 +16,10 @@ namespace AbstractLawFirmBusinessLogic.OfficePackage.HelperModels
get;
set;
} = new();
public List<ReportShopDocumentsViewModel> ShopDocuments
{
get;
set;
} = new();
}
}

View File

@ -14,5 +14,6 @@ namespace AbstractLawFirmBusinessLogic.OfficePackage.HelperModels
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public List<ReportOrdersViewModel> Orders { get; set; } = new();
public List<ReportDateOrdersViewModel> DateOrders { get; set; } = new();
}
}

View File

@ -12,5 +12,6 @@ namespace AbstractLawFirmBusinessLogic.OfficePackage.HelperModels
public string FileName { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public List<DocumentViewModel> Documents { get; set; } = new();
public List<ShopViewModel> Shops { get; set; } = new();
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmBusinessLogic.OfficePackage.HelperModels
{
public class WordTable
{
public List<string> Headers { get; set; } = new();
public List<string> Texts { get; set; } = new();
}
}

View File

@ -126,6 +126,85 @@ namespace AbstractLawFirmBusinessLogic.OfficePackage.Implements
_wordDocument.MainDocumentPart!.Document.Save();
_wordDocument.Dispose();
}
protected override void CreateTable(WordTable table)
{
if (_docBody == null || table == null)
{
return;
}
Table tab = new Table();
TableProperties props = 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
}
)
);
tab.AppendChild<TableProperties>(props);
TableGrid tableGrid = new TableGrid();
for (int i = 0; i < table.Headers.Count; i++)
{
tableGrid.AppendChild(new GridColumn());
}
tab.AppendChild(tableGrid);
TableRow tableRow = new TableRow();
foreach (var text in table.Headers)
{
tableRow.AppendChild(CreateTableCell(text));
}
tab.AppendChild(tableRow);
int height = table.Texts.Count / table.Headers.Count;
int width = table.Headers.Count;
for (int i = 0; i < height; i++)
{
tableRow = new TableRow();
for (int j = 0; j < width; j++)
{
var element = table.Texts[i * table.Headers.Count + j];
tableRow.AppendChild(CreateTableCell(element));
}
tab.AppendChild(tableRow);
}
_docBody.AppendChild(tab);
}
private TableCell CreateTableCell(string element)
{
var tableParagraph = new Paragraph();
var run = new Run();
run.AppendChild(new Text { Text = element });
tableParagraph.AppendChild(run);
var tableCell = new TableCell();
tableCell.AppendChild(tableParagraph);
return tableCell;
}
}
}

View File

@ -0,0 +1,27 @@
using AbstractLawFirmDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmContracts.BindingModels
{
public class ShopBindingModel : IShopModel
{
public int Id { get; set; }
public string ShopName { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public DateTime OpeningDate { get; set; } = DateTime.Now;
public Dictionary<int, (IDocumentModel, int)> ShopDocuments
{
get;
set;
} = new();
public int MaxCountDocuments { get; set; }
}
}

View File

@ -36,5 +36,10 @@ namespace AbstractLawFirmContracts.BusinessLogicsContracts
/// </summary>
/// <param name="model"></param>
void SaveOrdersToPdfFile(ReportBindingModel model);
List<ReportShopDocumentsViewModel> GetShopDocuments();
List<ReportDateOrdersViewModel> GetDateOrders();
void SaveShopsToWordFile(ReportBindingModel model);
void SaveShopDocumentsToExcelFile(ReportBindingModel model);
void SaveDateOrdersToPdfFile(ReportBindingModel model);
}
}

View File

@ -0,0 +1,23 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.SearchModels;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmContracts.BusinessLogicsContracts
{
public interface IShopLogic
{
List<ShopViewModel>? ReadList(ShopSearchModel? model);
ShopViewModel? ReadElement(ShopSearchModel model);
bool Create(ShopBindingModel model);
bool Update(ShopBindingModel model);
bool Delete(ShopBindingModel model);
bool SupplyDocuments(ShopSearchModel model, IDocumentModel document, int count);
bool SellDocument(IDocumentModel document, int count);
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmContracts.SearchModels
{
public class ShopSearchModel
{
public int? Id { get; set; }
public string? ShopName { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmContracts.SearchModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AbstractLawFirmDataModels.Models;
namespace AbstractLawFirmContracts.StoragesContracts
{
public interface IShopStorage
{
List<ShopViewModel> GetFullList();
List<ShopViewModel> GetFilteredList(ShopSearchModel model);
ShopViewModel? GetElement(ShopSearchModel model);
ShopViewModel? Insert(ShopBindingModel model);
ShopViewModel? Update(ShopBindingModel model);
ShopViewModel? Delete(ShopBindingModel model);
bool SellDocument(IDocumentModel model, int count);
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmContracts.ViewModels
{
public class ReportDateOrdersViewModel
{
public DateTime DateCreate { get; set; }
public int CountOrders { get; set; }
public double SumOrders { 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 AbstractLawFirmContracts.ViewModels
{
public class ReportShopDocumentsViewModel
{
public string ShopName { get; set; } = string.Empty;
public int Count { get; set; }
public List<Tuple<string, int>> Documents { get; set; } = new();
}
}

View File

@ -0,0 +1,32 @@
using AbstractLawFirmDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmContracts.ViewModels
{
public class ShopViewModel : IShopModel
{
public int Id { get; set; }
[DisplayName("Название магазина")]
public string ShopName { get; set; } = string.Empty;
[DisplayName("Адрес магазина")]
public string Address { get; set; } = string.Empty;
[DisplayName("Дата открытия")]
public DateTime OpeningDate { get; set; } = DateTime.Now;
public Dictionary<int, (IDocumentModel, int)> ShopDocuments
{
get;
set;
} = new();
[DisplayName("Максимальное количество пакетов документов в магазине")]
public int MaxCountDocuments { get; set; }
public List<Tuple<string, int>>? DocumentCount { get; set; } = new();
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmDataModels.Models
{
public interface IShopModel : IId
{
String ShopName { get; }
String Address { get; }
DateTime OpeningDate { get; }
Dictionary<int, (IDocumentModel, int)> ShopDocuments { get; }
int MaxCountDocuments { get; }
}
}

View File

@ -23,6 +23,8 @@ namespace AbstractLawFirmDatabaseImplement
public virtual DbSet<Document> Documents { set; get; }
public virtual DbSet<DocumentComponent> DocumentComponents { set; get; }
public virtual DbSet<Order> Orders { set; get; }
public virtual DbSet<Shop> Shops { set; get; }
public virtual DbSet<ShopDocument> ShopDocuments { set; get; }
public virtual DbSet<Client> Clients { set; get; }
public virtual DbSet<Implementer> Implementers { set; get; }
}

View File

@ -0,0 +1,138 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.SearchModels;
using AbstractLawFirmContracts.StoragesContracts;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmDataModels.Models;
using AbstractLawFirmDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmDatabaseImplement.Implements
{
public class ShopStorage : IShopStorage
{
public ShopViewModel? GetElement(ShopSearchModel model)
{
if (string.IsNullOrEmpty(model.ShopName) && !model.Id.HasValue)
{
return new();
}
using var context = new AbstractLawFirmDatabase();
return context.Shops.Include(x => x.Documents).ThenInclude(x => x.Document).FirstOrDefault(x =>
(!string.IsNullOrEmpty(model.ShopName) && x.ShopName == model.ShopName) ||
(model.Id.HasValue && x.Id == model.Id))?.GetViewModel;
}
public List<ShopViewModel> GetFilteredList(ShopSearchModel model)
{
if (string.IsNullOrEmpty(model.ShopName))
{
return new();
}
using var context = new AbstractLawFirmDatabase();
return context.Shops.Include(x => x.Documents).ThenInclude(x => x.Document).Where(x => x.ShopName.Contains(model.ShopName)).ToList().Select(x => x.GetViewModel).ToList();
}
public List<ShopViewModel> GetFullList()
{
using var context = new AbstractLawFirmDatabase();
return context.Shops.Include(x => x.Documents).ThenInclude(x => x.Document).ToList().Select(x => x.GetViewModel).ToList();
}
public ShopViewModel? Insert(ShopBindingModel model)
{
using var context = new AbstractLawFirmDatabase();
using var transaction = context.Database.BeginTransaction();
try
{
var newShop = Shop.Create(context, model);
if (newShop == null)
{
return null;
}
if (context.Shops.Any(x => x.ShopName == newShop.ShopName))
{
throw new Exception("Название магазина уже занято");
}
context.Shops.Add(newShop);
context.SaveChanges();
transaction.Commit();
return newShop.GetViewModel;
}
catch
{
transaction.Rollback();
throw;
}
}
public ShopViewModel? Update(ShopBindingModel model)
{
using var context = new AbstractLawFirmDatabase();
using var transaction = context.Database.BeginTransaction();
try
{
var shop = context.Shops.Include(x => x.Documents).FirstOrDefault(x => x.Id == model.Id);
if (shop == null)
{
return null;
}
shop.Update(model);
context.SaveChanges();
if (model.ShopDocuments.Count > 0)
{
shop.UpdateDocuments(context, model);
}
transaction.Commit();
return shop.GetViewModel;
}
catch
{
transaction.Rollback();
throw;
}
}
public ShopViewModel? Delete(ShopBindingModel model)
{
using var context = new AbstractLawFirmDatabase();
var shop = context.Shops.Include(x => x.Documents).FirstOrDefault(x => x.Id == model.Id);
if (shop != null)
{
context.Shops.Remove(shop);
context.SaveChanges();
return shop.GetViewModel;
}
return null;
}
public bool SellDocument(IDocumentModel model, int count)
{
using var context = new AbstractLawFirmDatabase();
using var transaction = context.Database.BeginTransaction();
foreach (var shopDocuments in context.ShopDocuments.Where(x => x.DocumentId == model.Id))
{
var min = Math.Min(count, shopDocuments.Count);
shopDocuments.Count -= min;
count -= min;
if (count <= 0)
{
break;
}
}
if (count == 0)
{
context.SaveChanges();
transaction.Commit();
}
else
transaction.Rollback();
if (count > 0)
return false;
return true;
}
}
}

View File

@ -0,0 +1,248 @@
// <auto-generated />
using System;
using AbstractLawFirmDatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AbstractLawFirmDatabaseImplement.Migrations
{
[DbContext(typeof(AbstractLawFirmDatabase))]
[Migration("20240324181609_Migr_for_lab3hard")]
partial class Migr_for_lab3hard
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.16")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Component", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ComponentName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Cost")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Components");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Document", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("DocumentName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("Id");
b.ToTable("Documents");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.DocumentComponent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("ComponentId")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("DocumentId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ComponentId");
b.HasIndex("DocumentId");
b.ToTable("DocumentComponents");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<DateTime>("DateCreate")
.HasColumnType("datetime2");
b.Property<DateTime?>("DateImplement")
.HasColumnType("datetime2");
b.Property<int>("DocumentId")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<double>("Sum")
.HasColumnType("float");
b.HasKey("Id");
b.HasIndex("DocumentId");
b.ToTable("Orders");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Shop", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("MaxCountDocuments")
.HasColumnType("int");
b.Property<DateTime>("OpeningDate")
.HasColumnType("datetime2");
b.Property<string>("ShopName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Shops");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.ShopDocument", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("DocumentId")
.HasColumnType("int");
b.Property<int>("ShopId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("DocumentId");
b.HasIndex("ShopId");
b.ToTable("ShopDocuments");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.DocumentComponent", b =>
{
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Component", "Component")
.WithMany("DocumentComponents")
.HasForeignKey("ComponentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Document", "Document")
.WithMany("Components")
.HasForeignKey("DocumentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("Document");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Order", b =>
{
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Document", "Document")
.WithMany("Orders")
.HasForeignKey("DocumentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Document");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.ShopDocument", b =>
{
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Document", "Document")
.WithMany()
.HasForeignKey("DocumentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Shop", "Shop")
.WithMany("Documents")
.HasForeignKey("ShopId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Document");
b.Navigation("Shop");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Component", b =>
{
b.Navigation("DocumentComponents");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Document", b =>
{
b.Navigation("Components");
b.Navigation("Orders");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Shop", b =>
{
b.Navigation("Documents");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,78 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AbstractLawFirmDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class Migr_for_lab3hard : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Shops",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ShopName = table.Column<string>(type: "nvarchar(max)", nullable: false),
Address = table.Column<string>(type: "nvarchar(max)", nullable: false),
OpeningDate = table.Column<DateTime>(type: "datetime2", nullable: false),
MaxCountDocuments = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Shops", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ShopDocuments",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
DocumentId = table.Column<int>(type: "int", nullable: false),
ShopId = table.Column<int>(type: "int", nullable: false),
Count = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ShopDocuments", x => x.Id);
table.ForeignKey(
name: "FK_ShopDocuments_Documents_DocumentId",
column: x => x.DocumentId,
principalTable: "Documents",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ShopDocuments_Shops_ShopId",
column: x => x.ShopId,
principalTable: "Shops",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ShopDocuments_DocumentId",
table: "ShopDocuments",
column: "DocumentId");
migrationBuilder.CreateIndex(
name: "IX_ShopDocuments_ShopId",
table: "ShopDocuments",
column: "ShopId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ShopDocuments");
migrationBuilder.DropTable(
name: "Shops");
}
}
}

View File

@ -183,6 +183,59 @@ namespace AbstractLawFirmDatabaseImplement.Migrations
b.ToTable("Orders");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Shop", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int>("MaxCountDocuments")
.HasColumnType("int");
b.Property<DateTime>("OpeningDate")
.HasColumnType("datetime2");
b.Property<string>("ShopName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Shops");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.ShopDocument", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("DocumentId")
.HasColumnType("int");
b.Property<int>("ShopId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("DocumentId");
b.HasIndex("ShopId");
b.ToTable("ShopDocuments");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.DocumentComponent", b =>
{
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Component", "Component")
@ -216,6 +269,23 @@ namespace AbstractLawFirmDatabaseImplement.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Document");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.ShopDocument", b =>
{
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Document", "Document")
.WithMany()
.HasForeignKey("DocumentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Shop", "Shop")
.WithMany("Documents")
.HasForeignKey("ShopId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AbstractLawFirmDatabaseImplement.Models.Implementer", "Implementer")
.WithMany("Orders")
.HasForeignKey("ImplementerId");
@ -224,6 +294,8 @@ namespace AbstractLawFirmDatabaseImplement.Migrations
b.Navigation("Document");
b.Navigation("Shop");
b.Navigation("Implementer");
});
@ -248,6 +320,11 @@ namespace AbstractLawFirmDatabaseImplement.Migrations
{
b.Navigation("Orders");
});
modelBuilder.Entity("AbstractLawFirmDatabaseImplement.Models.Shop", b =>
{
b.Navigation("Documents");
});
#pragma warning restore 612, 618
}
}

View File

@ -0,0 +1,114 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmDatabaseImplement.Models
{
public class Shop : IShopModel
{
public int Id { get; set; }
[Required]
public string ShopName { get; set; } = string.Empty;
[Required]
public string Address { get; set; } = string.Empty;
[Required]
public DateTime OpeningDate { get; set; }
[ForeignKey("ShopId")]
public List<ShopDocument> Documents { get; set; } = new();
private Dictionary<int, (IDocumentModel, int)>? _shopDocuments = null;
[NotMapped]
public Dictionary<int, (IDocumentModel, int)> ShopDocuments
{
get
{
if (_shopDocuments == null)
{
_shopDocuments = Documents.ToDictionary(recPC => recPC.DocumentId, recPC => (recPC.Document as IDocumentModel, recPC.Count));
}
return _shopDocuments;
}
}
[Required]
public int MaxCountDocuments { get; set; }
public static Shop Create(AbstractLawFirmDatabase context, ShopBindingModel model)
{
return new Shop()
{
Id = model.Id,
ShopName = model.ShopName,
Address = model.Address,
OpeningDate = model.OpeningDate,
Documents = model.ShopDocuments.Select(x => new ShopDocument
{
Document = context.Documents.First(y => y.Id == x.Key),
Count = x.Value.Item2
}).ToList(),
MaxCountDocuments = model.MaxCountDocuments
};
}
public void Update(ShopBindingModel model)
{
ShopName = model.ShopName;
Address = model.Address;
OpeningDate = model.OpeningDate;
MaxCountDocuments = model.MaxCountDocuments;
}
public ShopViewModel GetViewModel => new()
{
Id = Id,
ShopName = ShopName,
Address = Address,
OpeningDate = OpeningDate,
ShopDocuments = ShopDocuments,
MaxCountDocuments = MaxCountDocuments
};
public void UpdateDocuments(AbstractLawFirmDatabase context, ShopBindingModel model)
{
var ShopDocuments = context.ShopDocuments.Where(rec => rec.ShopId == model.Id).ToList();
if (ShopDocuments != null && ShopDocuments.Count > 0)
{
// удалили те, которых нет в модели
context.ShopDocuments.RemoveRange(ShopDocuments.Where(rec => !model.ShopDocuments.ContainsKey(rec.DocumentId)));
context.SaveChanges();
ShopDocuments = context.ShopDocuments.Where(rec => rec.ShopId == model.Id).ToList();
// обновили количество у существующих записей
foreach (var updateDocument in ShopDocuments)
{
updateDocument.Count = model.ShopDocuments[updateDocument.DocumentId].Item2;
model.ShopDocuments.Remove(updateDocument.DocumentId);
}
context.SaveChanges();
}
var shop = context.Shops.First(x => x.Id == Id);
foreach (var elem in model.ShopDocuments)
{
context.ShopDocuments.Add(new ShopDocument
{
Shop = shop,
Document = context.Documents.First(x => x.Id == elem.Key),
Count = elem.Value.Item2
});
context.SaveChanges();
}
_shopDocuments = null;
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmDatabaseImplement.Models
{
public class ShopDocument
{
public int Id { get; set; }
[Required]
public int DocumentId { get; set; }
[Required]
public int ShopId { get; set; }
[Required]
public int Count { get; set; }
public virtual Shop Shop { get; set; } = new();
public virtual Document Document { get; set; } = new();
}
}

View File

@ -14,11 +14,14 @@ namespace AbstractLawFirmFileImplement
private readonly string ComponentFileName = "Component.xml";
private readonly string OrderFileName = "Order.xml";
private readonly string DocumentFileName = "Document.xml";
private readonly string ShopFileName = "Shop.xml";
private readonly string ClientFileName = "Client.xml";
private readonly string ImplementerFileName = "Implementer.xml";
public List<Component> Components { get; private set; }
public List<Order> Orders { get; private set; }
public List<Document> Documents { get; private set; }
public List<Shop> Shops { get; private set; }
public List<Client> Clients { get; private set; }
public List<Implementer> Implementers { get; private set; }
public static DataFileSingleton GetInstance()
@ -32,6 +35,7 @@ namespace AbstractLawFirmFileImplement
public void SaveComponents() => SaveData(Components, ComponentFileName, "Components", x => x.GetXElement);
public void SaveDocuments() => SaveData(Documents, DocumentFileName, "Documents", x => x.GetXElement);
public void SaveOrders() => SaveData(Orders, OrderFileName, "Orders", x => x.GetXElement);
public void SaveShops() => SaveData(Shops, ShopFileName, "Shops", x => x.GetXElement);
public void SaveClients() => SaveData(Clients, ClientFileName, "Clients", x => x.GetXElement);
public void SaveImplementers() => SaveData(Orders, ImplementerFileName, "Implementers", x => x.GetXElement);
private DataFileSingleton()
@ -39,6 +43,7 @@ namespace AbstractLawFirmFileImplement
Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!;
Documents = LoadData(DocumentFileName, "Document", x => Document.Create(x)!)!;
Orders = LoadData(OrderFileName, "Order", x => Order.Create(x)!)!;
Shops = LoadData(ShopFileName, "Shop", x => Shop.Create(x)!)!;
Clients = LoadData(ClientFileName, "Client", x => Client.Create(x)!)!;
Implementers = LoadData(ImplementerFileName, "Impleneter", x => Implementer.Create(x)!)!;
}

View File

@ -0,0 +1,137 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.SearchModels;
using AbstractLawFirmContracts.StoragesContracts;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmDataModels.Models;
using AbstractLawFirmFileImplement.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmFileImplement.Implements
{
public class ShopStorage : IShopStorage
{
private readonly DataFileSingleton source;
public ShopStorage()
{
source = DataFileSingleton.GetInstance();
}
public ShopViewModel? GetElement(ShopSearchModel model)
{
if (!model.Id.HasValue)
{
return null;
}
return source.Shops.FirstOrDefault(x => model.Id.HasValue && x.Id == model.Id)?.GetViewModel;
}
public List<ShopViewModel> GetFilteredList(ShopSearchModel model)
{
if (string.IsNullOrEmpty(model.ShopName))
{
return new();
}
return source.Shops
.Select(x => x.GetViewModel)
.Where(x => x.ShopName.Contains(model.ShopName ?? string.Empty))
.ToList();
}
public List<ShopViewModel> GetFullList()
{
return source.Shops.Select(shop => shop.GetViewModel).ToList();
}
public ShopViewModel? Insert(ShopBindingModel model)
{
model.Id = source.Shops.Count > 0 ? source.Shops.Max(x => x.Id) + 1 : 1;
var newShop = Shop.Create(model);
if (newShop == null)
{
return null;
}
source.Shops.Add(newShop);
source.SaveShops();
return newShop.GetViewModel;
}
public ShopViewModel? Update(ShopBindingModel model)
{
var shop = source.Shops.FirstOrDefault(x => x.Id == model.Id);
if (shop == null)
{
return null;
}
shop.Update(model);
source.SaveShops();
return shop.GetViewModel;
}
public ShopViewModel? Delete(ShopBindingModel model)
{
var shop = source.Shops.FirstOrDefault(x => x.Id == model.Id);
if (shop == null)
{
return null;
}
source.Shops.Remove(shop);
source.SaveShops();
return shop.GetViewModel;
}
public bool SellDocument(IDocumentModel model, int count)
{
var document = source.Documents.FirstOrDefault(x => x.Id == model.Id);
if (document == null)
{
return false;
}
var shopDocuments = source.Shops.SelectMany(shop => shop.ShopDocuments.Where(c => c.Value.Item1.Id == document.Id));
int countStore = 0;
foreach (var it in shopDocuments)
countStore += it.Value.Item2;
if (count > countStore)
return false;
foreach (var shop in source.Shops)
{
var documents = shop.ShopDocuments;
foreach (var c in documents.Where(x => x.Value.Item1.Id == document.Id))
{
int min = Math.Min(c.Value.Item2, count);
documents[c.Value.Item1.Id] = (c.Value.Item1, c.Value.Item2 - min);
count -= min;
if (count <= 0)
break;
}
shop.Update(new ShopBindingModel
{
Id = shop.Id,
ShopName = shop.ShopName,
Address = shop.Address,
MaxCountDocuments = shop.MaxCountDocuments,
OpeningDate = shop.OpeningDate,
ShopDocuments = documents
});
source.SaveShops();
if (count <= 0)
return true;
}
return true;
}
}
}

View File

@ -0,0 +1,113 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace AbstractLawFirmFileImplement.Models
{
public class Shop : IShopModel
{
public int Id { get; private set; }
public string ShopName { get; private set; } = string.Empty;
public string Address { get; private set; } = string.Empty;
public int MaxCountDocuments { get; private set; }
public DateTime OpeningDate { get; private set; }
public Dictionary<int, int> Documents { get; private set; } = new();
private Dictionary<int, (IDocumentModel, int)>? _shopDocuments = null;
public Dictionary<int, (IDocumentModel, int)> ShopDocuments
{
get
{
if (_shopDocuments == null)
{
var source = DataFileSingleton.GetInstance();
_shopDocuments = Documents.ToDictionary(
x => x.Key,
y => ((source.Documents.FirstOrDefault(z => z.Id == y.Key) as IDocumentModel)!, y.Value)
);
}
return _shopDocuments;
}
}
public static Shop? Create(ShopBindingModel? model)
{
if (model == null)
{
return null;
}
return new Shop()
{
Id = model.Id,
ShopName = model.ShopName,
Address = model.Address,
MaxCountDocuments = model.MaxCountDocuments,
OpeningDate = model.OpeningDate,
Documents = model.ShopDocuments.ToDictionary(x => x.Key, x => x.Value.Item2)
};
}
public static Shop? Create(XElement element)
{
if (element == null)
{
return null;
}
return new Shop()
{
Id = Convert.ToInt32(element.Attribute("Id")!.Value),
ShopName = element.Element("ShopName")!.Value,
Address = element.Element("Address")!.Value,
MaxCountDocuments = Convert.ToInt32(element.Element("MaxCountDocuments")!.Value),
OpeningDate = Convert.ToDateTime(element.Element("OpeningDate")!.Value),
Documents = element.Element("ShopDocuments")!.Elements("ShopDocument").ToDictionary(
x => Convert.ToInt32(x.Element("Key")?.Value),
x => Convert.ToInt32(x.Element("Value")?.Value)
)
};
}
public void Update(ShopBindingModel? model)
{
if (model == null)
{
return;
}
ShopName = model.ShopName;
Address = model.Address;
MaxCountDocuments = model.MaxCountDocuments;
OpeningDate = model.OpeningDate;
if (model.ShopDocuments.Count > 0)
{
Documents = model.ShopDocuments.ToDictionary(x => x.Key, x => x.Value.Item2);
_shopDocuments = null;
}
}
public ShopViewModel GetViewModel => new()
{
Id = Id,
ShopName = ShopName,
Address = Address,
MaxCountDocuments = MaxCountDocuments,
OpeningDate = OpeningDate,
ShopDocuments = ShopDocuments,
};
public XElement GetXElement => new(
"Shop",
new XAttribute("Id", Id),
new XElement("ShopName", ShopName),
new XElement("Address", Address),
new XElement("MaxCountDocuments", MaxCountDocuments),
new XElement("OpeningDate", OpeningDate.ToString()),
new XElement("ShopDocuments", Documents.Select(x =>
new XElement("ShopDocument",
new XElement("Key", x.Key),
new XElement("Value", x.Value)))
.ToArray()));
}
}

View File

@ -13,6 +13,7 @@ namespace AbstractLawFirmListImplement
public List<Component> Components { get; set; }
public List<Order> Orders { get; set; }
public List<Document> Documents { get; set; }
public List<Shop> Shops { get; set; }
public List<Client> Clients { get; set; }
public List<Implementer> Implementers { get; set; }
private DataListSingleton()
@ -20,6 +21,7 @@ namespace AbstractLawFirmListImplement
Components = new List<Component>();
Orders = new List<Order>();
Documents = new List<Document>();
Shops = new List<Shop>();
Clients = new List<Client>();
Implementers = new List<Implementer>();
}

View File

@ -0,0 +1,123 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.SearchModels;
using AbstractLawFirmContracts.StoragesContracts;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmListImplement.Models;
using AbstractLawFirmDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmListImplement.Implements
{
public class ShopStorage : IShopStorage
{
private readonly DataListSingleton _source;
public bool SellDocument(IDocumentModel document, int count)
{
throw new NotImplementedException();
}
public ShopStorage()
{
_source = DataListSingleton.GetInstance();
}
public ShopViewModel? GetElement(ShopSearchModel model)
{
if (string.IsNullOrEmpty(model.ShopName) && !model.Id.HasValue)
{
return null;
}
foreach (var shop in _source.Shops)
{
if ((!string.IsNullOrEmpty(model.ShopName) && shop.ShopName == model.ShopName) || (model.Id.HasValue && shop.Id == model.Id))
{
return shop.GetViewModel;
}
}
return null;
}
public List<ShopViewModel> GetFilteredList(ShopSearchModel model)
{
var result = new List<ShopViewModel>();
if (string.IsNullOrEmpty(model.ShopName))
{
return result;
}
foreach (var shop in _source.Shops)
{
if (shop.ShopName.Contains(model.ShopName))
{
result.Add(shop.GetViewModel);
}
}
return result;
}
public List<ShopViewModel> GetFullList()
{
var result = new List<ShopViewModel>();
foreach (var shop in _source.Shops)
{
result.Add(shop.GetViewModel);
}
return result;
}
public ShopViewModel? Insert(ShopBindingModel model)
{
model.Id = 1;
foreach (var shop in _source.Shops)
{
if (model.Id <= shop.Id)
{
model.Id = shop.Id + 1;
}
}
var newShop = Shop.Create(model);
if (newShop == null)
{
return null;
}
_source.Shops.Add(newShop);
return newShop.GetViewModel;
}
public ShopViewModel? Update(ShopBindingModel model)
{
foreach (var shop in _source.Shops)
{
if (shop.Id == model.Id)
{
shop.Update(model);
return shop.GetViewModel;
}
}
return null;
}
public ShopViewModel? Delete(ShopBindingModel model)
{
for (int i = 0; i < _source.Shops.Count; ++i)
{
if (_source.Shops[i].Id == model.Id)
{
var element = _source.Shops[i];
_source.Shops.RemoveAt(i);
return element.GetViewModel;
}
}
return null;
}
}
}

View File

@ -0,0 +1,61 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AbstractLawFirmListImplement.Models
{
public class Shop : IShopModel
{
public int Id { get; private set; }
public string ShopName { get; private set; } = string.Empty;
public string Address { get; private set; } = string.Empty;
public int MaxCountDocuments { get; private set; }
public DateTime OpeningDate { get; private set; }
public Dictionary<int, (IDocumentModel, int)> ShopDocuments
{
get;
private set;
} = new Dictionary<int, (IDocumentModel, int)>();
public static Shop? Create(ShopBindingModel? model)
{
if (model == null)
{
return null;
}
return new Shop()
{
Id = model.Id,
ShopName = model.ShopName,
Address = model.Address,
OpeningDate = model.OpeningDate,
ShopDocuments = model.ShopDocuments
};
}
public void Update(ShopBindingModel? model)
{
if (model == null)
{
return;
}
ShopName = model.ShopName;
Address = model.Address;
OpeningDate = model.OpeningDate;
ShopDocuments = model.ShopDocuments;
}
public ShopViewModel GetViewModel => new()
{
Id = Id,
ShopName = ShopName,
Address = Address,
OpeningDate = OpeningDate,
ShopDocuments = ShopDocuments
};
}
}

View File

@ -0,0 +1,113 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.BusinessLogicsContracts;
using AbstractLawFirmContracts.SearchModels;
using AbstractLawFirmContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace AbstractLawFirmRestApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ShopController : Controller
{
private readonly ILogger _logger;
private readonly IShopLogic _shop;
public ShopController(ILogger<ShopController> logger, IShopLogic shopLogic)
{
_logger = logger;
_shop = shopLogic;
}
[HttpGet]
public List<ShopViewModel>? GetShopList()
{
try
{
List<ShopViewModel> shops = _shop.ReadList(null);
for (int i = 0; i < shops.Count; i++)
shops[i].DocumentCount = shops[i].ShopDocuments.Values.ToList().Select(x => (x.Item1.DocumentName, x.Item2).ToTuple()).ToList();
return shops;
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения списка магазинов");
throw;
}
}
[HttpGet]
public ShopViewModel? GetShop(int shopId)
{
try
{
return _shop.ReadElement(new ShopSearchModel
{
Id = shopId
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения магазина по id={Id}", shopId);
throw;
}
}
[HttpPost]
public void CreateShop(ShopBindingModel model)
{
try
{
_shop.Create(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка создания магазина");
throw;
}
}
[HttpPost]
public void UpdateShop(ShopBindingModel model)
{
try
{
_shop.Update(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка обновления магазина");
throw;
}
}
[HttpPost]
public void DeleteShop(ShopBindingModel model)
{
try
{
_shop.Delete(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка удаления магазина");
throw;
}
}
[HttpPost]
public void SupplyDocumentsToShop(Tuple<ShopSearchModel, DocumentBindingModel, int> supplyRequest)
{
try
{
_shop.SupplyDocuments(supplyRequest.Item1, supplyRequest.Item2, supplyRequest.Item3);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка пополнения магазина");
throw;
}
}
}
}

View File

@ -13,9 +13,11 @@ builder.Logging.AddLog4Net("log4net.config");
builder.Services.AddTransient<IClientStorage, ClientStorage>();
builder.Services.AddTransient<IOrderStorage, OrderStorage>();
builder.Services.AddTransient<IDocumentStorage, DocumentStorage>();
builder.Services.AddTransient<IShopStorage, ShopStorage>();
builder.Services.AddTransient<IOrderLogic, OrderLogic>();
builder.Services.AddTransient<IClientLogic, ClientLogic>();
builder.Services.AddTransient<IDocumentLogic, DocumentLogic>();
builder.Services.AddTransient<IShopLogic, ShopLogic>();
builder.Services.AddTransient<IImplementerStorage, ImplementerStorage>();
builder.Services.AddTransient<IImplementerLogic, ImplementerLogic>();
builder.Services.AddControllers();
@ -37,8 +39,7 @@ var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json",
"AbstractLawFirmRestApi v1"));
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json","AbstractLawFirmRestApi v1"));
}
app.UseHttpsRedirection();

View File

@ -0,0 +1,44 @@
using Newtonsoft.Json;
using System.Net.Http.Headers;
using System.Text;
namespace AbstractLawFirmShopApp
{
public static class APIClient
{
private static readonly HttpClient _client = new();
public static bool isAuth { get; set; } = false;
public static string ConfigPassword { get; private set; } = string.Empty;
public static void Connect(IConfiguration configuration)
{
ConfigPassword = configuration["Password"];
_client.BaseAddress = new Uri(configuration["IPAddress"]);
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public static T? GetRequest<T>(string requestUrl)
{
var response = _client.GetAsync(requestUrl);
var result = response.Result.Content.ReadAsStringAsync().Result;
if (response.Result.IsSuccessStatusCode)
{
return JsonConvert.DeserializeObject<T>(result);
}
else
{
throw new Exception(result);
}
}
public static void PostRequest<T>(string requestUrl, T model)
{
var json = JsonConvert.SerializeObject(model);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var response = _client.PostAsync(requestUrl, data);
var result = response.Result.Content.ReadAsStringAsync().Result;
if (!response.Result.IsSuccessStatusCode)
{
throw new Exception(result);
}
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AbstractLawFirmContracts\AbstractLawFirmContracts\AbstractLawFirmContracts.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,157 @@
using AbstractLawFirmContracts.BindingModels;
using AbstractLawFirmContracts.SearchModels;
using AbstractLawFirmContracts.ViewModels;
using AbstractLawFirmShopApp.Models;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
namespace AbstractLawFirmShopApp.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
if (!APIClient.isAuth)
{
return Redirect("~/Home/Enter");
}
return View(APIClient.GetRequest<List<ShopViewModel>>($"api/shop/getshoplist"));
}
public IActionResult Privacy()
{
if (!APIClient.isAuth)
{
return Redirect("~/Home/Enter");
}
return View();
}
[HttpGet]
public IActionResult Enter()
{
return View();
}
[HttpPost]
public void Enter(string password)
{
if (string.IsNullOrEmpty(password))
{
throw new Exception("Введите пароль");
}
if (!password.Equals(APIClient.ConfigPassword))
{
throw new Exception("Неверный пароль");
}
APIClient.isAuth = true;
Response.Redirect("Index");
}
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public void Create(string name, string address, DateTime openingDate, int count)
{
if (!APIClient.isAuth)
{
throw new Exception("Вы как суда попали? Суда вход только авторизованным");
}
if (count <= 0)
{
throw new Exception("Макс. кол-во док-ов должно быть больше чем 0");
}
APIClient.PostRequest("api/shop/createshop", new ShopBindingModel
{
ShopName = name,
Address = address,
OpeningDate = openingDate,
MaxCountDocuments = count,
});
Response.Redirect("Index");
}
[HttpGet]
public IActionResult Delete()
{
ViewBag.Shops = APIClient.GetRequest<List<ShopViewModel>>("api/shop/getshoplist");
return View();
}
[HttpPost]
public void Delete(int shop)
{
if (!APIClient.isAuth)
{
throw new Exception("Вы как суда попали? Суда вход только авторизованным");
}
APIClient.PostRequest($"api/shop/deleteshop", new ShopBindingModel { Id = shop });
Response.Redirect("Index");
}
[HttpGet]
public IActionResult Update()
{
ViewBag.Shops = APIClient.GetRequest<List<ShopViewModel>>("api/shop/getshoplist");
return View();
}
[HttpPost]
public void Update(int shop, string name, string address, DateTime openingDate, int count)
{
if (!APIClient.isAuth)
{
throw new Exception("Вы как суда попали? Суда вход только авторизованным");
}
APIClient.PostRequest($"api/shop/updateshop", new ShopBindingModel
{
Id = shop,
ShopName = name,
Address = address,
OpeningDate = openingDate,
MaxCountDocuments = count,
}
);
Response.Redirect("Index");
}
[HttpGet]
public ShopViewModel? GetShop(int shopId)
{
return APIClient.GetRequest<ShopViewModel>($"api/shop/getshop?shopId={shopId}");
}
public IActionResult Supply()
{
ViewBag.Shops = APIClient.GetRequest<List<ShopViewModel>>("api/shop/getshoplist");
ViewBag.Documents = APIClient.GetRequest<List<DocumentViewModel>>("api/main/getdocumentlist");
return View();
}
[HttpPost]
public void Supply(int shopId, int documentId, int count)
{
if (!APIClient.isAuth)
{
throw new Exception("Вы как суда попали? Суда вход только авторизованным");
}
APIClient.PostRequest($"api/shop/supplydocumentstoshop", (new ShopSearchModel { Id = shopId }, new DocumentBindingModel { Id = documentId }, count));
Response.Redirect("Index");
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

View File

@ -0,0 +1,9 @@
namespace AbstractLawFirmShopApp.Models
{
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

View File

@ -0,0 +1,31 @@
using AbstractLawFirmShopApp;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
APIClient.Connect(builder.Configuration);
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

View File

@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:54844",
"sslPort": 44351
}
},
"profiles": {
"AbstractLawFirmShopApp": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7108;http://localhost:5036",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,32 @@
@{
ViewData["Title"] = "Create";
}
<div class="text-center">
<h2 class="display-4 mb-5">Создание магазина</h2>
</div>
<form method="post">
<div class="row mb-5">
<div class="col-4">Название:</div>
<div class="col-8"><input type="text" name="name" id="name" /></div>
</div>
<div class="row mb-5">
<div class="col-4">Дата открытия:</div>
<div class="col-8">
<input type="date" id="openingDate" name="openingDate" /></div>
</div>
<div class="row mb-5">
<div class="col-4">Адрес:</div>
<div class="col-8"><input type="text" id="address" name="address" /></div>
</div>
<div class="row mb-5">
<div class="col-4">Макс. документов:</div>
<div class="col-8"><input type="number" id="count" name="count" /></div>
</div>
<div class="row mb-5">
<div class="col-8">
</div>
<div class="col-4">
<input type="submit" value="Создать" class="btn btn-success" />
</div>
</div>
</form>

View File

@ -0,0 +1,17 @@
@{
ViewData["Title"] = "Delete";
}
<div class="text-center">
<h2 class="display-4">Удаление магазина</h2>
</div>
<form method="post">
<div class="row">
<div class="col-4">Название:</div>
<div class="col-8">
<select id="shop" name="shop" class="form-control" asp-items="@(new SelectList(@ViewBag.Shops,"Id", "Name"))"></select>
</div>
</div>
<div class="col-4">
<input type="submit" value="Удалить" class="btn btn-danger" />
</div>
</form>

View File

@ -0,0 +1,15 @@
@{
ViewData["Title"] = "Enter";
}
<div class="text-center mb-5">
<h2 class="display-4">Авторизация</h2>
</div>
<form method="post">
<div class="row text-center mb-5">
<div class="mb-3 h4">Введите пароль:</div>
<div><input type="password" name="password"/></div>
</div>
<div class="row text-center">
<div><input type="submit" value="Войти" class="btn btn-success ps-5 pe-5" /></div>
</div>
</form>

View File

@ -0,0 +1,57 @@
@using AbstractLawFirmContracts.ViewModels
@model List<ShopViewModel>
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Магазины</h1>
</div>
<div class="text-center">
@{
if (Model == null)
{
<h3 class="display-4">Авторизируйтесь</h3>
return;
}
<p >
<a class="text-decoration-none me-3 text-black h5" asp-action="Create">Создать магазин</a>
<a class="text-decoration-none me-3 text-black h5" asp-action="Update">Изменить магазин</a>
<a class="text-decoration-none me-3 text-black h5" asp-action="Supply">Пополнить магазин</a>
<a class="text-decoration-none text-black h5" asp-action="Delete">Удалить магазин</a>
</p>
<table class="table">
<thead>
<tr>
<th>Номер</th>
<th>Название</th>
<th>Адрес</th>
<th>Дата открытия</th>
<th>Макс. док-ов</th>
</tr>
</thead>
<tbody>
@foreach (var shop in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => shop.Id)
</td>
<td>
@Html.DisplayFor(modelItem => shop.ShopName)
</td>
<td>
@Html.DisplayFor(modelItem => shop.Address)
</td>
<td>
@Html.DisplayFor(modelItem => shop.OpeningDate)
</td>
<td>
@Html.DisplayFor(modelItem => shop.MaxCountDocuments)
</td>
</tr>
}
</tbody>
</table>
}
</div>

View File

@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

@ -0,0 +1,29 @@
 @{
ViewData["Title"] = "Supply";
}
<div class="text-center mb-5">
<h2 class="display-4">Пополнение магазина</h2>
</div>
<form method="post">
<div class="row mb-5">
<div class="col-4">Название магазина:</div>
<div class="col-8 ">
<select id="shopId" name="shopId" class="form-control" asp-items="@(new SelectList(@ViewBag.Shops,"Id", "ShopName"))"></select>
</div>
</div>
<div class="row mb-5">
<div class="col-4">Документ:</div>
<div class="col-8">
<select id="documentId" name="documentId" class="form-control" asp-items="@(new SelectList(@ViewBag.Documents,"Id", "DocumentName"))"></select>
</div>
</div>
<div class="row mb-5">
<div class="col-4">Количество:</div>
<div class="col-8">
<input type="text" name="count" id="count" />
</div>
</div>
<div class="col-4">
<input type="submit" value="Пополнить" class="btn btn-success" />
</div>
</form>

View File

@ -0,0 +1,77 @@
@{
ViewData["Title"] = "Update";
}
<div class="text-center">
<h2 class="display-4 mb-5">Изменение магазина</h2>
</div>
<form method="post">
<div class="row mb-3">
<div class="col-4">Магазин:</div>
<div class="col-8">
<select id="shop" name="shop" onchange="getData()" class="form-control" asp-items="@(new SelectList(@ViewBag.Shops,"Id", "ShopName"))"></select>
</div>
</div>
<div class="row mb-3">
<div class="col-4">Название:</div>
<div class="col-8"><input type="text" name="shopName" id="shopName" /></div>
</div>
<div class="row mb-3">
<div class="col-4">Адрес:</div>
<div class="col-8"><input type="text" id="address" name="address" /></div>
</div>
<div class="row mb-3">
<div class="col-4">Дата открытия:</div>
<div class="col-8">
<input type="datetime-local" id="openingDate" name="openingDate" />
</div>
</div>
<div class="row mb-3">
<div class="col-4">Макс. док-ов:</div>
<div class="col-8"><input type="number" id="count" name="count" /></div>
</div>
<div class="row mb-3">
<div class="col-4">Док-ты в магазине:</div>
<div class="col-8">
<table class="table">
<thead>
<tr>
<th>Документ</th>
<th>Количество</th>
</tr>
</thead>
<tbody id="documentTable">
</tbody>
</table>
</div>
</div>
<div class="text-center ">
<input type="submit" value="Принять" class="btn btn-success ps-5 pe-5" />
</div>
</form>
<script>
function getData() {
var shopId = $('#shop').val();
var shopData = @Html.Raw(Json.Serialize(ViewBag.Shops));
var selectedShop = shopData.find(function (shop) {
return shop.id == shopId;
});
if (selectedShop) {
$("#shopName").val(selectedShop.shopName);
$("#openingDate").val(new Date(selectedShop.openingDate).toISOString().substring(0, 16));
$("#address").val(selectedShop.address);
$("#count").val(selectedShop.maxCountDocuments);
fillTable(selectedShop.documentCount);
}
}
function fillTable(shopDocuments) {
$("#documentTable").empty();
for (var doc in shopDocuments)
$("#documentTable").append('<tr><td>' + shopDocuments[doc].item1 + '</td><td>' + shopDocuments[doc].item2 + '</td></tr>');
}
</script>

View File

@ -0,0 +1,25 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - AbstractLawFirmShopApp</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/LawFirmShopApp.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">LawFirmShopApp</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2024 - LawFirmShopApp - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>

View File

@ -0,0 +1,48 @@
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
a {
color: #0077cc;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
}

View File

@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

View File

@ -0,0 +1,3 @@
@using AbstractLawFirmShopApp
@using AbstractLawFirmShopApp.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

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

View File

@ -0,0 +1,11 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"IPAddress": "http://localhost:5134/",
"Password": "password"
}

View File

@ -0,0 +1,18 @@
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 60px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,4 @@
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2021 Twitter, Inc.
Copyright (c) 2011-2021 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,427 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,424 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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