Compare commits
140 Commits
BeforeMain
...
main
Author | SHA1 | Date | |
---|---|---|---|
385937ee68 | |||
55a9363a09 | |||
1aca0b53bb | |||
256f8f98af | |||
e4e9447a0b | |||
f07b35cd87 | |||
10fb62b17e | |||
d5438a4090 | |||
85f38e9539 | |||
b48124b0b9 | |||
6f449c505b | |||
60c507bb4b | |||
2f80dcf920 | |||
c15757969f | |||
ce13c36817 | |||
1258a43786 | |||
51c8a7da5a | |||
b426a6373d | |||
38f53ae91e | |||
5bd38a465f | |||
ed4a896db8 | |||
842531bccd | |||
9e470873d8 | |||
13f475d64b | |||
cd21f23715 | |||
9c61562368 | |||
2b92074b02 | |||
66292d362b | |||
d43bff822f | |||
67257c30ca | |||
3afab0dee9 | |||
610c76a402 | |||
b686555cf7 | |||
f6657eaa0d | |||
acdd3e1554 | |||
5333817ea8 | |||
a166e976de | |||
4997506a44 | |||
e376e9d8f2 | |||
2bec90ed3d | |||
41f189f0ee | |||
8ed579f623 | |||
64bdab2d57 | |||
f3d161527a | |||
fe06bc28e1 | |||
f1a9439c55 | |||
786d2de669 | |||
5a027d33ef | |||
47534e6672 | |||
fbff900bef | |||
e343e4638f | |||
f663bfe663 | |||
b64aa50fc8 | |||
70f28e3c66 | |||
d3b455117e | |||
b84b593b88 | |||
d498e507ff | |||
f032fc0f44 | |||
8cc02e4532 | |||
a2b22658c3 | |||
10271ea4bd | |||
0f35bf9e19 | |||
f8845a84c0 | |||
011fa8a2c3 | |||
bfc1dc3313 | |||
a3bd2346ca | |||
7ee3f34450 | |||
1774b0c758 | |||
190968e7b5 | |||
70e9005df6 | |||
bc7055257d | |||
cade6df340 | |||
4684d4665b | |||
aeef227dfc | |||
70ae0159af | |||
b984fdfb05 | |||
b3d59578e7 | |||
f72779704e | |||
b9119331fe | |||
4121d5ec1c | |||
1c79c41e0f | |||
ffe3f57242 | |||
f6c5157c5d | |||
b0ea2fb11e | |||
a6aa2d3e35 | |||
a48d6d1e44 | |||
856735868d | |||
a7b13bef7a | |||
34849c0377 | |||
417a8c9dcf | |||
879d0d858b | |||
923d110e40 | |||
0b0e6abcde | |||
db7f79ed81 | |||
07ebb8d635 | |||
3244f9d2ea | |||
51a8119546 | |||
6011ed3f90 | |||
b1f517a3e2 | |||
eb08556e88 | |||
576d8eef75 | |||
1ea5be4788 | |||
d3b137fbdb | |||
6dd59c47ad | |||
ce1fd40875 | |||
1c67a1004f | |||
c2d673f9a3 | |||
0f7148fbe5 | |||
76c9fa6580 | |||
5c849f7d59 | |||
ea30411791 | |||
0a57d3ebf3 | |||
bab1b63323 | |||
2a7782eea0 | |||
998e352d2d | |||
ff8041fe1a | |||
2e505618bc | |||
1bcd3a5d0b | |||
8cddd1067c | |||
26966f9c8c | |||
d0aa59742c | |||
800a21389a | |||
88504d8bf1 | |||
0d9306c597 | |||
f749e8fcb4 | |||
3db96eaaa1 | |||
6789b86723 | |||
4e6b34a77d | |||
e7fff05911 | |||
3dd37697c8 | |||
2debfe4ba8 | |||
cf82bd4fe7 | |||
03d8c6db0a | |||
ff2f0d57db | |||
1160862303 | |||
8203d22849 | |||
934080cd54 | |||
c4c8069645 | |||
410ee5cb9f | |||
9ab410c5af |
@ -1,5 +1,5 @@
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.BuisnessLogicsContracts;
|
||||
using HardwareShopContracts.BusinessLogicsContracts;
|
||||
using HardwareShopContracts.SearchModels;
|
||||
using HardwareShopContracts.StoragesContracts;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
@ -1,5 +1,5 @@
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.BuisnessLogicsContracts;
|
||||
using HardwareShopContracts.BusinessLogicsContracts;
|
||||
using HardwareShopContracts.SearchModels;
|
||||
using HardwareShopContracts.StoragesContracts;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
@ -120,5 +120,17 @@ namespace HardwareShopBusinessLogic.BusinessLogics.Storekeeper
|
||||
{
|
||||
return StatusUpdate(model, OrderStatus.Выдан);
|
||||
}
|
||||
|
||||
public bool Delete(OrderBindingModel model)
|
||||
{
|
||||
CheckModel(model, false);
|
||||
_logger.LogInformation("Delete. Id: {Id}", model.Id);
|
||||
if (_orderStorage.Delete(model) == null)
|
||||
{
|
||||
_logger.LogWarning("Delete operation failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,144 @@
|
||||
using HardwareShopBusinessLogic.MailWorker;
|
||||
using HardwareShopBusinessLogic.OfficePackage;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperModels;
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.BusinessLogicsContracts;
|
||||
using HardwareShopContracts.StoragesContracts;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
||||
namespace HardwareShopBusinessLogic.BusinessLogics.Storekeeper
|
||||
{
|
||||
public class ReportStorekeeperLogic : IReportStorekeeperLogic
|
||||
{
|
||||
private readonly IComponentStorage _componentStorage;
|
||||
|
||||
private readonly IGoodStorage _goodStorage;
|
||||
|
||||
private readonly AbstractSaveToExcel _saveToExcel;
|
||||
|
||||
private readonly AbstractSaveToWord _saveToWord;
|
||||
|
||||
private readonly AbstractSaveToPdf _saveToPdf;
|
||||
|
||||
private readonly AbstractMailWorker _mailWorker;
|
||||
|
||||
public ReportStorekeeperLogic(IComponentStorage componentStorage, AbstractSaveToExcel abstractSaveToExcel, AbstractSaveToWord abstractSaveToWord, IGoodStorage goodStorage, AbstractMailWorker abstractMailWorker, AbstractSaveToPdf saveToPdf)
|
||||
{
|
||||
_componentStorage = componentStorage;
|
||||
_saveToExcel = abstractSaveToExcel;
|
||||
_saveToWord = abstractSaveToWord;
|
||||
_goodStorage = goodStorage;
|
||||
_mailWorker = abstractMailWorker;
|
||||
_saveToPdf = saveToPdf;
|
||||
}
|
||||
public List<ReportBuildGoodViewModel> GetBuildGood(List<GoodViewModel> goods)
|
||||
{
|
||||
var result = new List<ReportBuildGoodViewModel>();
|
||||
|
||||
foreach (var g in goods)
|
||||
{
|
||||
var good = _goodStorage.GetElement(new() { Id = g.Id })!;
|
||||
var builds = good.GoodComponents
|
||||
//получили сборки и количество компонентов
|
||||
.Select(x => _componentStorage.GetComponentBuilds(new() { Id = x.Key })
|
||||
//если кол-во компонентов в товаре == кол-ву в сборке
|
||||
.Where(y => x.Value.Item2 == y.Item2))
|
||||
.SelectMany(x => x.Select(x => x.Item1))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
ReportBuildGoodViewModel record = new()
|
||||
{
|
||||
GoodName = good.GoodName,
|
||||
Builds = builds
|
||||
};
|
||||
result.Add(record);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// Получение сведений по комплектующим за период,
|
||||
/// с указанием в каких товарах и сборках они использовались
|
||||
public List<ReportComponentsViewModel> GetComponents(ReportBindingModel model)
|
||||
{
|
||||
var result = new List<ReportComponentsViewModel>();
|
||||
var components = _componentStorage.GetFilteredList(new()
|
||||
{
|
||||
UserId = model.UserId,
|
||||
DateFrom = model.DateFrom,
|
||||
DateTo = model.DateTo
|
||||
});
|
||||
|
||||
foreach (var component in components)
|
||||
{
|
||||
var builds = component.ComponentBuilds
|
||||
.Select(x => Tuple.Create(x.Value.Item1.BuildName, x.Value.Item2))
|
||||
.ToList();
|
||||
|
||||
var goods = _componentStorage
|
||||
.GetComponentGoods(new() { Id = component.Id })
|
||||
.ToList();
|
||||
|
||||
ReportComponentsViewModel record = new()
|
||||
{
|
||||
ComponentName = component.ComponentName,
|
||||
TotalCount = builds.Sum(x => x.Item2) + goods.Sum(x => x.Item2),
|
||||
GoodOrBuilds = builds.Concat(goods).ToList()
|
||||
};
|
||||
|
||||
result.Add(record);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte[] SaveBuildGoodToWordFile(ReportBindingModel model, List<GoodViewModel> goods)
|
||||
{
|
||||
_saveToWord.CreateBuildGoodReport(new WordInfo
|
||||
{
|
||||
FileName = model.FileName,
|
||||
Title = "Cписок сборок по выбранным товарам",
|
||||
BuildGood = GetBuildGood(goods)
|
||||
});
|
||||
|
||||
byte[] file = File.ReadAllBytes(model.FileName);
|
||||
File.Delete(model.FileName);
|
||||
return file;
|
||||
}
|
||||
|
||||
public byte[] SaveBuildGoodToExcelFile(ReportBindingModel model, List<GoodViewModel> goods)
|
||||
{
|
||||
_saveToExcel.CreateBuildGoodReport(new ExcelInfo
|
||||
{
|
||||
FileName = model.FileName,
|
||||
Title = "Cписок сборок по выбранным товарам",
|
||||
BuildGood = GetBuildGood(goods)
|
||||
});
|
||||
|
||||
byte[] file = File.ReadAllBytes(model.FileName);
|
||||
File.Delete(model.FileName);
|
||||
return file;
|
||||
}
|
||||
|
||||
public bool SendReportOnMail(ReportBindingModel model)
|
||||
{
|
||||
model.FileName = "temp.pdf";
|
||||
_saveToPdf.CreateComponentsReport(new PdfInfo
|
||||
{
|
||||
FileName = model.FileName,
|
||||
Title = "Отчет по комплектующим",
|
||||
DateFrom = model.DateFrom,
|
||||
DateTo = model.DateTo,
|
||||
ReportComponents = GetComponents(model)
|
||||
});
|
||||
byte[] file = File.ReadAllBytes(model.FileName);
|
||||
File.Delete(model.FileName);
|
||||
|
||||
_mailWorker.MailSendAsync(new()
|
||||
{
|
||||
MailAddress = model.UserEmail,
|
||||
Subject = "Отчет по комплектующим",
|
||||
Text = $"Отчет по полученным вами комлектующим за период с {model.DateFrom} по {model.DateTo} в формате Pdf.",
|
||||
File = file
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ using HardwareShopContracts.SearchModels;
|
||||
using HardwareShopContracts.StoragesContracts;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace HardwareShopBusinessLogic.BusinessLogics
|
||||
{
|
||||
@ -93,17 +94,21 @@ namespace HardwareShopBusinessLogic.BusinessLogics
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(model.Login))
|
||||
if (string.IsNullOrEmpty(model.Login) || model.Login.Length > 40)
|
||||
{
|
||||
throw new ArgumentNullException("Нет логина пользователя", nameof(model.Login));
|
||||
throw new ArgumentNullException("Нет логина пользователя или длина превышает 40 символов", nameof(model.Login));
|
||||
}
|
||||
if (string.IsNullOrEmpty(model.Email))
|
||||
if (string.IsNullOrEmpty(model.Email) || model.Email.Length > 40)
|
||||
{
|
||||
throw new ArgumentNullException("Нет почты пользователя", nameof(model.Email));
|
||||
throw new ArgumentNullException("Нет почты пользователя или длина превышает 40 символов", nameof(model.Email));
|
||||
}
|
||||
if (string.IsNullOrEmpty(model.Password))
|
||||
if (!Regex.IsMatch(model.Email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.IgnoreCase))
|
||||
{
|
||||
throw new ArgumentNullException("Нет пароля пользователя", nameof(model.Password));
|
||||
throw new ArgumentException("Неправильно введенная почта", nameof(model.Email));
|
||||
}
|
||||
if (string.IsNullOrEmpty(model.Password) || model.Password.Length > 40 || model.Password.Contains(' '))
|
||||
{
|
||||
throw new ArgumentNullException("Нет пароля пользователя или пароль содержит пробелы", nameof(model.Password));
|
||||
}
|
||||
_logger.LogInformation("User. Login: {Login}. Email: {Email}. Id: {Id}",
|
||||
model.Login, model.Email, model.Id);
|
||||
|
@ -10,10 +10,12 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IBuildStorage _buildStorage;
|
||||
public BuildLogic(ILogger<BuildLogic> logger, IBuildStorage buildStorage)
|
||||
private readonly IComponentStorage _componentStorage;
|
||||
public BuildLogic(ILogger<BuildLogic> logger, IBuildStorage buildStorage, IComponentStorage componentStorage)
|
||||
{
|
||||
_logger = logger;
|
||||
_buildStorage = buildStorage;
|
||||
_componentStorage = componentStorage;
|
||||
}
|
||||
|
||||
public List<BuildViewModel>? ReadList(BuildSearchModel? model)
|
||||
@ -94,10 +96,6 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
throw new ArgumentNullException("Нет названия сборки", nameof(model.BuildName));
|
||||
}
|
||||
if (model.Price <= 0)
|
||||
{
|
||||
throw new ArgumentNullException("Цена компонента должна быть больше 0", nameof(model.Price));
|
||||
}
|
||||
if (model.UserId < 0)
|
||||
{
|
||||
throw new ArgumentNullException("Некорректный идентификатор у клиента", nameof(model.UserId));
|
||||
@ -106,7 +104,7 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
throw new ArgumentNullException("Некорректный идентификатор у сборки", nameof(model.Id));
|
||||
}
|
||||
_logger.LogInformation("Build. BuildName:{BuildName}. Price:{Price}. Id:{Id}", model.BuildName, model.Price, model.Id);
|
||||
_logger.LogInformation("Build. UserId:{UserId}. BuildName:{BuildName}. Price:{Price}. Id:{Id}", model.UserId, model.BuildName, model.Price, model.Id);
|
||||
var element = _buildStorage.GetElement(new BuildSearchModel
|
||||
{
|
||||
BuildName = model.BuildName
|
||||
|
@ -100,8 +100,12 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
throw new ArgumentNullException("Некорректный идентификатор у комментария", nameof(model.Id));
|
||||
}
|
||||
if (model.UserId < 0)
|
||||
{
|
||||
throw new ArgumentNullException("Некорректный идентификатор у клиента", nameof(model.UserId));
|
||||
}
|
||||
|
||||
_logger.LogInformation("Comment. BuildId:{BuildId}. Id:{Id}", model.BuildId, model.Id);
|
||||
_logger.LogInformation("Comment. UserId:{UserId}. BuildId:{BuildId}. Id:{Id}", model.UserId, model.BuildId, model.Id);
|
||||
}
|
||||
}
|
||||
}
|
@ -30,9 +30,34 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
return list;
|
||||
}
|
||||
|
||||
public CommentViewModel? ReadElement(CommentSearchModel model)
|
||||
public List<PurchaseViewModel>? ReadOrderList(PurchaseSearchModel model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
_logger.LogInformation("ReadOrderList. Id:{Id}", model.Id);
|
||||
var list = _purchaseStorage.GetReportFilteredList(model);
|
||||
if (list == null)
|
||||
{
|
||||
_logger.LogWarning("ReadOrderList return null list");
|
||||
return null;
|
||||
}
|
||||
_logger.LogInformation("ReadOrderList. Count:{Count}", list.Count);
|
||||
return list;
|
||||
}
|
||||
|
||||
public PurchaseViewModel? ReadElement(PurchaseSearchModel model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
_logger.LogInformation("ReadElement. Id:{Id}", model.Id);
|
||||
var element = _purchaseStorage.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 DeliveryPurchase(PurchaseBindingModel model)
|
||||
@ -50,7 +75,7 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
model.PurchaseStatus = PurchaseStatus.Выдан;
|
||||
model.DatePurchase = DateTime.Now;
|
||||
CheckModel(model, false);
|
||||
if (_purchaseStorage.Update(model) == null)
|
||||
if (_purchaseStorage.Update(model, false) == null)
|
||||
{
|
||||
_logger.LogWarning("Change status operation failed");
|
||||
return false;
|
||||
@ -78,6 +103,11 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
|
||||
public bool Update(PurchaseBindingModel model)
|
||||
{
|
||||
if (model.PurchaseStatus == PurchaseStatus.Выдан)
|
||||
{
|
||||
_logger.LogWarning("Update status operation failed");
|
||||
return false;
|
||||
}
|
||||
CheckModel(model);
|
||||
if (_purchaseStorage.Update(model) == null)
|
||||
{
|
||||
@ -89,6 +119,11 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
|
||||
public bool Delete(PurchaseBindingModel model)
|
||||
{
|
||||
if (model.PurchaseStatus == PurchaseStatus.Выдан)
|
||||
{
|
||||
_logger.LogWarning("Delete status operation failed");
|
||||
return false;
|
||||
}
|
||||
CheckModel(model, false);
|
||||
_logger.LogInformation("Delete. Id:{Id}", model.Id);
|
||||
if (_purchaseStorage.Delete(model) == null)
|
||||
@ -121,7 +156,7 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
throw new ArgumentNullException("Сумма заказа должна быть больше 0", nameof(model.Sum));
|
||||
}
|
||||
_logger.LogInformation("Purchase. PurchaseID:{Id}. Sum:{ Sum}", model.Id, model.Sum);
|
||||
_logger.LogInformation("Purchase. UserId:{UserId}. PurchaseID:{Id}. Sum:{ Sum}", model.UserId, model.Id, model.Sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,177 @@
|
||||
|
||||
using HardwareShopBusinessLogic.MailWorker;
|
||||
using HardwareShopBusinessLogic.OfficePackage;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperModels;
|
||||
using HardwareShopBusinessLogic.OfficePackage.Implements;
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.SearchModels;
|
||||
using HardwareShopContracts.StoragesContracts;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
using HardwareShopDatabaseImplement.Implements.Worker;
|
||||
using HardwareShopDatabaseImplement.Models.Worker;
|
||||
using System.Reflection.PortableExecutable;
|
||||
|
||||
namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
public class WorkerReportLogic : IWorkerReportLogic
|
||||
{
|
||||
|
||||
private readonly IPurchaseStorage _purchaseStorage;
|
||||
|
||||
private readonly AbstractSaveToExcel _saveToExcel;
|
||||
|
||||
private readonly AbstractSaveToWord _saveToWord;
|
||||
|
||||
private readonly AbstractSaveToPdf _saveToPdf;
|
||||
|
||||
private readonly AbstractMailWorker _mailKitWorker;
|
||||
|
||||
public WorkerReportLogic(IPurchaseStorage purchaseStorage, AbstractMailWorker mailKitWorker, AbstractSaveToPdf saveToPdf, AbstractSaveToExcel saveToExcel, AbstractSaveToWord saveToWord)
|
||||
{
|
||||
_purchaseStorage = purchaseStorage;
|
||||
_saveToExcel = saveToExcel;
|
||||
_saveToWord = saveToWord;
|
||||
_saveToPdf = saveToPdf;
|
||||
_mailKitWorker = mailKitWorker;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка компонент с указанием, в каких покупках используются
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<ReportPurchaseComponentViewModel> GetPurchaseComponent(List<PurchaseViewModel> purchaseList)
|
||||
{
|
||||
var list = new List<ReportPurchaseComponentViewModel>();
|
||||
|
||||
foreach (var p in purchaseList)
|
||||
{
|
||||
var purchase = _purchaseStorage.GetElement(new() { Id = p.Id })!;
|
||||
|
||||
var record = new ReportPurchaseComponentViewModel
|
||||
{
|
||||
Id = purchase.Id,
|
||||
Builds = new List<(string Build, int count, List<(string Component, int count)>)>(),
|
||||
TotalCount = 0,
|
||||
TotalCost = purchase.Sum,
|
||||
};
|
||||
foreach (var build in purchase.PurchaseBuilds)
|
||||
{
|
||||
List<(string Component, int count)> componentList = new List<(string Component, int count)>();
|
||||
int buildTotalCount = 0;
|
||||
foreach (var component in build.Value.Item1.BuildComponents)
|
||||
{
|
||||
componentList.Add(new(component.Value.Item1.ComponentName, component.Value.Item2));
|
||||
buildTotalCount += component.Value.Item2;
|
||||
}
|
||||
record.Builds.Add(new(build.Value.Item1.BuildName, build.Value.Item2, componentList));
|
||||
record.TotalCount += buildTotalCount * build.Value.Item2;
|
||||
}
|
||||
|
||||
list.Add(record);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка покупок за определенный период
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
public List<ReportPurchaseViewModel> GetPurchase(ReportBindingModel model)
|
||||
{
|
||||
var list = new List<ReportPurchaseViewModel>();
|
||||
var purchases = _purchaseStorage.GetFilteredList(new PurchaseSearchModel { DateFrom = model.DateFrom, DateTo = model.DateTo, UserId = model.UserId });
|
||||
foreach (var p in purchases)
|
||||
{
|
||||
var purchase = _purchaseStorage.GetElement(new() { Id = p.Id })!;
|
||||
List<string> commentList = new List<string>();
|
||||
List<string> componentList = new List<string>();
|
||||
foreach (var build in purchase.PurchaseBuilds)
|
||||
{
|
||||
foreach (var comment in build.Value.Item1.BuildComments)
|
||||
{
|
||||
commentList.Add(new(comment.Value.Text));
|
||||
}
|
||||
foreach (var component in build.Value.Item1.BuildComponents)
|
||||
{
|
||||
componentList.Add(component.Value.Item1.ComponentName);
|
||||
}
|
||||
}
|
||||
var record = new ReportPurchaseViewModel
|
||||
{
|
||||
Id = purchase.Id,
|
||||
PurchaseDate = (DateTime)p.DatePurchase,
|
||||
PurchaseSum = p.Sum,
|
||||
Comments = commentList,
|
||||
Components = componentList.Distinct().ToList()
|
||||
};
|
||||
list.Add(record);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение компонент с указаеним покупок в файл-Word
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
public byte[] SavePurchasesToWordFile(ReportBindingModel model, List<PurchaseViewModel> purchases)
|
||||
{
|
||||
_saveToWord.CreateBuildPurchaseReport(new WordInfo
|
||||
{
|
||||
FileName = model.FileName,
|
||||
Title = "Список Компонентов",
|
||||
PurchaseComponent = GetPurchaseComponent(purchases)
|
||||
});
|
||||
|
||||
byte[] file = File.ReadAllBytes(model.FileName);
|
||||
File.Delete(model.FileName);
|
||||
return file;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение компонент с указаеним покупок в файл-Excel
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
public byte[] SavePurchasesToExcelFile(ReportBindingModel model, List<PurchaseViewModel> purchases)
|
||||
{
|
||||
_saveToExcel.CreatePurchaseComponentReport(new ExcelInfo
|
||||
{
|
||||
FileName = model.FileName,
|
||||
Title = "Список Компонентов",
|
||||
PurchaseComponent = GetPurchaseComponent(purchases)
|
||||
});
|
||||
byte[] file = File.ReadAllBytes(model.FileName);
|
||||
File.Delete(model.FileName);
|
||||
return file;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение отчёта по покупкам в файл-Pdf
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
public void SendByMailPurchaseReport(ReportBindingModel model)
|
||||
{
|
||||
model.FileName = "temp.pdf";
|
||||
_saveToPdf.GetPurchaseReportFile(new()
|
||||
{
|
||||
FileName = model.FileName,
|
||||
Title = "Отчет по покупкам",
|
||||
DateFrom = model.DateFrom,
|
||||
DateTo = model.DateTo,
|
||||
ReportPurchases = GetPurchase(model)
|
||||
});
|
||||
byte[] file = File.ReadAllBytes(model.FileName);
|
||||
File.Delete(model.FileName);
|
||||
|
||||
_mailKitWorker.MailSendAsync(new()
|
||||
{
|
||||
MailAddress = model.UserEmail,
|
||||
Subject = "Отчет по покупкам",
|
||||
Text = $"За период с {model.DateFrom.ToShortDateString()} " +
|
||||
$"по {model.DateTo.ToShortDateString()}.",
|
||||
File = file
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -7,11 +7,17 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DocumentFormat.OpenXml" Version="2.20.0" />
|
||||
<PackageReference Include="MailKit" Version="4.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="PdfSharp.MigraDoc.Standard" Version="1.51.15" />
|
||||
<PackageReference Include="System.Text.Encoding" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\HardwareShopContracts\HardwareShopContracts.csproj" />
|
||||
<ProjectReference Include="..\HardwareShopDatabaseImplement\HardwareShopDatabaseImplement.csproj" />
|
||||
<ProjectReference Include="..\HardwareShopDataModels\HardwareShopDataModels.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -0,0 +1,62 @@
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace HardwareShopBusinessLogic.MailWorker
|
||||
{
|
||||
public abstract class AbstractMailWorker
|
||||
{
|
||||
protected string _mailLogin = string.Empty;
|
||||
|
||||
protected string _mailPassword = string.Empty;
|
||||
|
||||
protected string _smtpClientHost = string.Empty;
|
||||
|
||||
protected int _smtpClientPort;
|
||||
|
||||
protected string _popHost = string.Empty;
|
||||
|
||||
protected int _popPort;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public AbstractMailWorker(ILogger<AbstractMailWorker> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void MailConfig(MailConfigBindingModel config)
|
||||
{
|
||||
_mailLogin = config.MailLogin;
|
||||
_mailPassword = config.MailPassword;
|
||||
_smtpClientHost = config.SmtpClientHost;
|
||||
_smtpClientPort = config.SmtpClientPort;
|
||||
_popHost = config.PopHost;
|
||||
_popPort = config.PopPort;
|
||||
_logger.LogDebug("Config: {login}, {password}, {clientHost}, {clientPort}, {popHost}, {popPort}",
|
||||
_mailLogin, _mailPassword, _smtpClientHost, _smtpClientPort, _popHost, _popPort);
|
||||
}
|
||||
|
||||
public async void MailSendAsync(MailSendInfoBindingModel info)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(_smtpClientHost) || _smtpClientPort == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(info.MailAddress) || string.IsNullOrEmpty(info.Subject) || string.IsNullOrEmpty(info.Text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogDebug("Send Mail: {To}, {Subject}", info.MailAddress, info.Subject);
|
||||
await SendMailAsync(info);
|
||||
}
|
||||
|
||||
protected abstract Task SendMailAsync(MailSendInfoBindingModel info);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.BusinessLogicsContracts;
|
||||
using MailKit.Net.Pop3;
|
||||
using MailKit.Security;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using System.Text;
|
||||
|
||||
namespace HardwareShopBusinessLogic.MailWorker
|
||||
{
|
||||
public class MailKitWorker : AbstractMailWorker
|
||||
{
|
||||
public MailKitWorker(ILogger<MailKitWorker> logger) : base(logger) { }
|
||||
|
||||
protected override async Task SendMailAsync(MailSendInfoBindingModel info)
|
||||
{
|
||||
using var objMailMessage = new MailMessage();
|
||||
using var objSmtpClient = new SmtpClient(_smtpClientHost, _smtpClientPort);
|
||||
try
|
||||
{
|
||||
objMailMessage.From = new MailAddress(_mailLogin);
|
||||
objMailMessage.To.Add(new MailAddress(info.MailAddress));
|
||||
objMailMessage.Subject = info.Subject;
|
||||
objMailMessage.Body = info.Text;
|
||||
objMailMessage.SubjectEncoding = Encoding.UTF8;
|
||||
objMailMessage.BodyEncoding = Encoding.UTF8;
|
||||
MemoryStream ms = new(info.File);
|
||||
objMailMessage.Attachments.Add(new Attachment(ms, "report.pdf", "application/pdf"));
|
||||
|
||||
objSmtpClient.UseDefaultCredentials = false;
|
||||
objSmtpClient.EnableSsl = true;
|
||||
objSmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
|
||||
objSmtpClient.Credentials = new NetworkCredential(_mailLogin, _mailPassword);
|
||||
|
||||
await Task.Run(() => objSmtpClient.Send(objMailMessage));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperModels;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage
|
||||
{
|
||||
public abstract class AbstractSaveToExcel
|
||||
{
|
||||
/// <summary>
|
||||
/// Создание отчета по сборкам в выбранных товарах
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
public void CreateBuildGoodReport(ExcelInfo info)
|
||||
{
|
||||
CreateExcel(info);
|
||||
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "A",
|
||||
RowIndex = 1,
|
||||
Text = info.Title,
|
||||
StyleInfo = ExcelStyleInfoType.Title
|
||||
});
|
||||
|
||||
MergeCells(new ExcelMergeParameters
|
||||
{
|
||||
CellFromName = "A1",
|
||||
CellToName = "B1"
|
||||
});
|
||||
|
||||
uint rowIndex = 2;
|
||||
foreach (var bg in info.BuildGood)
|
||||
{
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "A",
|
||||
RowIndex = rowIndex,
|
||||
Text = bg.GoodName,
|
||||
StyleInfo = ExcelStyleInfoType.TextWithBroder
|
||||
});
|
||||
rowIndex++;
|
||||
|
||||
foreach (var build in bg.Builds)
|
||||
{
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "B",
|
||||
RowIndex = rowIndex,
|
||||
Text = build,
|
||||
StyleInfo = ExcelStyleInfoType.TextWithBroder
|
||||
});
|
||||
|
||||
rowIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
SaveExcel(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создание отчета по сборкам в выбранных товарах
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
public void CreatePurchaseComponentReport(ExcelInfo info)
|
||||
{
|
||||
CreateExcel(info);
|
||||
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "A",
|
||||
RowIndex = 1,
|
||||
Text = info.Title,
|
||||
StyleInfo = ExcelStyleInfoType.Title
|
||||
});
|
||||
|
||||
MergeCells(new ExcelMergeParameters
|
||||
{
|
||||
CellFromName = "A1",
|
||||
CellToName = "E1"
|
||||
});
|
||||
|
||||
uint rowIndex = 2;
|
||||
foreach (var bg in info.PurchaseComponent)
|
||||
{
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "A",
|
||||
RowIndex = rowIndex,
|
||||
Text = bg.Id.ToString(),
|
||||
StyleInfo = ExcelStyleInfoType.Text
|
||||
});
|
||||
rowIndex++;
|
||||
|
||||
foreach (var build in bg.Builds)
|
||||
{
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "B",
|
||||
RowIndex = rowIndex,
|
||||
Text = build.Build,
|
||||
StyleInfo = ExcelStyleInfoType.TextWithBroder
|
||||
});
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "C",
|
||||
RowIndex = rowIndex,
|
||||
Text = build.count.ToString(),
|
||||
StyleInfo = ExcelStyleInfoType.TextWithBroder
|
||||
});
|
||||
|
||||
rowIndex++;
|
||||
foreach (var component in build.Item3)
|
||||
{
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "D",
|
||||
RowIndex = rowIndex,
|
||||
Text = component.Component,
|
||||
StyleInfo = ExcelStyleInfoType.TextWithBroder
|
||||
});
|
||||
InsertCellInWorksheet(new ExcelCellParameters
|
||||
{
|
||||
ColumnName = "E",
|
||||
RowIndex = rowIndex,
|
||||
Text = component.count.ToString(),
|
||||
StyleInfo = ExcelStyleInfoType.TextWithBroder
|
||||
});
|
||||
|
||||
rowIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SaveExcel(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создание excel-файла
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
protected abstract void CreateExcel(ExcelInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Добавляем новую ячейку в лист
|
||||
/// </summary>
|
||||
/// <param name="cellParameters"></param>
|
||||
protected abstract void InsertCellInWorksheet(ExcelCellParameters excelParams);
|
||||
|
||||
/// <summary>
|
||||
/// Объединение ячеек
|
||||
/// </summary>
|
||||
/// <param name="mergeParameters"></param>
|
||||
protected abstract void MergeCells(ExcelMergeParameters excelParams);
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение файла
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
protected abstract void SaveExcel(ExcelInfo info);
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
using DocumentFormat.OpenXml.EMMA;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperModels;
|
||||
using MigraDoc.Rendering;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage
|
||||
{
|
||||
public abstract class AbstractSaveToPdf
|
||||
{
|
||||
public void GetPurchaseReportFile(PdfInfo info)
|
||||
{
|
||||
CreatePdf(info);
|
||||
|
||||
CreateParagraph(new PdfParagraph
|
||||
{
|
||||
Text = info.Title,
|
||||
Style = "NormalTitle",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Center
|
||||
});
|
||||
|
||||
CreateParagraph(new PdfParagraph
|
||||
{
|
||||
Text = $"за период с {info.DateFrom.ToShortDateString()} " +
|
||||
$"по {info.DateTo.ToShortDateString()}",
|
||||
Style = "Normal",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Center
|
||||
});
|
||||
|
||||
CreateTable(new List<string> { "3cm", "4cm", "3cm", "4cm", "4cm" });
|
||||
|
||||
CreateRow(new PdfRowParameters
|
||||
{
|
||||
Texts = new List<string> { "Покупка", "Дата покупки", "Цена", "Комментарии", "Комплектующие" },
|
||||
Style = "NormalTitle",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Center
|
||||
});
|
||||
|
||||
foreach (var record in info.ReportPurchases)
|
||||
{
|
||||
List<string> comments = record.Comments;
|
||||
List<string> components = record.Components;
|
||||
int recordHeight = Math.Max(comments.Count + 1, components.Count + 1);
|
||||
for (int i = 0; i < recordHeight; i++)
|
||||
{
|
||||
List<string> cellsData = new() { "", "", "", "", "" };
|
||||
if (i == 0)
|
||||
{
|
||||
cellsData[0] = record.Id.ToString();
|
||||
cellsData[1] = record.PurchaseDate.ToShortDateString();
|
||||
cellsData[2] = record.PurchaseSum.ToString("0.00") + " р.";
|
||||
CreateRow(new PdfRowParameters
|
||||
{
|
||||
Texts = cellsData,
|
||||
Style = "Normal",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||
});
|
||||
continue;
|
||||
}
|
||||
int k = i - 1;
|
||||
if (k < comments.Count)
|
||||
{
|
||||
cellsData[3] = comments[k];
|
||||
}
|
||||
if (k < components.Count)
|
||||
{
|
||||
cellsData[4] = components[k];
|
||||
}
|
||||
CreateRow(new PdfRowParameters
|
||||
{
|
||||
Texts = cellsData,
|
||||
Style = "Normal",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||
});
|
||||
}
|
||||
}
|
||||
CreateParagraph(new PdfParagraph { Text = $"Итого: {info.ReportPurchases.Sum(x => x.PurchaseSum)}\t", Style = "Normal", ParagraphAlignment = PdfParagraphAlignmentType.Left });
|
||||
SavePdf(info);
|
||||
}
|
||||
|
||||
public void CreateComponentsReport(PdfInfo info)
|
||||
{
|
||||
CreatePdf(info);
|
||||
CreateParagraph(new PdfParagraph { Text = info.Title, Style = "NormalTitle", ParagraphAlignment = PdfParagraphAlignmentType.Center });
|
||||
CreateParagraph(new PdfParagraph { Text = $"с {info.DateFrom.ToShortDateString()} по {info.DateTo.ToShortDateString()}", Style = "Normal", ParagraphAlignment = PdfParagraphAlignmentType.Center });
|
||||
|
||||
CreateTable(new List<string> { "5cm", "5cm", "3cm" });
|
||||
|
||||
CreateRow(new PdfRowParameters
|
||||
{
|
||||
Texts = new List<string> { "Комплектующее", "Товар/Сборка", "Количество" },
|
||||
Style = "NormalTitle",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Center
|
||||
});
|
||||
|
||||
foreach (var record in info.ReportComponents)
|
||||
{
|
||||
CreateRow(new PdfRowParameters
|
||||
{
|
||||
Texts = new List<string> { record.ComponentName, "", "" },
|
||||
Style = "Normal",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||
});
|
||||
foreach (var goodOrBuild in record.GoodOrBuilds)
|
||||
{
|
||||
CreateRow(new PdfRowParameters
|
||||
{
|
||||
Texts = new List<string> { "", goodOrBuild.Item1, goodOrBuild.Item2.ToString() },
|
||||
Style = "Normal",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||
});
|
||||
}
|
||||
CreateRow(new PdfRowParameters
|
||||
{
|
||||
Texts = new List<string> { "Итого", "", record.TotalCount.ToString() },
|
||||
Style = "Normal",
|
||||
ParagraphAlignment = PdfParagraphAlignmentType.Left
|
||||
});
|
||||
}
|
||||
|
||||
SavePdf(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создание doc-файла
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
protected abstract void CreatePdf(PdfInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Создание параграфа с текстом
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="style"></param>
|
||||
protected abstract void CreateParagraph(PdfParagraph paragraph);
|
||||
|
||||
/// <summary>
|
||||
/// Создание таблицы
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
/// <param name="style"></param>
|
||||
protected abstract void CreateTable(List<string> columns);
|
||||
|
||||
/// <summary>
|
||||
/// Создание и заполнение строки
|
||||
/// </summary>
|
||||
/// <param name="rowParameters"></param>
|
||||
protected abstract void CreateRow(PdfRowParameters rowParameters);
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение файла
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
protected abstract void SavePdf(PdfInfo info);
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperModels;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage
|
||||
{
|
||||
public abstract class AbstractSaveToWord
|
||||
{
|
||||
public void CreateBuildGoodReport(WordInfo info)
|
||||
{
|
||||
CreateWord(info);
|
||||
|
||||
CreateParagraph(new WordParagraph
|
||||
{
|
||||
Texts = new List<(string, WordTextProperties)> { (info.Title, new WordTextProperties { Bold = true, Size = "24" }) },
|
||||
TextProperties = new WordTextProperties
|
||||
{
|
||||
Size = "24",
|
||||
JustificationType = WordJustificationType.Center
|
||||
}
|
||||
});
|
||||
|
||||
List<WordRow> rows = new List<WordRow>();
|
||||
rows.Add(new WordRow
|
||||
{
|
||||
Rows = new List<(string, WordTextProperties)> {
|
||||
("Товары", new WordTextProperties { Size = "24", Bold = true }),
|
||||
("Сборки", new WordTextProperties { Size = "24", Bold = true })
|
||||
}
|
||||
});
|
||||
|
||||
var reportRecords = info.BuildGood;
|
||||
foreach (var reportRecord in reportRecords)
|
||||
{
|
||||
rows.Add(new WordRow
|
||||
{
|
||||
Rows = new List<(string, WordTextProperties)>
|
||||
{
|
||||
(reportRecord.GoodName, new WordTextProperties { Size = "24" }),
|
||||
("", new WordTextProperties { })
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < reportRecord.Builds.Count; i++)
|
||||
{
|
||||
rows.Add(new WordRow
|
||||
{
|
||||
Rows = new List<(string, WordTextProperties)>
|
||||
{
|
||||
("", new WordTextProperties { }),
|
||||
(reportRecord.Builds[i], new WordTextProperties { Size = "24" })
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
CreateTable(rows);
|
||||
|
||||
SaveWord(info);
|
||||
}
|
||||
|
||||
public void CreateBuildPurchaseReport(WordInfo info)
|
||||
{
|
||||
CreateWord(info);
|
||||
|
||||
CreateParagraph(new WordParagraph
|
||||
{
|
||||
Texts = new List<(string, WordTextProperties)> { (info.Title, new WordTextProperties { Bold = true, Size = "24" }) },
|
||||
TextProperties = new WordTextProperties
|
||||
{
|
||||
Size = "24",
|
||||
JustificationType = WordJustificationType.Center
|
||||
}
|
||||
});
|
||||
|
||||
List<WordRow> rows = new List<WordRow>();
|
||||
rows.Add(new WordRow
|
||||
{
|
||||
Rows = new List<(string, WordTextProperties)> {
|
||||
("Покупки", new WordTextProperties { Size = "24", Bold = true }),
|
||||
("Сборки", new WordTextProperties { Size = "24", Bold = true }),
|
||||
("Количество", new WordTextProperties { Size = "24", Bold = true }),
|
||||
("Компоненты", new WordTextProperties { Size = "24", Bold = true }),
|
||||
("Количество", new WordTextProperties { Size = "24", Bold = true })
|
||||
}
|
||||
});
|
||||
|
||||
var reportRecords = info.PurchaseComponent;
|
||||
foreach (var reportRecord in reportRecords)
|
||||
{
|
||||
rows.Add(new WordRow
|
||||
{
|
||||
Rows = new List<(string, WordTextProperties)>
|
||||
{
|
||||
(reportRecord.Id.ToString(), new WordTextProperties { }),
|
||||
("", new WordTextProperties { }),
|
||||
("", new WordTextProperties { }),
|
||||
("", new WordTextProperties { }),
|
||||
("", new WordTextProperties { })
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < reportRecord.Builds.Count; i++)
|
||||
{
|
||||
rows.Add(new WordRow
|
||||
{
|
||||
Rows = new List<(string, WordTextProperties)>
|
||||
{
|
||||
("", new WordTextProperties { }),
|
||||
(reportRecord.Builds[i].Build, new WordTextProperties { }),
|
||||
(reportRecord.Builds[i].count.ToString(), new WordTextProperties { }),
|
||||
("", new WordTextProperties { }),
|
||||
("", new WordTextProperties { })
|
||||
}
|
||||
});
|
||||
for(int j = 0; j < reportRecord.Builds[i].Item3.Count; j++)
|
||||
{
|
||||
rows.Add(new WordRow
|
||||
{
|
||||
Rows = new List<(string, WordTextProperties)>
|
||||
{
|
||||
("", new WordTextProperties { }),
|
||||
("", new WordTextProperties { }),
|
||||
("", new WordTextProperties { }),
|
||||
(reportRecord.Builds[i].Item3[j].Component, new WordTextProperties { }),
|
||||
(reportRecord.Builds[i].Item3[j].count.ToString(), new WordTextProperties { })
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CreateTable(rows);
|
||||
|
||||
SaveWord(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создание doc-файла
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
protected abstract void CreateWord(WordInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Создание таблицы
|
||||
/// </summary>
|
||||
/// <param name="rows"></param>
|
||||
protected abstract void CreateTable(List<WordRow> rows);
|
||||
|
||||
/// <summary>
|
||||
/// Создание абзаца с текстом
|
||||
/// </summary>
|
||||
/// <param name="paragraph"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract void CreateParagraph(WordParagraph paragraph);
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение файла
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
protected abstract void SaveWord(WordInfo info);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperEnums
|
||||
{
|
||||
public enum ExcelStyleInfoType
|
||||
{
|
||||
Title,
|
||||
|
||||
Text,
|
||||
|
||||
TextWithBroder
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperEnums
|
||||
{
|
||||
public enum PdfParagraphAlignmentType
|
||||
{
|
||||
Center,
|
||||
|
||||
Left,
|
||||
|
||||
Rigth
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperEnums
|
||||
{
|
||||
public enum WordJustificationType
|
||||
{
|
||||
Center,
|
||||
|
||||
Both
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class ExcelCellParameters
|
||||
{
|
||||
public string ColumnName { get; set; } = string.Empty;
|
||||
|
||||
public uint RowIndex { get; set; }
|
||||
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
public string CellReference => $"{ColumnName}{RowIndex}";
|
||||
|
||||
public ExcelStyleInfoType StyleInfo { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class ExcelInfo
|
||||
{
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public List<ReportBuildGoodViewModel> BuildGood { get; set; } = new();
|
||||
|
||||
public List<ReportPurchaseComponentViewModel> PurchaseComponent { get; set; } = new();
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class ExcelMergeParameters
|
||||
{
|
||||
public string CellFromName { get; set; } = string.Empty;
|
||||
|
||||
public string CellToName { get; set; } = string.Empty;
|
||||
|
||||
public string Merge => $"{CellFromName}:{CellToName}";
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class PdfInfo
|
||||
{
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public DateTime DateFrom { get; set; }
|
||||
|
||||
public DateTime DateTo { get; set; }
|
||||
|
||||
public List<ReportComponentsViewModel> ReportComponents { get; set; } = new();
|
||||
|
||||
public List<ReportPurchaseViewModel> ReportPurchases { get; set; } = new();
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class PdfParagraph
|
||||
{
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
public string Style { get; set; } = string.Empty;
|
||||
|
||||
public PdfParagraphAlignmentType ParagraphAlignment { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class PdfRowParameters
|
||||
{
|
||||
public List<string> Texts { get; set; } = new();
|
||||
|
||||
public string Style { get; set; } = string.Empty;
|
||||
|
||||
public PdfParagraphAlignmentType ParagraphAlignment { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class WordInfo
|
||||
{
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public List<ReportBuildGoodViewModel> BuildGood { get; set; } = new();
|
||||
|
||||
public List<ReportPurchaseComponentViewModel> PurchaseComponent { get; set; } = new();
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class WordParagraph
|
||||
{
|
||||
public List<(string, WordTextProperties)> Texts { get; set; } = new();
|
||||
|
||||
public WordTextProperties? TextProperties { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class WordRow
|
||||
{
|
||||
public List<(string, WordTextProperties)> Rows { get; set; } = new();
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.HelperModels
|
||||
{
|
||||
public class WordTextProperties
|
||||
{
|
||||
public string Size { get; set; } = string.Empty;
|
||||
|
||||
public bool Bold { get; set; }
|
||||
|
||||
public WordJustificationType JustificationType { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,292 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperModels;
|
||||
using DocumentFormat.OpenXml;
|
||||
using DocumentFormat.OpenXml.Office2010.Excel;
|
||||
using DocumentFormat.OpenXml.Office2013.Excel;
|
||||
using DocumentFormat.OpenXml.Packaging;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.Implements
|
||||
{
|
||||
public class SaveToExcel : AbstractSaveToExcel
|
||||
{
|
||||
private SpreadsheetDocument? _spreadsheetDocument;
|
||||
|
||||
private SharedStringTablePart? _shareStringPart;
|
||||
|
||||
private Worksheet? _worksheet;
|
||||
|
||||
/// <summary>
|
||||
/// Настройка стилей для файла
|
||||
/// </summary>
|
||||
/// <param name="workbookpart"></param>
|
||||
private static void CreateStyles(WorkbookPart workbookpart)
|
||||
{
|
||||
var sp = workbookpart.AddNewPart<WorkbookStylesPart>();
|
||||
sp.Stylesheet = new Stylesheet();
|
||||
|
||||
var fonts = new Fonts() { Count = 2U, KnownFonts = true };
|
||||
|
||||
var fontUsual = new Font();
|
||||
fontUsual.Append(new FontSize() { Val = 12D });
|
||||
fontUsual.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Theme = 1U });
|
||||
fontUsual.Append(new FontName() { Val = "Times New Roman" });
|
||||
fontUsual.Append(new FontFamilyNumbering() { Val = 2 });
|
||||
fontUsual.Append(new FontScheme() { Val = FontSchemeValues.Minor });
|
||||
|
||||
var fontTitle = new Font();
|
||||
fontTitle.Append(new Bold());
|
||||
fontTitle.Append(new FontSize() { Val = 14D });
|
||||
fontTitle.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Theme = 1U });
|
||||
fontTitle.Append(new FontName() { Val = "Times New Roman" });
|
||||
fontTitle.Append(new FontFamilyNumbering() { Val = 2 });
|
||||
fontTitle.Append(new FontScheme() { Val = FontSchemeValues.Minor });
|
||||
|
||||
fonts.Append(fontUsual);
|
||||
fonts.Append(fontTitle);
|
||||
|
||||
var fills = new Fills() { Count = 2U };
|
||||
|
||||
var fill1 = new Fill();
|
||||
fill1.Append(new PatternFill() { PatternType = PatternValues.None });
|
||||
|
||||
var fill2 = new Fill();
|
||||
fill2.Append(new PatternFill() { PatternType = PatternValues.Gray125 });
|
||||
|
||||
fills.Append(fill1);
|
||||
fills.Append(fill2);
|
||||
|
||||
var borders = new Borders() { Count = 2U };
|
||||
|
||||
var borderNoBorder = new Border();
|
||||
borderNoBorder.Append(new LeftBorder());
|
||||
borderNoBorder.Append(new RightBorder());
|
||||
borderNoBorder.Append(new TopBorder());
|
||||
borderNoBorder.Append(new BottomBorder());
|
||||
borderNoBorder.Append(new DiagonalBorder());
|
||||
|
||||
var borderThin = new Border();
|
||||
|
||||
var leftBorder = new LeftBorder() { Style = BorderStyleValues.Thin };
|
||||
leftBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U });
|
||||
|
||||
var rightBorder = new RightBorder() { Style = BorderStyleValues.Thin };
|
||||
rightBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U });
|
||||
|
||||
var topBorder = new TopBorder() { Style = BorderStyleValues.Thin };
|
||||
topBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U });
|
||||
|
||||
var bottomBorder = new BottomBorder() { Style = BorderStyleValues.Thin };
|
||||
bottomBorder.Append(new DocumentFormat.OpenXml.Office2010.Excel.Color() { Indexed = 64U });
|
||||
|
||||
borderThin.Append(leftBorder);
|
||||
borderThin.Append(rightBorder);
|
||||
borderThin.Append(topBorder);
|
||||
borderThin.Append(bottomBorder);
|
||||
borderThin.Append(new DiagonalBorder());
|
||||
|
||||
borders.Append(borderNoBorder);
|
||||
borders.Append(borderThin);
|
||||
|
||||
var cellStyleFormats = new CellStyleFormats() { Count = 1U };
|
||||
var cellFormatStyle = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 0U };
|
||||
|
||||
cellStyleFormats.Append(cellFormatStyle);
|
||||
|
||||
var cellFormats = new CellFormats() { Count = 3U };
|
||||
var cellFormatFont = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 0U, FormatId = 0U, ApplyFont = true };
|
||||
var cellFormatFontAndBorder = new CellFormat() { NumberFormatId = 0U, FontId = 0U, FillId = 0U, BorderId = 1U, FormatId = 0U, ApplyFont = true, ApplyBorder = true };
|
||||
var cellFormatTitle = new CellFormat() { NumberFormatId = 0U, FontId = 1U, FillId = 0U, BorderId = 0U, FormatId = 0U, Alignment = new Alignment() { Vertical = VerticalAlignmentValues.Center, WrapText = true, Horizontal = HorizontalAlignmentValues.Center }, ApplyFont = true };
|
||||
|
||||
cellFormats.Append(cellFormatFont);
|
||||
cellFormats.Append(cellFormatFontAndBorder);
|
||||
cellFormats.Append(cellFormatTitle);
|
||||
|
||||
var cellStyles = new CellStyles() { Count = 1U };
|
||||
|
||||
cellStyles.Append(new CellStyle() { Name = "Normal", FormatId = 0U, BuiltinId = 0U });
|
||||
|
||||
var differentialFormats = new DocumentFormat.OpenXml.Office2013.Excel.DifferentialFormats() { Count = 0U };
|
||||
|
||||
var tableStyles = new TableStyles() { Count = 0U, DefaultTableStyle = "TableStyleMedium2", DefaultPivotStyle = "PivotStyleLight16" };
|
||||
|
||||
var stylesheetExtensionList = new StylesheetExtensionList();
|
||||
|
||||
var stylesheetExtension1 = new StylesheetExtension() { Uri = "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}" };
|
||||
stylesheetExtension1.AddNamespaceDeclaration("x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main");
|
||||
stylesheetExtension1.Append(new SlicerStyles() { DefaultSlicerStyle = "SlicerStyleLight1" });
|
||||
|
||||
var stylesheetExtension2 = new StylesheetExtension() { Uri = "{9260A510-F301-46a8-8635-F512D64BE5F5}" };
|
||||
stylesheetExtension2.AddNamespaceDeclaration("x15", "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main");
|
||||
stylesheetExtension2.Append(new TimelineStyles() { DefaultTimelineStyle = "TimeSlicerStyleLight1" });
|
||||
|
||||
stylesheetExtensionList.Append(stylesheetExtension1);
|
||||
stylesheetExtensionList.Append(stylesheetExtension2);
|
||||
|
||||
sp.Stylesheet.Append(fonts);
|
||||
sp.Stylesheet.Append(fills);
|
||||
sp.Stylesheet.Append(borders);
|
||||
sp.Stylesheet.Append(cellStyleFormats);
|
||||
sp.Stylesheet.Append(cellFormats);
|
||||
sp.Stylesheet.Append(cellStyles);
|
||||
sp.Stylesheet.Append(differentialFormats);
|
||||
sp.Stylesheet.Append(tableStyles);
|
||||
sp.Stylesheet.Append(stylesheetExtensionList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение номера стиля из типа
|
||||
/// </summary>
|
||||
/// <param name="styleInfo"></param>
|
||||
/// <returns></returns>
|
||||
private static uint GetStyleValue(ExcelStyleInfoType styleInfo)
|
||||
{
|
||||
return styleInfo switch
|
||||
{
|
||||
ExcelStyleInfoType.Title => 2U,
|
||||
ExcelStyleInfoType.TextWithBroder => 1U,
|
||||
ExcelStyleInfoType.Text => 0U,
|
||||
_ => 0U,
|
||||
};
|
||||
}
|
||||
|
||||
protected override void CreateExcel(ExcelInfo info)
|
||||
{
|
||||
_spreadsheetDocument = SpreadsheetDocument.Create(info.FileName, SpreadsheetDocumentType.Workbook);
|
||||
// Создаем книгу (в ней хранятся листы)
|
||||
var workbookpart = _spreadsheetDocument.AddWorkbookPart();
|
||||
workbookpart.Workbook = new Workbook();
|
||||
|
||||
CreateStyles(workbookpart);
|
||||
|
||||
// Получаем/создаем хранилище текстов для книги
|
||||
_shareStringPart = _spreadsheetDocument.WorkbookPart!.GetPartsOfType<SharedStringTablePart>().Any()
|
||||
? _spreadsheetDocument.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First()
|
||||
: _spreadsheetDocument.WorkbookPart.AddNewPart<SharedStringTablePart>();
|
||||
|
||||
// Создаем SharedStringTable, если его нет
|
||||
if (_shareStringPart.SharedStringTable == null)
|
||||
{
|
||||
_shareStringPart.SharedStringTable = new SharedStringTable();
|
||||
}
|
||||
|
||||
// Создаем лист в книгу
|
||||
var worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
|
||||
worksheetPart.Worksheet = new Worksheet(new SheetData());
|
||||
|
||||
// Добавляем лист в книгу
|
||||
var sheets = _spreadsheetDocument.WorkbookPart.Workbook.AppendChild(new Sheets());
|
||||
var sheet = new Sheet()
|
||||
{
|
||||
Id = _spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
|
||||
SheetId = 1,
|
||||
Name = "Лист"
|
||||
};
|
||||
sheets.Append(sheet);
|
||||
|
||||
_worksheet = worksheetPart.Worksheet;
|
||||
}
|
||||
|
||||
protected override void InsertCellInWorksheet(ExcelCellParameters excelParams)
|
||||
{
|
||||
if (_worksheet == null || _shareStringPart == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var sheetData = _worksheet.GetFirstChild<SheetData>();
|
||||
if (sheetData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ищем строку, либо добавляем ее
|
||||
Row row;
|
||||
if (sheetData.Elements<Row>().Where(r => r.RowIndex! == excelParams.RowIndex).Any())
|
||||
{
|
||||
row = sheetData.Elements<Row>().Where(r => r.RowIndex! == excelParams.RowIndex).First();
|
||||
}
|
||||
else
|
||||
{
|
||||
row = new Row() { RowIndex = excelParams.RowIndex };
|
||||
sheetData.Append(row);
|
||||
}
|
||||
|
||||
// Ищем нужную ячейку
|
||||
Cell cell;
|
||||
if (row.Elements<Cell>().Where(c => c.CellReference!.Value == excelParams.CellReference).Any())
|
||||
{
|
||||
cell = row.Elements<Cell>().Where(c => c.CellReference!.Value == excelParams.CellReference).First();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Все ячейки должны быть последовательно друг за другом расположены
|
||||
// нужно определить, после какой вставлять
|
||||
Cell? refCell = null;
|
||||
foreach (Cell rowCell in row.Elements<Cell>())
|
||||
{
|
||||
if (string.Compare(rowCell.CellReference!.Value, excelParams.CellReference, true) > 0)
|
||||
{
|
||||
refCell = rowCell;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var newCell = new Cell() { CellReference = excelParams.CellReference };
|
||||
row.InsertBefore(newCell, refCell);
|
||||
|
||||
cell = newCell;
|
||||
}
|
||||
|
||||
// вставляем новый текст
|
||||
_shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new Text(excelParams.Text)));
|
||||
_shareStringPart.SharedStringTable.Save();
|
||||
|
||||
cell.CellValue = new CellValue((_shareStringPart.SharedStringTable.Elements<SharedStringItem>().Count() - 1).ToString());
|
||||
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
|
||||
cell.StyleIndex = GetStyleValue(excelParams.StyleInfo);
|
||||
}
|
||||
|
||||
protected override void MergeCells(ExcelMergeParameters excelParams)
|
||||
{
|
||||
if (_worksheet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
MergeCells mergeCells;
|
||||
|
||||
if (_worksheet.Elements<MergeCells>().Any())
|
||||
{
|
||||
mergeCells = _worksheet.Elements<MergeCells>().First();
|
||||
}
|
||||
else
|
||||
{
|
||||
mergeCells = new MergeCells();
|
||||
|
||||
if (_worksheet.Elements<CustomSheetView>().Any())
|
||||
{
|
||||
_worksheet.InsertAfter(mergeCells, _worksheet.Elements<CustomSheetView>().First());
|
||||
}
|
||||
else
|
||||
{
|
||||
_worksheet.InsertAfter(mergeCells, _worksheet.Elements<SheetData>().First());
|
||||
}
|
||||
}
|
||||
|
||||
var mergeCell = new MergeCell()
|
||||
{
|
||||
Reference = new StringValue(excelParams.Merge)
|
||||
};
|
||||
mergeCells.Append(mergeCell);
|
||||
}
|
||||
|
||||
protected override void SaveExcel(ExcelInfo info)
|
||||
{
|
||||
if (_spreadsheetDocument == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_spreadsheetDocument.WorkbookPart!.Workbook.Save();
|
||||
_spreadsheetDocument.Close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperModels;
|
||||
using MigraDoc.DocumentObjectModel;
|
||||
using MigraDoc.DocumentObjectModel.Tables;
|
||||
using MigraDoc.Rendering;
|
||||
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.Implements
|
||||
{
|
||||
public class SaveToPdf : AbstractSaveToPdf
|
||||
{
|
||||
private Document? _document;
|
||||
|
||||
private Section? _section;
|
||||
|
||||
private Table? _table;
|
||||
|
||||
private static ParagraphAlignment GetParagraphAlignment(PdfParagraphAlignmentType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
PdfParagraphAlignmentType.Center => ParagraphAlignment.Center,
|
||||
PdfParagraphAlignmentType.Left => ParagraphAlignment.Left,
|
||||
PdfParagraphAlignmentType.Rigth => ParagraphAlignment.Right,
|
||||
_ => ParagraphAlignment.Justify,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создание стилей для документа
|
||||
/// </summary>
|
||||
/// <param name="document"></param>
|
||||
private static void DefineStyles(Document document)
|
||||
{
|
||||
var style = document.Styles["Normal"];
|
||||
style.Font.Name = "Times New Roman";
|
||||
style.Font.Size = 14;
|
||||
|
||||
style = document.Styles.AddStyle("NormalTitle", "Normal");
|
||||
style.Font.Bold = true;
|
||||
}
|
||||
|
||||
protected override void CreatePdf(PdfInfo info)
|
||||
{
|
||||
_document = new Document();
|
||||
DefineStyles(_document);
|
||||
|
||||
_section = _document.AddSection();
|
||||
}
|
||||
|
||||
protected override void CreateParagraph(PdfParagraph pdfParagraph)
|
||||
{
|
||||
if (_section == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var paragraph = _section.AddParagraph(pdfParagraph.Text);
|
||||
paragraph.Format.SpaceAfter = "1cm";
|
||||
paragraph.Format.Alignment = GetParagraphAlignment(pdfParagraph.ParagraphAlignment);
|
||||
paragraph.Style = pdfParagraph.Style;
|
||||
}
|
||||
|
||||
protected override void CreateTable(List<string> columns)
|
||||
{
|
||||
if (_document == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_table = _document.LastSection.AddTable();
|
||||
|
||||
foreach (var elem in columns)
|
||||
{
|
||||
_table.AddColumn(elem);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CreateRow(PdfRowParameters rowParameters)
|
||||
{
|
||||
if (_table == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var row = _table.AddRow();
|
||||
for (int i = 0; i < rowParameters.Texts.Count; ++i)
|
||||
{
|
||||
row.Cells[i].AddParagraph(rowParameters.Texts[i]);
|
||||
|
||||
if (!string.IsNullOrEmpty(rowParameters.Style))
|
||||
{
|
||||
row.Cells[i].Style = rowParameters.Style;
|
||||
}
|
||||
|
||||
Unit borderWidth = 0.5;
|
||||
|
||||
row.Cells[i].Borders.Left.Width = borderWidth;
|
||||
row.Cells[i].Borders.Right.Width = borderWidth;
|
||||
row.Cells[i].Borders.Top.Width = borderWidth;
|
||||
row.Cells[i].Borders.Bottom.Width = borderWidth;
|
||||
|
||||
row.Cells[i].Format.Alignment = GetParagraphAlignment(rowParameters.ParagraphAlignment);
|
||||
row.Cells[i].VerticalAlignment = VerticalAlignment.Center;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SavePdf(PdfInfo info)
|
||||
{
|
||||
var renderer = new PdfDocumentRenderer(true)
|
||||
{
|
||||
Document = _document
|
||||
};
|
||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||||
renderer.RenderDocument();
|
||||
renderer.PdfDocument.Save(info.FileName);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperEnums;
|
||||
using HardwareShopBusinessLogic.OfficePackage.HelperModels;
|
||||
using DocumentFormat.OpenXml;
|
||||
using DocumentFormat.OpenXml.Packaging;
|
||||
using DocumentFormat.OpenXml.Wordprocessing;
|
||||
|
||||
namespace HardwareShopBusinessLogic.OfficePackage.Implements
|
||||
{
|
||||
public class SaveToWord : AbstractSaveToWord
|
||||
{
|
||||
private WordprocessingDocument? _wordDocument;
|
||||
|
||||
private Body? _docBody;
|
||||
|
||||
/// <summary>
|
||||
/// Получение типа выравнивания
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private static JustificationValues GetJustificationValues(WordJustificationType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
WordJustificationType.Both => JustificationValues.Both,
|
||||
WordJustificationType.Center => JustificationValues.Center,
|
||||
_ => JustificationValues.Left,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Настройки страницы
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static SectionProperties CreateSectionProperties()
|
||||
{
|
||||
var properties = new SectionProperties();
|
||||
|
||||
var pageSize = new PageSize
|
||||
{
|
||||
Orient = PageOrientationValues.Portrait
|
||||
};
|
||||
|
||||
properties.AppendChild(pageSize);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Задание форматирования для абзаца
|
||||
/// </summary>
|
||||
/// <param name="paragraphProperties"></param>
|
||||
/// <returns></returns>
|
||||
private static ParagraphProperties? CreateParagraphProperties(WordTextProperties? paragraphProperties)
|
||||
{
|
||||
if (paragraphProperties == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var properties = new ParagraphProperties();
|
||||
|
||||
properties.AppendChild(new Justification()
|
||||
{
|
||||
Val = GetJustificationValues(paragraphProperties.JustificationType)
|
||||
});
|
||||
|
||||
properties.AppendChild(new SpacingBetweenLines
|
||||
{
|
||||
LineRule = LineSpacingRuleValues.Auto
|
||||
});
|
||||
|
||||
properties.AppendChild(new Indentation());
|
||||
|
||||
var paragraphMarkRunProperties = new ParagraphMarkRunProperties();
|
||||
if (!string.IsNullOrEmpty(paragraphProperties.Size))
|
||||
{
|
||||
paragraphMarkRunProperties.AppendChild(new FontSize { Val = paragraphProperties.Size });
|
||||
}
|
||||
properties.AppendChild(paragraphMarkRunProperties);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
protected override void CreateWord(WordInfo info)
|
||||
{
|
||||
_wordDocument = WordprocessingDocument.Create(info.FileName, WordprocessingDocumentType.Document);
|
||||
MainDocumentPart mainPart = _wordDocument.AddMainDocumentPart();
|
||||
mainPart.Document = new Document();
|
||||
_docBody = mainPart.Document.AppendChild(new Body());
|
||||
}
|
||||
|
||||
protected override void CreateTable(List<WordRow> data)
|
||||
{
|
||||
if (_docBody == null || data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Table table = new Table();
|
||||
var tableProp = new TableProperties();
|
||||
tableProp.AppendChild(new TableLayout { Type = TableLayoutValues.Fixed });
|
||||
tableProp.AppendChild(new TableBorders(
|
||||
new TopBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },
|
||||
new LeftBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },
|
||||
new RightBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },
|
||||
new BottomBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },
|
||||
new InsideHorizontalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 },
|
||||
new InsideVerticalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 4 }
|
||||
));
|
||||
tableProp.AppendChild(new TableWidth { Type = TableWidthUnitValues.Auto });
|
||||
table.AppendChild(tableProp);
|
||||
TableGrid tableGrid = new TableGrid();
|
||||
for (int j = 0; j < data[0].Rows.Count; ++j)
|
||||
{
|
||||
tableGrid.AppendChild(new GridColumn() { Width = "1600" });
|
||||
}
|
||||
table.AppendChild(tableGrid);
|
||||
for (int i = 0; i < data.Count; ++i)
|
||||
{
|
||||
TableRow docRow = new TableRow();
|
||||
for (int j = 0; j < data[i].Rows.Count; ++j)
|
||||
{
|
||||
var docParagraph = new Paragraph();
|
||||
var docRun = new Run();
|
||||
var runProperties = new RunProperties();
|
||||
|
||||
docParagraph.AppendChild(CreateParagraphProperties(data[i].Rows[j].Item2));
|
||||
|
||||
runProperties.AppendChild(new RunFonts() { Ascii = "Times New Roman", ComplexScript = "Times New Roman", HighAnsi = "Times New Roman" });
|
||||
runProperties.AppendChild(new FontSize { Val = data[i].Rows[j].Item2.Size == null ? data[i].Rows[j].Item2.Size : "24" });
|
||||
if (data[i].Rows[j].Item2.Bold)
|
||||
runProperties.AppendChild(new Bold());
|
||||
|
||||
docRun.AppendChild(runProperties);
|
||||
docRun.AppendChild(new Text { Text = data[i].Rows[j].Item1.ToString(), Space = SpaceProcessingModeValues.Preserve });
|
||||
|
||||
docParagraph.AppendChild(docRun);
|
||||
TableCell docCell = new TableCell();
|
||||
docCell.AppendChild(docParagraph);
|
||||
docRow.AppendChild(docCell);
|
||||
}
|
||||
table.AppendChild(docRow);
|
||||
}
|
||||
_docBody.AppendChild(table);
|
||||
}
|
||||
|
||||
protected override void CreateParagraph(WordParagraph paragraph)
|
||||
{
|
||||
if (_docBody == null || paragraph == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var docParagraph = new Paragraph();
|
||||
|
||||
docParagraph.AppendChild(CreateParagraphProperties(paragraph.TextProperties));
|
||||
|
||||
foreach (var run in paragraph.Texts)
|
||||
{
|
||||
var docRun = new Run();
|
||||
|
||||
var properties = new RunProperties();
|
||||
properties.AppendChild(new FontSize { Val = run.Item2.Size });
|
||||
if (run.Item2.Bold)
|
||||
{
|
||||
properties.AppendChild(new Bold());
|
||||
}
|
||||
docRun.AppendChild(properties);
|
||||
|
||||
docRun.AppendChild(new Text { Text = run.Item1, Space = SpaceProcessingModeValues.Preserve });
|
||||
|
||||
docParagraph.AppendChild(docRun);
|
||||
}
|
||||
|
||||
_docBody.AppendChild(docParagraph);
|
||||
}
|
||||
|
||||
protected override void SaveWord(WordInfo info)
|
||||
{
|
||||
if (_docBody == null || _wordDocument == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_docBody.AppendChild(CreateSectionProperties());
|
||||
|
||||
_wordDocument.MainDocumentPart!.Document.Save();
|
||||
|
||||
_wordDocument.Close();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HardwareShopClientApi.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class WeatherForecastController : ControllerBase
|
||||
{
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet(Name = "GetWeatherForecast")]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
{
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateTime.Now.AddDays(index),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,25 +0,0 @@
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
@ -1,13 +0,0 @@
|
||||
namespace HardwareShopClientApi
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string? Summary { get; set; }
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ using Newtonsoft.Json;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace HardwareShopClientApp
|
||||
namespace HardwareShopStorekeeperApp
|
||||
{
|
||||
//Клиент который общается с API, а не наша сущность
|
||||
public class APIClient
|
||||
@ -46,5 +46,23 @@ namespace HardwareShopClientApp
|
||||
throw new Exception(result);
|
||||
}
|
||||
}
|
||||
|
||||
public static R? PostRequestWithResult<T, R>(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)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<R>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
using HardwareShopClientApp.Models;
|
||||
using HardwareShopStorekeeperApp.Models;
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
using HardwareShopDataModels.Enums;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace HardwareShopClientApp.Controllers
|
||||
namespace HardwareShopStorekeeperApp.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
@ -17,25 +16,24 @@ namespace HardwareShopClientApp.Controllers
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Register()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void Register(string login, string email, string password, int role)
|
||||
public void Register(string login, string email, string password)
|
||||
{
|
||||
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password) || role <= 0)
|
||||
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
throw new Exception("Введите логин, email, пароль и роль");
|
||||
throw new Exception("Введите логин, email, пароль");
|
||||
}
|
||||
APIClient.PostRequest("api/client/register", new UserBindingModel
|
||||
APIClient.PostRequest("api/user/register", new UserBindingModel
|
||||
{
|
||||
Login = login,
|
||||
Email = email,
|
||||
Password = password,
|
||||
Role = (UserRole)role
|
||||
Role = UserRole.Кладовщик
|
||||
});
|
||||
Response.Redirect("Enter");
|
||||
return;
|
||||
@ -43,17 +41,43 @@ namespace HardwareShopClientApp.Controllers
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
//return RedirectToAction("MainWorker", "Worker");
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Privacy()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
return View();
|
||||
return View(APIClient.User);
|
||||
}
|
||||
|
||||
public IActionResult Privacy()
|
||||
[HttpPost]
|
||||
public IActionResult Privacy(string login, string email, string password)
|
||||
{
|
||||
return View();
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
throw new Exception("Введите логин, пароль и почту");
|
||||
}
|
||||
APIClient.PostRequest("api/user/updatedata", new UserBindingModel
|
||||
{
|
||||
Id = APIClient.User.Id,
|
||||
Login = login,
|
||||
Email = email,
|
||||
Password = password
|
||||
});
|
||||
|
||||
APIClient.User.Login = login;
|
||||
APIClient.User.Email = email;
|
||||
APIClient.User.Password = password;
|
||||
|
||||
return RedirectToAction("MainStorekeeper", "Storekeeper");
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
@ -62,8 +86,6 @@ namespace HardwareShopClientApp.Controllers
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Enter()
|
||||
{
|
||||
return View();
|
||||
@ -74,30 +96,14 @@ namespace HardwareShopClientApp.Controllers
|
||||
{
|
||||
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password))
|
||||
{
|
||||
throw new Exception("Введите логин и пароль");
|
||||
throw new Exception("Введите почту и пароль");
|
||||
}
|
||||
APIClient.User = APIClient.GetRequest<UserViewModel>($"api/client/login?email={email}&password={password}");
|
||||
if (APIClient.User == null)
|
||||
APIClient.User = APIClient.GetRequest<UserViewModel>($"api/user/login?email={email}&password={password}");
|
||||
if (APIClient.User == null || APIClient.User.Role != UserRole.Кладовщик)
|
||||
{
|
||||
throw new Exception("Неверный логин/пароль");
|
||||
throw new Exception("Неверные почта и/или пароль");
|
||||
}
|
||||
if ((int)APIClient.User.Role == 1)
|
||||
{
|
||||
//TempData["UserId"] = APIClient.User.Id;
|
||||
return RedirectToAction("WorkerReport", "Worker");
|
||||
return RedirectToAction("MainStorekeeper", "Storekeeper");
|
||||
}
|
||||
else
|
||||
{
|
||||
return Redirect("Index");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult MainWorker()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,456 @@
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
using HardwareShopDatabaseImplement.Models;
|
||||
using HardwareShopDatabaseImplement.Models.Storekeeper;
|
||||
using HardwareShopDataModels.Enums;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace HardwareShopStorekeeperApp.Controllers
|
||||
{
|
||||
public class StorekeeperController : Controller
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
|
||||
public StorekeeperController(ILogger<HomeController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IActionResult CreateOrder()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
ViewBag.Goods = APIClient.GetRequest<List<GoodViewModel>>($"api/good/getgoods?userId={APIClient.User.Id}");
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void CreateOrder(int good, int count, string sum)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (good <= 0)
|
||||
{
|
||||
throw new Exception("Некорректный идентификатор товара");
|
||||
}
|
||||
if (count <= 0)
|
||||
{
|
||||
throw new Exception("Количество должно быть больше 0");
|
||||
}
|
||||
if (Convert.ToDouble(sum.Replace('.', ',')) <= 0)
|
||||
{
|
||||
throw new Exception("Цена должна быть больше 0");
|
||||
}
|
||||
APIClient.PostRequest("api/order/createorder", new OrderBindingModel
|
||||
{
|
||||
UserId = APIClient.User.Id,
|
||||
GoodId = good,
|
||||
Count = count,
|
||||
Sum = Convert.ToDouble(sum.Replace('.', ','))
|
||||
});
|
||||
Response.Redirect("Orders");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void DeleteOrder(int Id)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (Id <= 0)
|
||||
{
|
||||
throw new Exception("Некорректный идентификатор");
|
||||
}
|
||||
APIClient.PostRequest("api/order/deleteorder", new OrderBindingModel
|
||||
{
|
||||
Id = Id
|
||||
});
|
||||
Response.Redirect("Orders");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void UpdateOrder(int id, int status)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (id <= 0)
|
||||
{
|
||||
throw new Exception("Некорректный идентификатор");
|
||||
}
|
||||
if (status <= 0)
|
||||
{
|
||||
throw new Exception("Некорректный статус");
|
||||
}
|
||||
APIClient.PostRequest("api/order/updatedata", new OrderBindingModel
|
||||
{
|
||||
Id = id,
|
||||
Status = (OrderStatus)status
|
||||
});
|
||||
Response.Redirect("Orders");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public double Calc(int count, int good)
|
||||
{
|
||||
var prod = APIClient.GetRequest<GoodViewModel>($"api/good/getgood?id={good}");
|
||||
double result = Math.Round(count * (prod?.Price ?? 1), 2);
|
||||
return result;
|
||||
}
|
||||
|
||||
public IActionResult CreateGood()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>($"api/component/getcomponents?userId={APIClient.User.Id}");
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void CreateGood([FromBody] GoodBindingModel goodModel)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (string.IsNullOrEmpty(goodModel.GoodName))
|
||||
{
|
||||
throw new Exception("Название не должно быть пустым");
|
||||
}
|
||||
if (goodModel.Price <= 0)
|
||||
{
|
||||
throw new Exception("Цена должна быть больше 0");
|
||||
}
|
||||
goodModel.UserId = APIClient.User.Id;
|
||||
APIClient.PostRequest("api/good/creategood", goodModel);
|
||||
}
|
||||
|
||||
public IActionResult UpdateGood(int goodid)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>($"api/component/getcomponents?userId={APIClient.User.Id}");
|
||||
return View(goodid);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void UpdateGood([FromBody] GoodBindingModel goodModel)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (string.IsNullOrEmpty(goodModel.GoodName))
|
||||
{
|
||||
throw new Exception("Название не должно быть пустым");
|
||||
}
|
||||
if (goodModel.Price <= 0)
|
||||
{
|
||||
throw new Exception("Цена должна быть больше 0");
|
||||
}
|
||||
goodModel.UserId = APIClient.User.Id;
|
||||
APIClient.PostRequest("api/good/updatedata", goodModel);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public GoodViewModel? GetGood(int Id)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (Id <= 0)
|
||||
{
|
||||
throw new Exception($"Идентификатор товара не может быть меньше или равен 0");
|
||||
}
|
||||
var result = APIClient.GetRequest<GoodViewModel>($"api/good/getgood?id={Id}");
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public Tuple<GoodViewModel, List<Tuple<ComponentViewModel?, int>>>? GetGoodUpdate(int goodid)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
var result = APIClient.GetRequest<Tuple<GoodViewModel,
|
||||
List<Tuple<ComponentViewModel?, int>>>?>($"api/good/getgoodupdate?id={goodid}&userId={APIClient.User.Id}");
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void DeleteGood(int good)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (good <= 0)
|
||||
{
|
||||
throw new Exception($"Идентификатор товара не может быть меньше или равен 0");
|
||||
}
|
||||
APIClient.PostRequest("api/good/deletegood", new GoodBindingModel
|
||||
{
|
||||
Id = good
|
||||
});
|
||||
}
|
||||
|
||||
public IActionResult LinkBuilds(int componentid)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
ViewBag.Builds = APIClient.GetRequest<List<BuildViewModel>>($"api/build/getbuilds");
|
||||
return View(componentid);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void LinkBuilds([FromBody] ComponentBindingModel componentModel)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
componentModel.UserId = APIClient.User.Id;
|
||||
APIClient.PostRequest($"api/component/updatedata", componentModel);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public BuildViewModel? GetBuild(int buildId)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (buildId <= 0)
|
||||
{
|
||||
throw new Exception($"Идентификатор сборки не может быть меньше или равен 0");
|
||||
}
|
||||
var result = APIClient.GetRequest<BuildViewModel>($"api/build/getbuild?buildId={buildId}");
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public List<Tuple<BuildViewModel, int>>? GetComponentBuilds(int componentid)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
var result = APIClient.GetRequest<List<Tuple<BuildViewModel, int>>?>($"api/component/getcomponentbuilds?id={componentid}");
|
||||
return result;
|
||||
}
|
||||
|
||||
public IActionResult CreateComponent()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void CreateComponent(string name, string cost)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new Exception("Название не должно быть пустым");
|
||||
}
|
||||
if (string.IsNullOrEmpty(cost) || Convert.ToDouble(cost.Replace('.', ',')) <= 0)
|
||||
{
|
||||
throw new Exception("Цена должна быть больше 0");
|
||||
}
|
||||
APIClient.PostRequest("api/component/createcomponent", new ComponentBindingModel
|
||||
{
|
||||
UserId = APIClient.User.Id,
|
||||
ComponentName = name,
|
||||
Cost = Convert.ToDouble(cost.Replace('.', ','))
|
||||
});
|
||||
Response.Redirect("Components");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ComponentViewModel? GetComponent(int Id)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
var result = APIClient.GetRequest<ComponentViewModel?>($"api/component/getcomponent?id={Id}");
|
||||
if (result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void UpdateComponent(string name, string cost, DateTime date, int component)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (component <= 0)
|
||||
{
|
||||
throw new Exception($"Идентификатор комплектующего не может быть меньше или равен 0");
|
||||
}
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
throw new Exception($"Имя комплектующего не должно быть пустым");
|
||||
}
|
||||
if (Convert.ToDouble(cost.Replace('.', ',')) <= 0)
|
||||
{
|
||||
throw new Exception($"Цена комплектующего не может быть меньше или равна 0");
|
||||
}
|
||||
APIClient.PostRequest("api/component/updatecomponent", new ComponentBindingModel
|
||||
{
|
||||
Id = component,
|
||||
ComponentName = name,
|
||||
Cost = Convert.ToDouble(cost.Replace('.', ',')),
|
||||
UserId = APIClient.User.Id,
|
||||
});
|
||||
Response.Redirect("Components");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void DeleteComponent(int component)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (component <= 0)
|
||||
{
|
||||
throw new Exception($"Идентификатор комплектующего не может быть меньше или равен 0");
|
||||
}
|
||||
APIClient.PostRequest("api/component/deletecomponent", new ComponentBindingModel
|
||||
{
|
||||
Id = component
|
||||
});
|
||||
}
|
||||
|
||||
public IActionResult MainStorekeeper()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Components()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
return View(APIClient.GetRequest<List<ComponentViewModel>>($"api/component/getcomponents?userId={APIClient.User.Id}"));
|
||||
}
|
||||
|
||||
public IActionResult Goods()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
return View(APIClient.GetRequest<List<GoodViewModel>>($"api/good/getgoods?userId={APIClient.User.Id}"));
|
||||
}
|
||||
|
||||
public IActionResult Orders()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
return View(APIClient.GetRequest<List<OrderViewModel>>($"api/order/getorders?userId={APIClient.User.Id}"));
|
||||
}
|
||||
|
||||
public IActionResult ListBuilds()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
ViewBag.Goods = APIClient.GetRequest<List<GoodViewModel>>($"api/good/getgoods?userId={APIClient.User.Id}");
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public int[]? ListBuilds([FromBody] GoodBindingModel goodModel, [FromQuery] string format)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
if (string.IsNullOrEmpty(format))
|
||||
{
|
||||
throw new FormatException("Неправильный формат файла");
|
||||
}
|
||||
byte[]? file = APIClient.PostRequestWithResult<GoodBindingModel, byte[]>($"api/report/buildgoodreport?format={format}", goodModel);
|
||||
return file!.Select(b => (int)b).ToArray();
|
||||
}
|
||||
|
||||
public IActionResult Report()
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
return Redirect("~/Home/Enter");
|
||||
}
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public List<ReportComponentsViewModel> Report([FromBody] ReportBindingModel reportModel)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
reportModel.UserId = APIClient.User.Id;
|
||||
List<ReportComponentsViewModel>? list = APIClient.PostRequestWithResult
|
||||
<ReportBindingModel, List<ReportComponentsViewModel>>("api/report/componentsreport", reportModel);
|
||||
return list!;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void ReportSendOnMail([FromBody] ReportBindingModel reportModel)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
reportModel.UserId = APIClient.User.Id;
|
||||
reportModel.UserEmail = APIClient.User.Email;
|
||||
APIClient.PostRequest("api/report/componentsreportsendonmail", reportModel);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public List<CommentViewModel> GetCommentsOnBuild(int buildId)
|
||||
{
|
||||
if (APIClient.User == null)
|
||||
{
|
||||
throw new Exception("Вы как сюда попали? Сюда вход только авторизованным");
|
||||
}
|
||||
return APIClient.GetRequest<List<CommentViewModel>>($"api/comment/GetCommentsOnBuild?buildId={buildId}")!;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
using HardwareShopClientApp.Models;
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
using HardwareShopDataModels.Enums;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace HardwareShopClientApp.Controllers
|
||||
{
|
||||
public class WorkerController : Controller
|
||||
{
|
||||
private readonly ILogger<WorkerController> _logger;
|
||||
|
||||
public WorkerController(ILogger<WorkerController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IActionResult Builds()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Comments()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult listComponents()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult MainWorker()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Purchases()
|
||||
{
|
||||
//return View();
|
||||
//string login = (string)TempData["UserId"];
|
||||
|
||||
return View(APIClient.GetRequest<List<PurchaseViewModel>>($"api/client/getpurchases?UserId={APIClient.User.Id}"));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public void Purchases(int id)
|
||||
{
|
||||
//return View();
|
||||
//string login = (string)TempData["UserId"];
|
||||
|
||||
Response.Redirect("Purchase");
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Purchase()
|
||||
{
|
||||
//return View();
|
||||
//string login = (string)TempData["UserId"];
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult WorkerReport()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<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="..\HardwareShopContracts\HardwareShopContracts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.13" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\HardwareShopBusinessLogic\HardwareShopBusinessLogic.csproj" />
|
||||
<ProjectReference Include="..\HardwareShopContracts\HardwareShopContracts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,4 +1,4 @@
|
||||
namespace HardwareShopClientApp.Models
|
||||
namespace HardwareShopStorekeeperApp.Models
|
||||
{
|
||||
public class ErrorViewModel
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
using HardwareShopClientApp;
|
||||
using HardwareShopStorekeeperApp;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@ -7,6 +7,7 @@ builder.Services.AddControllersWithViews();
|
||||
|
||||
var app = builder.Build();
|
||||
APIClient.Connect(builder.Configuration);
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"HardwareShopClientApp": {
|
||||
"HardwareShopStorekeeperApp": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
|
@ -1,9 +1,20 @@
|
||||
@{
|
||||
ViewData["Title"] = "Enter";
|
||||
}
|
||||
@section Header {}
|
||||
@section Header {
|
||||
<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">Магазин компьютерной техники "Ты ж программист"</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>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Вход в приложение</h2>
|
||||
<h2 class="display-4">Вход</h2>
|
||||
</div>
|
||||
<form method="post" class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
@ -15,9 +26,7 @@
|
||||
<input type="password" class="form-control" name="password">
|
||||
</div>
|
||||
<div class="col-sm-2 d-flex justify-content-evenly align-items-baseline">
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Submit</button>
|
||||
<a asp-action="Register">Регистрация</a>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Подтвердить</button>
|
||||
</div><a asp-action="Register">Регистрация</a>
|
||||
</form>
|
||||
|
||||
|
@ -1,99 +1,32 @@
|
||||
@{
|
||||
ViewData["Title"] = "Home Page";
|
||||
ViewData["Title"] = "Enter";
|
||||
}
|
||||
|
||||
@using HardwareShopContracts.ViewModels
|
||||
|
||||
@model List<PurchaseViewModel>
|
||||
|
||||
@section Header {
|
||||
<header>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<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">
|
||||
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Магазин компьютерной техники "Ты ж программист"</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="Worker" asp-action="Purchases">Purchases</a>
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Enter">Вход</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Builds">Builds</a>
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Register">Регистрация</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Comments">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="listComponents">listComponents</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="WorkerReport">WorkerReport</a>
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Storekeeper" asp-action="MainStorekeeper">Кладовщик</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
</header>
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Регистрация</h2>
|
||||
<div class="d-flex justify-content-center">
|
||||
<img src="images/logo.png"/>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
@{
|
||||
if (Model == null)
|
||||
{
|
||||
<h3 class="display-4">Авторизируйтесь</h3>
|
||||
return;
|
||||
}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Номер
|
||||
</th>
|
||||
<th>
|
||||
Блюдо
|
||||
</th>
|
||||
<th>
|
||||
Дата создания
|
||||
</th>
|
||||
<th>
|
||||
Количество
|
||||
</th>
|
||||
<th>
|
||||
Сумма
|
||||
</th>
|
||||
<th>
|
||||
Статус
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Id)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.DatePurchase)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Sum)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.PurchaseStatus)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.UserLogin)
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
@ -1,6 +1,29 @@
|
||||
@{
|
||||
ViewData["Title"] = "Privacy Policy";
|
||||
}
|
||||
<h1>@ViewData["Title"]</h1>
|
||||
@using HardwareShopContracts.ViewModels;
|
||||
|
||||
<p>Use this page to detail your site's privacy policy.</p>
|
||||
|
||||
@model UserViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Privacy Policy";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Личные данные</h2>
|
||||
</div>
|
||||
<form method="post" class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Почта:</label>
|
||||
<input type="text" class="form-control" name="email" value="@Model.Email">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Пароль:</label>
|
||||
<input type="text" class="form-control" name="password" value="@Model.Password">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Логин:</label>
|
||||
<input type="text" class="form-control" name="login" value="@Model.Login">
|
||||
</div>
|
||||
<div class="col-sm-2 d-flex justify-content-evenly align-items-baseline">
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Подтвердить</button>
|
||||
</div>
|
||||
</form>
|
@ -1,31 +1,36 @@
|
||||
@{
|
||||
ViewData["Title"] = "Register";
|
||||
}
|
||||
@section Header {}
|
||||
@section Header {
|
||||
<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">Магазин компьютерной техники "Ты ж программист"</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>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Регистрация</h2>
|
||||
</div>
|
||||
<form method="post" class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Логин</label>
|
||||
<input type="text" class="form-control" aria-describedby="emailHelp" name="login">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Почта</label>
|
||||
<input type="text" class="form-control" name="email">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Логин</label>
|
||||
<input type="text" class="form-control" aria-describedby="emailHelp" name="login">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Пароль</label>
|
||||
<input type="password" class="form-control" name="password">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Роль</label>
|
||||
<select class="form-select" name="role">
|
||||
<option value="1">Работник</option>
|
||||
<option value="2">Кладовщик</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Submit</button>
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Подтвердить</button>
|
||||
<a asp-action="Enter">Вернуться на вход</a>
|
||||
|
||||
</form>
|
||||
|
||||
|
@ -3,10 +3,11 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - HardwareShopClientApp</title>
|
||||
<title>@ViewData["Title"] - Магазин компьютерной техники</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="~/HardwareShopClientApp.styles.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/HardwareShopStorekeeperApp.styles.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/lib/font-awesome-4.7.0/css/font-awesome.min.css">
|
||||
</head>
|
||||
<body>
|
||||
@RenderSection("Header")
|
||||
@ -16,11 +17,6 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container">
|
||||
© 2023 - HardwareShopClientApp - <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>
|
||||
|
@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - Магазин компьютерной техники</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="~/HardwareShopStorekeeperApp.styles.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/lib/font-awesome-4.7.0/css/font-awesome.min.css">
|
||||
@await RenderSectionAsync("Styles", required: false)
|
||||
</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">Магазин компьютерной техники "Ты ж программист"</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="Storekeeper" asp-action="Components">Комплектующие</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Storekeeper" asp-action="Goods">Товары</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Storekeeper" asp-action="Orders">Заказы</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Storekeeper" asp-action="ListBuilds">Получение списка</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Storekeeper" asp-action="Report">Отчёт</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Личные данные</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="container">
|
||||
<main role="main" class="pb-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<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>
|
@ -0,0 +1,127 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
|
||||
@model List<ComponentViewModel>
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Комплектующие";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Комплектующие</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-center">
|
||||
@{
|
||||
<p>
|
||||
<a asp-action="CreateComponent" class="btn btn-primary mx-2">Создать комплектующее</a>
|
||||
</p>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Название
|
||||
</th>
|
||||
<th>
|
||||
Цена
|
||||
</th>
|
||||
<th>
|
||||
Дата приобретения
|
||||
</th>
|
||||
<th>
|
||||
Действия
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.ComponentName)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Cost)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.DateCreate)
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<a asp-controller="Storekeeper"
|
||||
asp-action="LinkBuilds"
|
||||
asp-route-componentid="@item.Id"
|
||||
class="btn btn-success">
|
||||
<i class="fa fa-paperclip fa-rotate-90" aria-hidden="true"></i>
|
||||
</a>
|
||||
<button onclick="getComponent(@item.Id)" type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#updateModal">
|
||||
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button onclick="deleteComponent(@item.Id)" type="button" class="btn btn-danger">
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
</div>
|
||||
|
||||
<form method="post" asp-controller="Storekeeper" asp-action="UpdateComponent">
|
||||
<div class="modal fade" id="updateModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Комплектующая</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="col">
|
||||
<label class="form-label">Название</label>
|
||||
<input type="text" class="form-control" name="name" id="name" required>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Стоимость</label>
|
||||
<input type="number" step="0.01" class="form-control" name="cost" id="cost" min="0.01" required>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" id="component" name="component" />
|
||||
<div class="modal-footer">
|
||||
<input type="submit" class="btn btn-primary" value="Сохранить">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
function getComponent(componentId) {
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "/Storekeeper/GetComponent",
|
||||
data: { Id: componentId },
|
||||
success: function (result) {
|
||||
if (result != null)
|
||||
{
|
||||
$('#name').val(result.componentName);
|
||||
$('#cost').val(result.cost);
|
||||
$('#component').val(result.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function deleteComponent(componentId) {
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/Storekeeper/DeleteComponent",
|
||||
data: { component: componentId }
|
||||
}).done(() => window.location.href = "/Storekeeper/Components");
|
||||
}
|
||||
</script>
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
@{
|
||||
ViewData["Title"] = "Создание комплектующего";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Создание комплектующего</h2>
|
||||
</div>
|
||||
|
||||
<form method="post" class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Название</label>
|
||||
<input type="text" class="form-control" name="name" required>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Стоимость</label>
|
||||
<input type="number" step="0.01" class="form-control" name="cost" min="0.01" required>
|
||||
</div>
|
||||
<div class="col-sm-2 d-flex justify-content-evenly align-items-baseline">
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Сохранить</button>
|
||||
</div>
|
||||
</form>
|
@ -0,0 +1,152 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "Создание товара";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Создание товара</h2>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Название</label>
|
||||
<input type="text" class="form-control" name="name" id="name" >
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Цена</label>
|
||||
<input type="number" step="0.01" class="form-control" name="price" id="price" readonly min="0.01" value="0" >
|
||||
</div>
|
||||
<h1 class="display-6">Комплектующие</h1>
|
||||
<div class="d-flex justify-content-center">
|
||||
<button type="button" class="btn btn-primary mx-2 mt-3" data-bs-toggle="modal" data-bs-target="#exampleModal">Добавить</button>
|
||||
</div>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Комплектующее</th>
|
||||
<th scope="col">Стоимость</th>
|
||||
<th scope="col">Количество</th>
|
||||
<th scope="col">Сумма</th>
|
||||
<th scope="col">Действие</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="result">
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="col-sm-2 d-flex justify-content-evenly align-items-baseline">
|
||||
<button type="button" class="btn btn-primary mt-3 px-4" id="creategood">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Комплектующее</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class="form-label">Комплектующее</label>
|
||||
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components, "Id", "ComponentName"))"></select>
|
||||
<label class="form-label">Количество</label>
|
||||
<input type="number" class="form-control" name="count" id="count" min="1" value="1" >
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="savecomponent">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
let list = [];
|
||||
const name = document.getElementById("name");
|
||||
const submitComponentBtn = document.getElementById("savecomponent");
|
||||
const saveBtn = document.getElementById("creategood");
|
||||
const countElem = document.getElementById("count");
|
||||
const resultTable = document.getElementById("result");
|
||||
const totalPrice = document.getElementById("price");
|
||||
|
||||
submitComponentBtn.addEventListener("click", () => {
|
||||
console.log('try to add component')
|
||||
var count = $('#count').val();
|
||||
var component = $('#component').val();
|
||||
if (component && count && count > 0) {
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `/Storekeeper/GetComponent`,
|
||||
data: { Id: component },
|
||||
success: function (result) {
|
||||
let flag = false
|
||||
if (list.length > 0) {
|
||||
list.forEach((elem) => {
|
||||
if (elem.component.id === parseInt(result.id)) {
|
||||
console.log('component already added')
|
||||
flag = true
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!flag) list.push({ component: result, count: count })
|
||||
reloadTable()
|
||||
countElem.value = '1'
|
||||
}
|
||||
}).fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
saveBtn.addEventListener("click", () => {
|
||||
console.log('try to add good')
|
||||
if (list.length == 0) {
|
||||
alert('failed add good. components are empty')
|
||||
return
|
||||
}
|
||||
let components = []
|
||||
let counts = []
|
||||
list.forEach((x) => {
|
||||
components.push(x.component);
|
||||
counts.push(parseInt(x.count))
|
||||
})
|
||||
$.ajax(
|
||||
{
|
||||
url: `/Storekeeper/CreateGood`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({"GoodName": name.value,"Price": parseFloat(totalPrice.value),
|
||||
"GoodComponentsComponents": components, "GoodComponentsCounts": counts })
|
||||
}
|
||||
).done(() => window.location.href = '/Storekeeper/Goods')
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
})
|
||||
|
||||
function reloadTable() {
|
||||
resultTable.innerHTML = ''
|
||||
let price = 0;
|
||||
let count = 0;
|
||||
list.forEach((elem) => {
|
||||
resultTable.innerHTML += `<tr><td>${elem.component.componentName}</td><td>${elem.component.cost}</td><td>${elem.count}</td><td>${Math.round(elem.component.cost * elem.count * 100) / 100}</td><td> \
|
||||
<div> \
|
||||
<button onclick="deleteComponent(${count})" type="button" class="btn btn-danger"> \
|
||||
<i class="fa fa-trash" aria-hidden="true"></i> \
|
||||
</button> \
|
||||
</div><td/></tr>`
|
||||
count++;
|
||||
price += elem.component.cost * elem.count
|
||||
})
|
||||
totalPrice.value = Math.round(price * 100) / 100
|
||||
}
|
||||
|
||||
function deleteComponent(id) {
|
||||
list = list.filter(value => value.component.componentName != resultTable.rows[id].cells[0].innerText)
|
||||
reloadTable()
|
||||
}
|
||||
|
||||
</script>
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
@{
|
||||
ViewData["Title"] = "Создание заказа";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Создание заказа</h2>
|
||||
</div>
|
||||
|
||||
<form method="post" class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Товар</label>
|
||||
<select id="good" name="good" class="form-control" asp-items="@(new SelectList(@ViewBag.Goods, "Id", "GoodName"))" required></select>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Количество</label>
|
||||
<input type="number" class="form-control" name="count" id="count" min="1" value="1" required>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Сумма</label>
|
||||
<input type="number" step="0.01" class="form-control" name="sum" id="sum" value="0" min="0,01" readonly required>
|
||||
</div>
|
||||
<div class="col-sm-2 d-flex justify-content-evenly align-items-baseline">
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Сохранить</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
$('#good').on('change', function () {
|
||||
check();
|
||||
});
|
||||
$('#count').on('input', function () {
|
||||
check();
|
||||
});
|
||||
|
||||
function check() {
|
||||
var count = $('#count').val();
|
||||
var good = $('#good').val();
|
||||
if (count && good) {
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/Storekeeper/Calc",
|
||||
data: { count: count, good: good },
|
||||
success: function (result) {
|
||||
$("#sum").val(result);
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
});
|
||||
};
|
||||
}
|
||||
check()
|
||||
</script>
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
|
||||
@model List<GoodViewModel>
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Товары";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Товары</h1>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<p>
|
||||
<a asp-action="CreateGood" class="btn btn-primary mx-2">Создать товар</a>
|
||||
</p>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Название
|
||||
</th>
|
||||
<th>
|
||||
Цена
|
||||
</th>
|
||||
<th>
|
||||
Действия
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.GoodName)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Price)
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<a asp-controller="Storekeeper"
|
||||
asp-action="UpdateGood"
|
||||
asp-route-goodid="@item.Id"
|
||||
class="btn btn-primary">
|
||||
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||
</a>
|
||||
<button onclick="deleteGood(@item.Id)" type="button" class="btn btn-danger">
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
function deleteGood(goodId) {
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "/Storekeeper/DeleteGood",
|
||||
data: { good: goodId }
|
||||
}).done(() => window.location.href = "/Storekeeper/Goods");
|
||||
}
|
||||
</script>
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "Привязка сборок";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Привязка сборок</h1>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<div class="d-flex justify-content-center">
|
||||
<button type="button" class="btn btn-primary mx-2 mt-3" data-bs-toggle="modal" data-bs-target="#exampleModal">Привязать</button>
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="display-6">Привязанные сборки</h1>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Сборка</th>
|
||||
<th scope="col">Количество</th>
|
||||
<th scope="col">Действие</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="result">
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="col-sm-2 d-flex justify-content-evenly align-items-baseline">
|
||||
<button type="button" class="btn btn-primary mt-3 px-4" id="linkbuilds">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Привязка сборки</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class="form-label">Сборка</label>
|
||||
<select id="build" name="build" class="form-control" asp-items="@(new SelectList(@ViewBag.Builds, "Id", "BuildName"))" required></select>
|
||||
<table class="table table-hover">
|
||||
<thead><tr><th scope="col">Комментарии</th></tr></thead>
|
||||
<tbody id="comments"></tbody>
|
||||
<label class="form-label">Количество</label>
|
||||
<input type="number" class="form-control" name="count" id="count" min="1" value="1" required>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="savebuild">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
const componentid = @Model;
|
||||
let component;
|
||||
let list = [];
|
||||
const submitBuildBtn = document.getElementById("savebuild");
|
||||
const saveBtn = document.getElementById("linkbuilds");
|
||||
const countElem = document.getElementById("count");
|
||||
const resultTable = document.getElementById("result");
|
||||
const selectBuilds = document.getElementById("build");
|
||||
const comments = document.getElementById("comments");
|
||||
|
||||
selectBuilds.addEventListener('change', function() { getCommentsOnBuild() });
|
||||
|
||||
function getCommentsOnBuild() {
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `/Storekeeper/GetCommentsOnBuild`,
|
||||
data: { buildId: selectBuilds.value },
|
||||
success: function (result) {
|
||||
reloadCommentsTable(result)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
submitBuildBtn.addEventListener("click", () => {
|
||||
console.log('try to add build')
|
||||
var count = $('#count').val();
|
||||
var build = $('#build').val();
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `/Storekeeper/GetBuild`,
|
||||
data: { buildId: build },
|
||||
success: function (result) {
|
||||
let flag = false
|
||||
if (list.length > 0) {
|
||||
list.forEach((elem) => {
|
||||
if (elem.build.id === parseInt(result.id)) {
|
||||
console.log('build already added')
|
||||
flag = true
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!flag) list.push({ build: result, count: count })
|
||||
reloadTable()
|
||||
countElem.value = '1'
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
saveBtn.addEventListener("click", () => {
|
||||
console.log('try to link builds')
|
||||
let builds = []
|
||||
let counts = []
|
||||
list.forEach((x) => {
|
||||
builds.push(x.build);
|
||||
counts.push(parseInt(x.count))
|
||||
})
|
||||
$.ajax(
|
||||
{
|
||||
url: `/Storekeeper/LinkBuilds`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ "Id": componentid, "ComponentName": component.componentName,
|
||||
"Cost": component.cost, "ComponentBuildsBuilds": builds, "ComponentBuildsCounts": counts })
|
||||
}
|
||||
).done(() => window.location.href = '/Storekeeper/Components')
|
||||
})
|
||||
|
||||
function reloadTable() {
|
||||
resultTable.innerHTML = ''
|
||||
let count = 0;
|
||||
list.forEach((elem) => {
|
||||
resultTable.innerHTML += `<tr><td>${elem.build.buildName}</td><td>${elem.count}</td><td> \
|
||||
<div> \
|
||||
<button onclick="deleteBuild(${count})" type="button" class="btn btn-danger"> \
|
||||
<i class="fa fa-trash" aria-hidden="true"></i> \
|
||||
</button> \
|
||||
</div><td/></tr>`
|
||||
count++;
|
||||
})
|
||||
}
|
||||
|
||||
function reloadCommentsTable(result) {
|
||||
comments.innerHTML = ''
|
||||
result.forEach((elem) => {
|
||||
comments.innerHTML += `<tr><td>${elem.text}</td></tr>`
|
||||
})
|
||||
}
|
||||
|
||||
function deleteBuild(id) {
|
||||
list = list.filter(value => value.build.buildName != resultTable.rows[id].cells[0].innerText)
|
||||
reloadTable()
|
||||
}
|
||||
|
||||
function getComponentBuilds() {
|
||||
if (componentid) {
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "/Storekeeper/GetComponent",
|
||||
data: { Id: componentid },
|
||||
success: function (result) {
|
||||
component = result
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "/Storekeeper/GetComponentBuilds",
|
||||
data: { componentid: componentid },
|
||||
success: function (result) {
|
||||
if (result) {
|
||||
result.forEach(elem => {
|
||||
list.push({ build: elem.item1, count: elem.item2 })
|
||||
})
|
||||
reloadTable()
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
getComponentBuilds();
|
||||
getCommentsOnBuild();
|
||||
|
||||
</script>
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "Получение списка";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Получение списка сборок</h1>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<h1 class="display-6">Выбранные товары</h1>
|
||||
<div class="d-flex justify-content-center">
|
||||
<button type="button" class="btn btn-primary mx-2 mt-3" data-bs-toggle="modal" data-bs-target="#exampleModal">Добавить товар</button>
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Товар</th>
|
||||
<th scope="col">Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="result">
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="col d-flex justify-content-evenly align-items-baseline">
|
||||
<button type="button" class="btn btn-primary m-2" id="savedoc">Сохранить в doc-формате</button>
|
||||
<button type="button" class="btn btn-primary m-2" id="saveexcel">Сохранить в xls-формате</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Товар</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class="form-label">Товар</label>
|
||||
<select id="good" name="good" class="form-control" asp-items="@(new SelectList(@ViewBag.Goods, "Id", "GoodName"))"></select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="savegood">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
let list = [];
|
||||
const submitGoodBtn = document.getElementById("savegood");
|
||||
const resultTable = document.getElementById("result");
|
||||
const saveDocBtn = document.getElementById("savedoc");
|
||||
const saveExcelBtn = document.getElementById("saveexcel");
|
||||
|
||||
submitGoodBtn.addEventListener("click", () => {
|
||||
console.log('try to add good')
|
||||
var good = $('#good').val();
|
||||
if (good)
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `/Storekeeper/GetGood`,
|
||||
data: { Id: good },
|
||||
success: function (result) {
|
||||
let flag = false
|
||||
if (list.length > 0) {
|
||||
list.forEach((elem) => {
|
||||
if (elem.id === parseInt(result.id)) {
|
||||
console.log('good already added')
|
||||
flag = true
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!flag) list.push(result)
|
||||
reloadTable()
|
||||
}
|
||||
}).fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
})
|
||||
|
||||
saveDocBtn.addEventListener("click", async () => {
|
||||
send('docx')
|
||||
})
|
||||
|
||||
saveExcelBtn.addEventListener("click", async () => {
|
||||
send('xlsx')
|
||||
})
|
||||
|
||||
function send(format) {
|
||||
console.log(`try to save in ${format} format`)
|
||||
if (list.length == 0) {
|
||||
alert('operation failed. goods are empty')
|
||||
return
|
||||
}
|
||||
$.ajax({
|
||||
url: `/Storekeeper/ListBuilds?format=${format}`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ "Goods" : list })
|
||||
}).done((file) => {
|
||||
let byteArray = new Uint8Array(file);
|
||||
saveFile(byteArray, format);
|
||||
})
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
}
|
||||
|
||||
async function saveFile(bytes, format) {
|
||||
if (window.showSaveFilePicker) {
|
||||
const opts = {
|
||||
suggestedName: `listbuilds.${format}`,
|
||||
types: [{
|
||||
description: `${format} file`,
|
||||
accept:
|
||||
{
|
||||
[`text/${format}`]: [`.${format}`]
|
||||
},
|
||||
}],
|
||||
};
|
||||
const handle = await showSaveFilePicker(opts);
|
||||
const writable = await handle.createWritable();
|
||||
await writable.write(bytes);
|
||||
writable.close();
|
||||
alert('done')
|
||||
}
|
||||
}
|
||||
|
||||
function reloadTable() {
|
||||
resultTable.innerHTML = ''
|
||||
let count = 0;
|
||||
list.forEach((elem) => {
|
||||
resultTable.innerHTML += `<tr><td>${elem.goodName}</td><td> \
|
||||
<div> \
|
||||
<button onclick="deleteGood(${count})" type="button" class="btn btn-danger"> \
|
||||
<i class="fa fa-trash" aria-hidden="true"></i> \
|
||||
</button> \
|
||||
</div></td></tr>`
|
||||
count++;
|
||||
})
|
||||
}
|
||||
|
||||
function deleteGood(id) {
|
||||
list = list.filter(value => value.goodName != resultTable.rows[id].cells[0].innerText)
|
||||
reloadTable()
|
||||
}
|
||||
</script>
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
@{
|
||||
ViewData["Title"] = "Основная - Кладовщик";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="d-flex justify-content-center">
|
||||
<img src="../images/logo.png"/>
|
||||
</div>
|
@ -0,0 +1,168 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
|
||||
@model List<OrderViewModel>
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Заказы";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Заказы</h1>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<p>
|
||||
<a asp-action="CreateOrder" class="btn btn-primary mx-2">Создать заказ</a>
|
||||
<button type="button" class="btn btn-primary mx-2" id="delete">Удалить заказ</button>
|
||||
<button type="button" class="btn btn-primary mx-2" id="inwork">Выполняется</button>
|
||||
<button type="button" class="btn btn-primary mx-2" id="ready">Готов</button>
|
||||
<button type="button" class="btn btn-primary mx-2" id="done">Выдан</button>
|
||||
</p>
|
||||
<table class="table" id="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Номер
|
||||
</th>
|
||||
<th>
|
||||
Товар
|
||||
</th>
|
||||
<th>
|
||||
Количество
|
||||
</th>
|
||||
<th>
|
||||
Сумма
|
||||
</th>
|
||||
<th>
|
||||
Статус
|
||||
</th>
|
||||
<th>
|
||||
Дата создания
|
||||
</th>
|
||||
<th>
|
||||
Дата выполнения
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Id)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.GoodName)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Count)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Sum)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Status)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.DateCreate)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.DateImplement)
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@section Styles
|
||||
{
|
||||
<style>
|
||||
tr{cursor: pointer;}
|
||||
.selected{background-color: #0d6efd; color: white;}
|
||||
</style>
|
||||
}
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
// get selected row
|
||||
// display selected row data in text input
|
||||
|
||||
var table = document.getElementById("table");
|
||||
var remove = document.getElementById("delete");
|
||||
var inwork = document.getElementById("inwork");
|
||||
var ready = document.getElementById("ready");
|
||||
var done = document.getElementById("done");
|
||||
for(var i = 1; i < table.rows.length; i++)
|
||||
{
|
||||
table.rows[i].onclick = function()
|
||||
{
|
||||
// remove the background from the previous selected row
|
||||
if(typeof index !== "undefined") {
|
||||
table.rows[index].classList.toggle("selected");
|
||||
}
|
||||
// get the selected row index
|
||||
index = this.rowIndex;
|
||||
// add class selected to the row
|
||||
this.classList.toggle("selected");
|
||||
|
||||
var order = parseInt(this.cells[0].innerText)
|
||||
remove.addEventListener("click", () => {
|
||||
console.log('try to delete order')
|
||||
$.ajax(
|
||||
{
|
||||
url: `/Storekeeper/DeleteOrder`,
|
||||
type: 'POST',
|
||||
data: { id: order }
|
||||
}
|
||||
).done(() => window.location.href='/Storekeeper/Orders')
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
})
|
||||
inwork.addEventListener("click", () => {
|
||||
console.log('try to update order status')
|
||||
$.ajax(
|
||||
{
|
||||
url: `/Storekeeper/UpdateOrder`,
|
||||
type: 'POST',
|
||||
data: { id : order, status : 1 }
|
||||
}
|
||||
).done((result) => window.location.href='/Storekeeper/Orders')
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
})
|
||||
ready.addEventListener("click", () => {
|
||||
console.log('try to update order status')
|
||||
$.ajax(
|
||||
{
|
||||
url: `/Storekeeper/UpdateOrder`,
|
||||
type: 'POST',
|
||||
data: { id : order, status : 2 }
|
||||
}
|
||||
).done(() => window.location.href='/Storekeeper/Orders')
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
})
|
||||
done.addEventListener("click", () => {
|
||||
console.log('try to update order status')
|
||||
$.ajax(
|
||||
{
|
||||
url: `/Storekeeper/UpdateOrder`,
|
||||
type: 'POST',
|
||||
data: { id : order, status : 3 }
|
||||
}
|
||||
).done(() => window.location.href='/Storekeeper/Orders')
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
</script>
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "Отчет";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">С</label>
|
||||
<input type="date" class="form-control" name="dateFrom" id="dateFrom">
|
||||
<label class="form-label">По</label>
|
||||
<input type="date" class="form-control" name="dateTo" id="dateTo">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4" id="page">Вывод на страницу</button>
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4" id="mail">Отправить на почту</button>
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Комплектующее</th>
|
||||
<th scope="col">Товар/Сборка</th>
|
||||
<th scope="col">Количество</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="result">
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
let list = []
|
||||
const from = document.getElementById("dateFrom");
|
||||
const to = document.getElementById("dateTo");
|
||||
const onpage = document.getElementById("page");
|
||||
const onmail = document.getElementById("mail");
|
||||
const resultTable = document.getElementById("result");
|
||||
|
||||
onpage.addEventListener("click", () => {
|
||||
console.log('try to get report')
|
||||
if (from.value && to.value && from.value !== '' && to.value !== '') {
|
||||
const dateFrom = new Date(from.value);
|
||||
const dateTo = new Date(to.value);
|
||||
if (dateFrom.getTime() > dateTo.getTime())
|
||||
alert("Неправильные даты")
|
||||
const reportModel = { "DateFrom": dateFrom, "DateTo": dateTo }
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
contentType: "application/json",
|
||||
url: `/Storekeeper/Report`,
|
||||
data: JSON.stringify(reportModel),
|
||||
success: function (result) {
|
||||
list = result
|
||||
console.log(list)
|
||||
reloadTable()
|
||||
}
|
||||
}).fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
} else { alert("Пустые поля") }
|
||||
})
|
||||
onmail.addEventListener("click", () => {
|
||||
console.log('try to send email')
|
||||
if (from.value && to.value && from.value !== '' && to.value !== '') {
|
||||
const dateFrom = new Date(from.value);
|
||||
const dateTo = new Date(to.value);
|
||||
if (dateFrom.getTime() > dateTo.getTime())
|
||||
alert("Неправильные даты")
|
||||
const reportModel = { "DateFrom": dateFrom, "DateTo": dateTo }
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
contentType: "application/json",
|
||||
url: `/Storekeeper/ReportSendOnMail`,
|
||||
data: JSON.stringify(reportModel)
|
||||
}).fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
} else { alert("Пустые поля") }
|
||||
})
|
||||
|
||||
function reloadTable() {
|
||||
resultString = '';
|
||||
list.forEach((elem) => {
|
||||
resultString += `<tr><td>${elem.componentName}</td><td></td><td></td></tr>`;
|
||||
elem.goodOrBuilds.forEach((goodOrBuild) => {
|
||||
resultString += `<tr><td></td><td>${goodOrBuild.item1}</td><td>${goodOrBuild.item2}</td></tr>`;
|
||||
})
|
||||
resultString += `<tr><td>Итого</td><td></td><td>${elem.totalCount}</td></tr>`;
|
||||
})
|
||||
resultTable.innerHTML = resultString
|
||||
}
|
||||
</script>
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
|
||||
@model int
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Товар";
|
||||
Layout = "~/Views/Shared/_LayoutStorekeeper.cshtml";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Редактирование товара</h2>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Название</label>
|
||||
<input type="text" class="form-control" name="name" id="name" required>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Цена</label>
|
||||
<input type="number" step="0.01" class="form-control" name="price" id="price" readonly min="0.01" value="0" required>
|
||||
</div>
|
||||
<h1 class="display-6">Комплектующие</h1>
|
||||
<div class="d-flex justify-content-center">
|
||||
<button type="button" class="btn btn-primary mx-2 mt-3" data-bs-toggle="modal" data-bs-target="#exampleModal">Добавить</button>
|
||||
</div>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Комплектующее</th>
|
||||
<th scope="col">Стоимость</th>
|
||||
<th scope="col">Количество</th>
|
||||
<th scope="col">Сумма</th>
|
||||
<th scope="col">Действие</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="result">
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="col-sm-2 d-flex justify-content-evenly align-items-baseline">
|
||||
<button type="button" class="btn btn-primary mt-3 px-4" id="editgood">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Комплектующее</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<label class="form-label">Комплектующее</label>
|
||||
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components, "Id", "ComponentName"))"></select>
|
||||
<label class="form-label">Количество</label>
|
||||
<input type="number" class="form-control" name="count" id="count" min="1" value="1" required>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" id="savecomponent">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts
|
||||
{
|
||||
<script>
|
||||
const goodid = @Model
|
||||
// components & counts
|
||||
let list = [];
|
||||
const name = document.getElementById("name");
|
||||
const submitComponentBtn = document.getElementById("savecomponent");
|
||||
const saveBtn = document.getElementById("editgood");
|
||||
const countElem = document.getElementById("count");
|
||||
const resultTable = document.getElementById("result");
|
||||
const totalPrice = document.getElementById("price");
|
||||
|
||||
submitComponentBtn.addEventListener("click", () => {
|
||||
console.log('try to add component')
|
||||
var count = $('#count').val();
|
||||
var component = $('#component').val();
|
||||
if (component && count && count > 0)
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `/Storekeeper/GetComponent`,
|
||||
data: { Id: component },
|
||||
success: function (result) {
|
||||
let flag = false
|
||||
if (list.length > 0) {
|
||||
list.forEach((elem) => {
|
||||
if (elem.component.id === parseInt(result.id)) {
|
||||
console.log('component already added')
|
||||
flag = true
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!flag) list.push({ component: result, count: count })
|
||||
reloadTable()
|
||||
countElem.value = '1'
|
||||
}
|
||||
}).fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
});
|
||||
})
|
||||
|
||||
saveBtn.addEventListener("click", () => {
|
||||
console.log('try to update good')
|
||||
if (list.length == 0) {
|
||||
console.log('failed update good')
|
||||
return
|
||||
}
|
||||
let components = []
|
||||
let counts = []
|
||||
list.forEach((x) => {
|
||||
components.push(x.component);
|
||||
counts.push(parseInt(x.count))
|
||||
})
|
||||
$.ajax(
|
||||
{
|
||||
url: `/Storekeeper/UpdateGood`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ "Id": goodid, "GoodName": name.value,"Price": parseFloat(totalPrice.value),
|
||||
"GoodComponentsComponents": components, "GoodComponentsCounts": counts })
|
||||
}
|
||||
).done(() => window.location.href = '/Storekeeper/Goods')
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
})
|
||||
|
||||
function reloadTable() {
|
||||
resultTable.innerHTML = ''
|
||||
let price = 0;
|
||||
let count = 0;
|
||||
list.forEach((elem) => {
|
||||
resultTable.innerHTML += `<tr><td>${elem.component.componentName}</td><td>${elem.component.cost}</td><td>${elem.count}</td><td>${Math.round(elem.component.cost * elem.count * 100) / 100}</td><td> \
|
||||
<div> \
|
||||
<button onclick="deleteComponent(${count})" type="button" class="btn btn-danger"> \
|
||||
<i class="fa fa-trash" aria-hidden="true"></i> \
|
||||
</button> \
|
||||
</div><td/></tr>`
|
||||
count++;
|
||||
price += elem.component.cost * elem.count
|
||||
})
|
||||
totalPrice.value = Math.round(price * 100) / 100
|
||||
}
|
||||
|
||||
function deleteComponent(id) {
|
||||
list = list.filter(value => value.component.componentName != resultTable.rows[id].cells[0].innerText)
|
||||
reloadTable()
|
||||
}
|
||||
|
||||
function getGood() {
|
||||
if (goodid) {
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "/Storekeeper/GetGoodUpdate",
|
||||
data: { goodid: goodid },
|
||||
success: function (result) {
|
||||
if (result) {
|
||||
name.value = result.item1.goodName
|
||||
totalPrice.value = result.item1.price
|
||||
result.item2.forEach(elem => {
|
||||
list.push({ component: elem.item1, count: elem.item2 })
|
||||
})
|
||||
reloadTable()
|
||||
}
|
||||
else
|
||||
alert("Ошибка получения товара")
|
||||
}
|
||||
})
|
||||
.fail(function(xhr, textStatus, errorThrown) {
|
||||
alert(xhr.responseText);
|
||||
})
|
||||
};
|
||||
}
|
||||
getGood();
|
||||
</script>
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
@{
|
||||
ViewData["Title"] = "Builds";
|
||||
}
|
||||
|
||||
@section Header {
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<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="Worker" asp-action="Purchases">Purchases</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Builds">Builds</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Comments">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="listComponents">listComponents</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="WorkerReport">WorkerReport</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Регистрация</h2>
|
||||
</div>
|
||||
<form method="post" class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Логин</label>
|
||||
<input type="text" class="form-control" aria-describedby="emailHelp" name="login">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Почта</label>
|
||||
<input type="text" class="form-control" name="email">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Пароль</label>
|
||||
<input type="password" class="form-control" name="password">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Роль</label>
|
||||
<select class="form-select" name="role">
|
||||
<option value="1">Работник</option>
|
||||
<option value="2">Кладовщик</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Submit</button>
|
||||
|
||||
</form>
|
||||
|
@ -1,62 +0,0 @@
|
||||
@{
|
||||
ViewData["Title"] = "Comments";
|
||||
}
|
||||
|
||||
@section Header {
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<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="Worker" asp-action="Purchases">Purchases</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Builds">Builds</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Comments">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="listComponents">listComponents</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="WorkerReport">WorkerReport</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Регистрация</h2>
|
||||
</div>
|
||||
<form method="post" class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Логин</label>
|
||||
<input type="text" class="form-control" aria-describedby="emailHelp" name="login">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Почта</label>
|
||||
<input type="text" class="form-control" name="email">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Пароль</label>
|
||||
<input type="password" class="form-control" name="password">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Роль</label>
|
||||
<select class="form-select" name="role">
|
||||
<option value="1">Работник</option>
|
||||
<option value="2">Кладовщик</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Submit</button>
|
||||
|
||||
</form>
|
||||
|
@ -1,36 +0,0 @@
|
||||
@{
|
||||
ViewData["Title"] = "MainWorker";
|
||||
}
|
||||
|
||||
@section Header {
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<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="Worker" asp-action="Purchases">Purchases</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Builds">Builds</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Comments">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="listComponents">listComponents</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="WorkerReport">WorkerReport</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
|
@ -1,106 +0,0 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "Purchase";
|
||||
}
|
||||
|
||||
@model List<GoodViewModel>
|
||||
|
||||
@section Header {
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<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="Worker" asp-action="Purchases">Purchases</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Builds">Builds</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Comments">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="listComponents">listComponents</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="WorkerReport">WorkerReport</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
<form class="d-flex justify-content-evenly">
|
||||
<div class=" col-sm-8">
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Товары</h2>
|
||||
</div>
|
||||
<div class="text-center" name="id">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Номер
|
||||
</th>
|
||||
<th>
|
||||
Название товара
|
||||
</th>
|
||||
<th>
|
||||
Цена
|
||||
</th>
|
||||
<th>
|
||||
Пользователь
|
||||
</th>
|
||||
<th>
|
||||
Количество
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center d-flex flex-column mt-5">
|
||||
<button type="button" class="btn btn-primary btn-lg mb-5" data-bs-toggle="modal" data-bs-target="#exampleModal">Добавить</button>
|
||||
<button type="button" class="btn btn-primary btn-lg mb-5" data-bs-toggle="modal" data-bs-target="#exampleModal">Изменить</button>
|
||||
<button type="button" class="btn btn-primary btn-lg mb-5">Удалить</button>
|
||||
<button type="button" class="btn btn-primary btn-lg mb-5">Обновить</button>
|
||||
</div>
|
||||
|
||||
<!-- Модальное окно -->
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Заголовок модального окна</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Товар</label>
|
||||
<select class="form-select" name="role">
|
||||
<option value="1">Товар 1</option>
|
||||
<option value="2">Товар 2</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Количество</label>
|
||||
<input type="number" class="form-control" name="count">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="button" class="btn btn-primary">Сохранить изменения</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
@ -1,103 +0,0 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "Purchases";
|
||||
}
|
||||
|
||||
@model List<PurchaseViewModel>
|
||||
|
||||
@section Header {
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<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="Worker" asp-action="Purchases">Purchases</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Builds">Builds</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Comments">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="listComponents">listComponents</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="WorkerReport">WorkerReport</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
<form method="post" class="d-flex justify-content-evenly">
|
||||
<div class=" col-sm-8">
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Покупки</h2>
|
||||
</div>
|
||||
<div class="text-center" name="id">
|
||||
@{
|
||||
if (Model == null)
|
||||
{
|
||||
<h3 class="display-4">Авторизируйтесь</h3>
|
||||
return;
|
||||
}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Номер
|
||||
</th>
|
||||
<th>
|
||||
Дата оплаты
|
||||
</th>
|
||||
<th>
|
||||
Сумма
|
||||
</th>
|
||||
<th>
|
||||
Статус
|
||||
</th>
|
||||
<th>
|
||||
Пользователь
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Id)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.DatePurchase)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Sum)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.PurchaseStatus)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.UserLogin)
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center d-flex flex-column mt-5">
|
||||
<button type="submit" class="btn btn-primary btn-lg mb-5">Добавить</button>
|
||||
<button type="submit" class="btn btn-primary btn-lg mb-5">Изменить</button>
|
||||
<button type="button" class="btn btn-primary btn-lg mb-5">Удалить</button>
|
||||
<button type="button" class="btn btn-primary btn-lg mb-5">Обновить</button>
|
||||
</div>
|
||||
</form>
|
@ -1,38 +0,0 @@
|
||||
@using HardwareShopContracts.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "WorkerReport";
|
||||
}
|
||||
|
||||
@section Header {
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<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="Worker" asp-action="Purchases">Purchases</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Builds">Builds</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Comments">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="listComponents">listComponents</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="WorkerReport">WorkerReport</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
|
||||
|
@ -1,62 +0,0 @@
|
||||
@{
|
||||
ViewData["Title"] = "listComponents";
|
||||
}
|
||||
|
||||
@section Header {
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container-fluid">
|
||||
<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="Worker" asp-action="Purchases">Purchases</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Builds">Builds</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="Comments">Comments</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="listComponents">listComponents</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Worker" asp-action="WorkerReport">WorkerReport</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
}
|
||||
<div class="text-center">
|
||||
<h2 class="display-4">Регистрация</h2>
|
||||
</div>
|
||||
<form method="post" class="d-flex flex-column align-items-center">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Логин</label>
|
||||
<input type="text" class="form-control" aria-describedby="emailHelp" name="login">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Почта</label>
|
||||
<input type="text" class="form-control" name="email">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Пароль</label>
|
||||
<input type="password" class="form-control" name="password">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label">Роль</label>
|
||||
<select class="form-select" name="role">
|
||||
<option value="1">Работник</option>
|
||||
<option value="2">Кладовщик</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-3 px-4">Submit</button>
|
||||
|
||||
</form>
|
||||
|
@ -1,3 +1,3 @@
|
||||
@using HardwareShopClientApp
|
||||
@using HardwareShopClientApp.Models
|
||||
@using HardwareShopStorekeeperApp
|
||||
@using HardwareShopStorekeeperApp.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
@ -7,5 +7,5 @@
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
|
||||
"IPAddress": "http://localhost:5205/"
|
||||
"IPAddress": "http://localhost:5254/"
|
||||
}
|
||||
|
BIN
HardwareShop/HardwareShopClientApp/wwwroot/images/logo.png
Normal file
BIN
HardwareShop/HardwareShopClientApp/wwwroot/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
2337
HardwareShop/HardwareShopClientApp/wwwroot/lib/font-awesome-4.7.0/css/font-awesome.css
vendored
Normal file
2337
HardwareShop/HardwareShopClientApp/wwwroot/lib/font-awesome-4.7.0/css/font-awesome.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
HardwareShop/HardwareShopClientApp/wwwroot/lib/font-awesome-4.7.0/css/font-awesome.min.css
vendored
Normal file
4
HardwareShop/HardwareShopClientApp/wwwroot/lib/font-awesome-4.7.0/css/font-awesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,17 +1,21 @@
|
||||
using HardwareShopDataModels.Models;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
public class BuildBindingModel : IBuildModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
public double Price { get; set; }
|
||||
|
||||
public string BuildName { get; set; } = string.Empty;
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
public Dictionary<int, (IComponentModel, int)>? BuildComponents { get; set; }
|
||||
public Dictionary<int, (IPurchaseModel, int)> BuildPurchases { get; set; } = new();
|
||||
|
||||
public Dictionary<int, (IComponentModel, int)> BuildComponents { get; set; } = new();
|
||||
|
||||
public Dictionary<int, ICommentModel> BuildComments { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using HardwareShopDataModels.Models;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using HardwareShopDataModels.Models;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
using HardwareShopDataModels.Models;
|
||||
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
@ -11,5 +12,25 @@ namespace HardwareShopContracts.BindingModels
|
||||
public double Cost { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
public DateTime DateCreate { get; set; } = DateTime.Now;
|
||||
|
||||
public Dictionary<int, (IBuildModel, int)> ComponentBuilds
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
|
||||
public List<BuildViewModel> ComponentBuildsBuilds
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
|
||||
public List<int> ComponentBuildsCounts
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using HardwareShopDataModels.Models;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
using HardwareShopDataModels.Models;
|
||||
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
@ -17,5 +18,26 @@ namespace HardwareShopContracts.BindingModels
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
|
||||
// for dictionary item1
|
||||
public List<ComponentViewModel> GoodComponentsComponents
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
|
||||
// for dictionary item2
|
||||
public List<int> GoodComponentsCounts
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
|
||||
// for report list
|
||||
public List<GoodViewModel> Goods
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
public class MailConfigBindingModel
|
||||
{
|
||||
public string MailLogin { get; set; } = string.Empty;
|
||||
|
||||
public string MailPassword { get; set; } = string.Empty;
|
||||
// откуда отправляем письма
|
||||
public string SmtpClientHost { get; set; } = string.Empty;
|
||||
|
||||
public int SmtpClientPort { get; set; }
|
||||
// откуда получаем
|
||||
public string PopHost { get; set; } = string.Empty;
|
||||
|
||||
public int PopPort { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
public class MailSendInfoBindingModel
|
||||
{
|
||||
public string MailAddress { get; set; } = string.Empty;
|
||||
|
||||
public string Subject { get; set; } = string.Empty;
|
||||
|
||||
public string Text { get; set; } = string.Empty;
|
||||
|
||||
public byte[] File { get; set; } = Array.Empty<byte>();
|
||||
}
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
using HardwareShopDataModels.Enums;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
using HardwareShopDataModels.Enums;
|
||||
using HardwareShopDataModels.Models;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
public class PurchaseBindingModel : IPurchaseModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public decimal Sum { get; set; }
|
||||
public double Sum { get; set; }
|
||||
|
||||
public PurchaseStatus PurchaseStatus { get; set; } = PurchaseStatus.Неизвестен;
|
||||
|
||||
@ -15,8 +16,26 @@ namespace HardwareShopContracts.BindingModels
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
public Dictionary<int, (IBuildModel, int)>? PurchaseBuilds { get; set; }
|
||||
|
||||
public Dictionary<int, (IGoodModel, int)> PurchaseGoods { get; set; } = new();
|
||||
|
||||
public Dictionary<int, (IBuildModel, int)> PurchaseBuilds { get; set; } = new();
|
||||
|
||||
public List<GoodViewModel> ListPurchaseGoods
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
|
||||
public List<int> PurchaseGoodsCounts
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
|
||||
public List<PurchaseViewModel> Purchases
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
public class ReportBindingModel
|
||||
{
|
||||
public string UserEmail { get; set; } = string.Empty;
|
||||
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
public DateTime DateFrom { get; set; }
|
||||
|
||||
public DateTime DateTo { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
using HardwareShopDataModels.Models;
|
||||
using HardwareShopDataModels.Enums;
|
||||
using HardwareShopDataModels.Enums;
|
||||
using HardwareShopDataModels.Models;
|
||||
|
||||
namespace HardwareShopContracts.BindingModels
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
using HardwareShopContracts.SearchModels;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
||||
namespace HardwareShopContracts.BuisnessLogicsContracts
|
||||
namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
public interface IComponentLogic
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
using HardwareShopContracts.SearchModels;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
||||
namespace HardwareShopContracts.BuisnessLogicsContracts
|
||||
namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
public interface IGoodLogic
|
||||
{
|
||||
|
@ -11,5 +11,6 @@ namespace HardwareShopContracts.BuisnessLogicsContracts
|
||||
bool TakeOrderInWork(OrderBindingModel model);
|
||||
bool FinishOrder(OrderBindingModel model);
|
||||
bool DeliveryOrder(OrderBindingModel model);
|
||||
bool Delete(OrderBindingModel model);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
public interface IPurchaseLogic
|
||||
{
|
||||
List<PurchaseViewModel>? ReadList(PurchaseSearchModel? model);
|
||||
CommentViewModel? ReadElement(CommentSearchModel model);
|
||||
List<PurchaseViewModel>? ReadOrderList(PurchaseSearchModel model);
|
||||
PurchaseViewModel? ReadElement(PurchaseSearchModel model);
|
||||
bool Create(PurchaseBindingModel model);
|
||||
bool Update(PurchaseBindingModel model);
|
||||
bool Delete(PurchaseBindingModel model);
|
||||
|
@ -0,0 +1,41 @@
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
||||
namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
public interface IReportStorekeeperLogic
|
||||
{
|
||||
/// <summary>
|
||||
/// Получение списка сборок с указанием, в каких товарах используются
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<ReportBuildGoodViewModel> GetBuildGood(List<GoodViewModel> goods);
|
||||
|
||||
/// <summary>
|
||||
/// Получение сведений по комплектующим за период,
|
||||
/// с указанием в каких товарах и сборках они использовались
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
List<ReportComponentsViewModel> GetComponents(ReportBindingModel model);
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение списка сборок по выбранным товарам в файл-Word
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
byte[] SaveBuildGoodToWordFile(ReportBindingModel model, List<GoodViewModel> goods);
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение списка сборок по выбранным товарам в файл-Excel
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
byte[] SaveBuildGoodToExcelFile(ReportBindingModel model, List<GoodViewModel> goods);
|
||||
|
||||
/// <summary>
|
||||
/// Отправление отчета на почту
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
bool SendReportOnMail(ReportBindingModel model);
|
||||
}
|
||||
}
|
@ -7,13 +7,9 @@ namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
public interface IUserLogic
|
||||
{
|
||||
List<UserViewModel>? ReadList(UserSearchModel? model);
|
||||
|
||||
UserViewModel? ReadElement(UserSearchModel model);
|
||||
|
||||
bool Create(UserBindingModel model);
|
||||
|
||||
bool Update(UserBindingModel model);
|
||||
|
||||
bool Delete(UserBindingModel model);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
|
||||
using HardwareShopContracts.BindingModels;
|
||||
using HardwareShopContracts.ViewModels;
|
||||
|
||||
namespace HardwareShopContracts.BusinessLogicsContracts
|
||||
{
|
||||
public interface IWorkerReportLogic
|
||||
{
|
||||
/// <summary>
|
||||
/// Получение списка компонент с указанием, в каких покупках используются
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<ReportPurchaseComponentViewModel> GetPurchaseComponent(List<PurchaseViewModel> purchaseList);
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка покупок за определенный период
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
List<ReportPurchaseViewModel> GetPurchase(ReportBindingModel model);
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение компонент с указаеним покупок в файл-Word
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
byte[] SavePurchasesToWordFile(ReportBindingModel model, List<PurchaseViewModel> purchases);
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение компонент с указаеним покупок в файл-Excel
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
byte[] SavePurchasesToExcelFile(ReportBindingModel model, List<PurchaseViewModel> purchases);
|
||||
|
||||
/// <summary>
|
||||
/// Сохранение отчёта по покупкам в файл-Pdf
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
void SendByMailPurchaseReport(ReportBindingModel model);
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System.ComponentModel;
|
||||
namespace HardwareShopContracts.SearchModels
|
||||
namespace HardwareShopContracts.SearchModels
|
||||
{
|
||||
public class BuildSearchModel
|
||||
{
|
||||
|
@ -1,7 +1,4 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace HardwareShopContracts.SearchModels
|
||||
namespace HardwareShopContracts.SearchModels
|
||||
{
|
||||
public class CommentSearchModel
|
||||
{
|
||||
|
@ -4,5 +4,8 @@
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
public string? ComponentName { get; set; }
|
||||
public int? UserId { get; set; }
|
||||
public DateTime? DateFrom { get; set; }
|
||||
public DateTime? DateTo { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -4,5 +4,6 @@
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
public string? GoodName { get; set; }
|
||||
public int? UserId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
public class OrderSearchModel
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
public DateTime? DateFrom { get; set; }
|
||||
public DateTime? DateTo { get; set; }
|
||||
public int? UserId { get; set; }
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user