Compare commits
32 Commits
Task_5_Api
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a690777272 | |||
| 9401c42ffd | |||
| 6b1f57a3b9 | |||
| b8a9409dad | |||
| 2b24a8d6f2 | |||
| 0a831f0a6c | |||
| bde930a544 | |||
| b70143484d | |||
| 75c0be18ce | |||
| a26193512c | |||
| 6c561fb147 | |||
| 46a8843a84 | |||
| ce492dd8a1 | |||
| 1153b716f4 | |||
| b6d3d53856 | |||
| 9138a12e97 | |||
| ed2369ed85 | |||
| 92d02d4ba6 | |||
| b977e76302 | |||
| 4fdc420920 | |||
| 8e930475a3 | |||
| 57f878a051 | |||
| b59bdf9f3d | |||
| f5d5ff4b24 | |||
| 3e48ad4d24 | |||
| b1e5b7de93 | |||
| 9ed33690cf | |||
| 1c0bf1efd2 | |||
| e8f493691f | |||
| de879be266 | |||
| 164def1e18 | |||
| 56053a7287 |
@@ -24,17 +24,30 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
private static readonly string[] clientsByDepositHeader = ["Фамилия", "Имя", "Баланс", "Ставка", "Срок", "Период"];
|
||||
private static readonly string[] currencyHeader = ["Валюта", "Кредитная программа", "Макс. сумма", "Ставка", "Срок"];
|
||||
|
||||
public async Task<List<ClientsByCreditProgramDataModel>> GetDataClientsByCreditProgramAsync(CancellationToken ct)
|
||||
/// <summary>
|
||||
/// Получения данных для отчета Клиента по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ClientsByCreditProgramDataModel>> GetDataClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data ClientsByCreditProgram");
|
||||
if (creditProgramIds is null || creditProgramIds.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
var clients = await Task.Run(() => _clientStorage.GetList(), ct);
|
||||
var creditPrograms = await Task.Run(() => _creditProgramStorage.GetList(), ct);
|
||||
var currencies = await Task.Run(() => _currencyStorage.GetList(), ct);
|
||||
|
||||
return creditPrograms
|
||||
.Where(cp => cp.Currencies.Any()) // Проверяем, что у кредитной программы есть связанные валюты
|
||||
var filteredPrograms = creditPrograms
|
||||
.Where(cp => creditProgramIds.Contains(cp.Id));
|
||||
|
||||
return filteredPrograms
|
||||
.Select(cp => new ClientsByCreditProgramDataModel
|
||||
{
|
||||
CreditProgramId = cp.Id,
|
||||
CreditProgramName = cp.Name,
|
||||
ClientSurname = clients.Where(c => c.CreditProgramClients.Any(cpc => cpc.CreditProgramId == cp.Id))
|
||||
.Select(c => c.Surname).ToList(),
|
||||
@@ -45,10 +58,17 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentClientsByCreditProgramAsync(CancellationToken ct)
|
||||
/// <summary>
|
||||
/// Создание word отчета Клиента по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<Stream> CreateDocumentClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report ClientsByCreditProgram");
|
||||
var data = await GetDataClientsByCreditProgramAsync(ct) ?? throw new InvalidOperationException("No found data");
|
||||
var data = await GetDataClientsByCreditProgramAsync(creditProgramIds, ct) ?? throw new InvalidOperationException("No found data");
|
||||
|
||||
var tableRows = new List<string[]>
|
||||
{
|
||||
@@ -59,27 +79,34 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
{
|
||||
for (int i = 0; i < program.ClientSurname.Count; i++)
|
||||
{
|
||||
tableRows.Add(new string[]
|
||||
{
|
||||
tableRows.Add(
|
||||
[
|
||||
program.CreditProgramName,
|
||||
program.ClientSurname[i],
|
||||
program.ClientName[i],
|
||||
program.ClientBalance[i].ToString("N2")
|
||||
});
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return _baseWordBuilder
|
||||
.AddHeader("Клиенты по кредитным программам")
|
||||
.AddParagraph($"Сформировано на дату {DateTime.Now}")
|
||||
.AddTable([3000, 3000, 3000, 3000], tableRows)
|
||||
.AddTable([2000, 2000, 2000, 2000], tableRows)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateExcelDocumentClientsByCreditProgramAsync(CancellationToken ct)
|
||||
/// <summary>
|
||||
/// Создание excel отчета Клиенты по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<Stream> CreateExcelDocumentClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create Excel report ClientsByCreditProgram");
|
||||
var data = await GetDataClientsByCreditProgramAsync(ct) ?? throw new InvalidOperationException("No found data");
|
||||
var data = await GetDataClientsByCreditProgramAsync(creditProgramIds, ct) ?? throw new InvalidOperationException("No found data");
|
||||
|
||||
var tableRows = new List<string[]>
|
||||
{
|
||||
@@ -90,23 +117,32 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
{
|
||||
for (int i = 0; i < program.ClientSurname.Count; i++)
|
||||
{
|
||||
tableRows.Add(new string[]
|
||||
{
|
||||
tableRows.Add(
|
||||
[
|
||||
program.CreditProgramName,
|
||||
program.ClientSurname[i],
|
||||
program.ClientName[i],
|
||||
program.ClientBalance[i].ToString("N2")
|
||||
});
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return _baseExcelBuilder
|
||||
.AddHeader("Клиенты по кредитным программам", 0, 4)
|
||||
.AddParagraph($"Сформировано на дату {DateTime.Now}", 0)
|
||||
.AddTable([3000, 3000, 3000, 3000], tableRows)
|
||||
.AddTable([25, 25, 25, 25], tableRows)
|
||||
.Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных для отчета Клиента по Депозитам
|
||||
/// </summary>
|
||||
/// <param name="dateStart"></param>
|
||||
/// <param name="dateFinish"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<List<ClientsByDepositDataModel>> GetDataClientsByDepositAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data ClientsByDeposit from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
@@ -147,14 +183,23 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.Any())
|
||||
{
|
||||
throw new InvalidOperationException("No clients with deposits found");
|
||||
}
|
||||
//if (!result.Any())
|
||||
//{
|
||||
// throw new InvalidOperationException("No clients with deposits found");
|
||||
//}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Создание pdf отчета Клиента по Депозитам
|
||||
/// </summary>
|
||||
/// <param name="dateStart"></param>
|
||||
/// <param name="dateFinish"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<Stream> CreateDocumentClientsByDepositAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report ClientsByDeposit from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
@@ -169,24 +214,33 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
|
||||
foreach (var client in data)
|
||||
{
|
||||
tableRows.Add(new string[]
|
||||
{
|
||||
tableRows.Add(
|
||||
[
|
||||
client.ClientSurname,
|
||||
client.ClientName,
|
||||
client.ClientBalance.ToString("N2"),
|
||||
client.DepositRate.ToString("N2"),
|
||||
$"{client.DepositPeriod} мес.",
|
||||
$"{client.FromPeriod.ToShortDateString()} - {client.ToPeriod.ToShortDateString()}"
|
||||
});
|
||||
]);
|
||||
}
|
||||
|
||||
return _basePdfBuilder
|
||||
.AddHeader("Клиенты по вкладам")
|
||||
.AddParagraph($"за период с {dateStart.ToShortDateString()} по {dateFinish.ToShortDateString()}")
|
||||
.AddTable([80, 80, 80, 80, 80, 80], tableRows)
|
||||
.AddTable([25, 25, 25, 25, 25, 25], tableRows)
|
||||
.Build();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных для отчета Депозиты и Кредитные программы по Валютам
|
||||
/// </summary>
|
||||
/// <param name="dateStart"></param>
|
||||
/// <param name="dateFinish"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public async Task<List<CreditProgramAndDepositByCurrencyDataModel>> GetDataDepositAndCreditProgramByCurrencyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data DepositAndCreditProgramByCurrency from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
@@ -215,6 +269,15 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Создание pdf отчета Депозиты и Кредитные программы по Валютам
|
||||
/// </summary>
|
||||
/// <param name="dateStart"></param>
|
||||
/// <param name="dateFinish"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<Stream> CreateDocumentDepositAndCreditProgramByCurrencyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report DepositAndCreditProgramByCurrency from {dateStart} to {dateFinish}", dateStart, dateFinish);
|
||||
@@ -229,27 +292,66 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
|
||||
foreach (var currency in data)
|
||||
{
|
||||
// Вывод информации по кредитным программам
|
||||
for (int i = 0; i < currency.CreditProgramName.Count; i++)
|
||||
{
|
||||
tableRows.Add(new string[]
|
||||
// Вычисляем индекс депозита, если есть соответствующие
|
||||
string depositRate = "—";
|
||||
string depositPeriod = "—";
|
||||
|
||||
// Проверяем, есть ли депозиты для этой валюты и не вышли ли мы за границы массива
|
||||
if (currency.DepositRate.Count > 0)
|
||||
{
|
||||
// Берем индекс по модулю, чтобы не выйти за границы массива
|
||||
int depositIndex = i % currency.DepositRate.Count;
|
||||
depositRate = currency.DepositRate[depositIndex].ToString("N2");
|
||||
depositPeriod = $"{currency.DepositPeriod[depositIndex]} мес.";
|
||||
}
|
||||
|
||||
// Добавляем строку в таблицу
|
||||
tableRows.Add(
|
||||
[
|
||||
currency.CurrencyName,
|
||||
currency.CreditProgramName[i],
|
||||
currency.CreditProgramMaxCost[i].ToString("N2"),
|
||||
currency.DepositRate[i].ToString("N2"),
|
||||
$"{currency.DepositPeriod[i]} мес."
|
||||
});
|
||||
depositRate,
|
||||
depositPeriod
|
||||
]);
|
||||
}
|
||||
|
||||
// Если есть депозиты, но нет кредитных программ, добавляем строки только с депозитами
|
||||
if (currency.CreditProgramName.Count == 0 && currency.DepositRate.Count > 0)
|
||||
{
|
||||
for (int j = 0; j < currency.DepositRate.Count; j++)
|
||||
{
|
||||
tableRows.Add(
|
||||
[
|
||||
currency.CurrencyName,
|
||||
"—",
|
||||
"—",
|
||||
currency.DepositRate[j].ToString("N2"),
|
||||
$"{currency.DepositPeriod[j]} мес."
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _basePdfBuilder
|
||||
.AddHeader("Вклады и кредитные программы по валютам")
|
||||
.AddParagraph($"за период с {dateStart.ToShortDateString()} по {dateFinish.ToShortDateString()}")
|
||||
.AddTable([80, 100, 80, 80, 80], tableRows)
|
||||
.AddTable([25, 30, 25, 25, 25], tableRows)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public async Task<List<DepositByCreditProgramDataModel>> GetDataDepositByCreditProgramAsync(CancellationToken ct)
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных для отчета Депозиты по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<List<DepositByCreditProgramDataModel>> GetDataDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Get data DepositByCreditProgram");
|
||||
var deposits = await Task.Run(() => _depositStorage.GetList(), ct);
|
||||
@@ -261,7 +363,10 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
throw new InvalidOperationException("No deposits with currencies found");
|
||||
}
|
||||
|
||||
return creditPrograms.Select(cp => new DepositByCreditProgramDataModel
|
||||
var filteredPrograms = creditPrograms
|
||||
.Where(cp => creditProgramIds == null || creditProgramIds.Contains(cp.Id));
|
||||
|
||||
return filteredPrograms.Select(cp => new DepositByCreditProgramDataModel
|
||||
{
|
||||
CreditProgramName = cp.Name,
|
||||
DepositRate = deposits.Select(d => d.InterestRate).ToList(),
|
||||
@@ -270,10 +375,18 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateDocumentDepositByCreditProgramAsync(CancellationToken ct)
|
||||
|
||||
/// <summary>
|
||||
/// Создание word отчета Депозиты по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<Stream> CreateDocumentDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create report DepositByCreditProgram");
|
||||
var data = await GetDataDepositByCreditProgramAsync(ct) ?? throw new InvalidOperationException("No found data");
|
||||
var data = await GetDataDepositByCreditProgramAsync(creditProgramIds, ct) ?? throw new InvalidOperationException("No found data");
|
||||
|
||||
var tableRows = new List<string[]>
|
||||
{
|
||||
@@ -284,27 +397,34 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
{
|
||||
for (int i = 0; i < program.DepositRate.Count; i++)
|
||||
{
|
||||
tableRows.Add(new string[]
|
||||
{
|
||||
tableRows.Add(
|
||||
[
|
||||
program.CreditProgramName,
|
||||
program.DepositRate[i].ToString("N2"),
|
||||
program.DepositCost[i].ToString("N2"),
|
||||
program.DepositPeriod[i].ToString()
|
||||
});
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return _baseWordBuilder
|
||||
.AddHeader("Вклады по кредитным программам")
|
||||
.AddParagraph($"Сформировано на дату {DateTime.Now}")
|
||||
.AddTable([3000, 3000, 3000, 3000], tableRows)
|
||||
.AddTable([2000, 2000, 2000, 2000], tableRows)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public async Task<Stream> CreateExcelDocumentDepositByCreditProgramAsync(CancellationToken ct)
|
||||
/// <summary>
|
||||
/// Создание excel отчета Депозиты по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public async Task<Stream> CreateExcelDocumentDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
_logger.LogInformation("Create Excel report DepositByCreditProgram");
|
||||
var data = await GetDataDepositByCreditProgramAsync(ct) ?? throw new InvalidOperationException("No found data");
|
||||
var data = await GetDataDepositByCreditProgramAsync(creditProgramIds, ct) ?? throw new InvalidOperationException("No found data");
|
||||
|
||||
var tableRows = new List<string[]>
|
||||
{
|
||||
@@ -315,20 +435,20 @@ public class ReportContract(IClientStorageContract clientStorage, ICurrencyStora
|
||||
{
|
||||
for (int i = 0; i < program.DepositRate.Count; i++)
|
||||
{
|
||||
tableRows.Add(new string[]
|
||||
{
|
||||
tableRows.Add(
|
||||
[
|
||||
program.CreditProgramName,
|
||||
program.DepositRate[i].ToString("N2"),
|
||||
program.DepositCost[i].ToString("N2"),
|
||||
program.DepositPeriod[i].ToString()
|
||||
});
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return _baseExcelBuilder
|
||||
.AddHeader("Вклады по кредитным программам", 0, 4)
|
||||
.AddParagraph($"Сформировано на дату {DateTime.Now}", 0)
|
||||
.AddTable([3000, 3000, 3000, 3000], tableRows)
|
||||
.AddTable([25, 25, 25, 25], tableRows)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class MigraDocPdfBuilder : BasePdfBuilder
|
||||
// Добавляем столбцы с заданной шириной
|
||||
foreach (var width in columnsWidths)
|
||||
{
|
||||
var widthInCm = width / 28.35;
|
||||
var widthInCm = width / 10.35;
|
||||
var column = table.AddColumn(Unit.FromCentimeter(widthInCm));
|
||||
column.Format.Alignment = ParagraphAlignment.Left;
|
||||
}
|
||||
|
||||
@@ -15,4 +15,6 @@ public interface IClerkAdapter
|
||||
ClerkOperationResponse RegisterClerk(ClerkBindingModel clerkModel);
|
||||
|
||||
ClerkOperationResponse ChangeClerkInfo(ClerkBindingModel clerkModel);
|
||||
|
||||
ClerkOperationResponse Login(LoginBindingModel clerkModel, out string token);
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ namespace BankContracts.AdapterContracts;
|
||||
|
||||
public interface IReportAdapter
|
||||
{
|
||||
Task<ReportOperationResponse> GetDataClientsByCreditProgramAsync(CancellationToken ct);
|
||||
Task<ReportOperationResponse> GetDataClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<ReportOperationResponse> GetDataClientsByDepositAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
Task<ReportOperationResponse> GetDataDepositByCreditProgramAsync(CancellationToken ct);
|
||||
Task<ReportOperationResponse> GetDataDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<ReportOperationResponse> GetDataDepositAndCreditProgramByCurrencyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<ReportOperationResponse> CreateDocumentClientsByCreditProgramAsync(CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateExcelDocumentClientsByCreditProgramAsync(CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateDocumentClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateExcelDocumentClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateDocumentClientsByDepositAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateDocumentDepositByCreditProgramAsync(CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateExcelDocumentDepositByCreditProgramAsync(CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateDocumentDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateExcelDocumentDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<ReportOperationResponse> CreateDocumentDepositAndCreditProgramByCurrencyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
}
|
||||
|
||||
@@ -15,4 +15,6 @@ public interface IStorekeeperAdapter
|
||||
StorekeeperOperationResponse RegisterStorekeeper(StorekeeperBindingModel storekeeperModel);
|
||||
|
||||
StorekeeperOperationResponse ChangeStorekeeperInfo(StorekeeperBindingModel storekeeperModel);
|
||||
|
||||
StorekeeperOperationResponse Login(LoginBindingModel storekeeperModel, out string token);
|
||||
}
|
||||
|
||||
@@ -21,4 +21,7 @@ public class ClerkOperationResponse : OperationResponse
|
||||
|
||||
public static ClerkOperationResponse InternalServerError(string message) =>
|
||||
InternalServerError<ClerkOperationResponse>(message);
|
||||
|
||||
public static ClerkOperationResponse Unauthorized(string message) =>
|
||||
Unauthorized<ClerkOperationResponse>(message);
|
||||
}
|
||||
|
||||
@@ -18,4 +18,7 @@ public class ReportOperationResponse : OperationResponse
|
||||
public static ReportOperationResponse BadRequest(string message) => BadRequest<ReportOperationResponse>(message);
|
||||
|
||||
public static ReportOperationResponse InternalServerError(string message) => InternalServerError<ReportOperationResponse>(message);
|
||||
|
||||
public Stream? GetStream() => Result as Stream;
|
||||
public string? GetFileName() => FileName;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ public class StorekeeperOperationResponse : OperationResponse
|
||||
public static StorekeeperOperationResponse OK(List<StorekeeperViewModel> data) =>
|
||||
OK<StorekeeperOperationResponse, List<StorekeeperViewModel>>(data);
|
||||
|
||||
public static StorekeeperOperationResponse OK(string token) =>
|
||||
OK<StorekeeperOperationResponse, string>(token);
|
||||
|
||||
public static StorekeeperOperationResponse OK(StorekeeperViewModel data) =>
|
||||
OK<StorekeeperOperationResponse, StorekeeperViewModel>(data);
|
||||
|
||||
@@ -21,4 +24,7 @@ public class StorekeeperOperationResponse : OperationResponse
|
||||
|
||||
public static StorekeeperOperationResponse InternalServerError(string message) =>
|
||||
InternalServerError<StorekeeperOperationResponse>(message);
|
||||
|
||||
public static StorekeeperOperationResponse Unauthorized(string message) =>
|
||||
Unauthorized<StorekeeperOperationResponse>(message);
|
||||
}
|
||||
|
||||
8
TheBank/BankContracts/BindingModels/LoginBindingModel.cs
Normal file
8
TheBank/BankContracts/BindingModels/LoginBindingModel.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace BankContracts.BindingModels;
|
||||
|
||||
public class LoginBindingModel
|
||||
{
|
||||
public required string Login { get; set; }
|
||||
|
||||
public required string Password { get; set; }
|
||||
}
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
public class MailSendInfoBindingModel
|
||||
{
|
||||
public string MailAddress { get; set; } = string.Empty;
|
||||
public string ToEmail { get; set; } = string.Empty;
|
||||
|
||||
public string Subject { get; set; } = string.Empty;
|
||||
public string Text { get; set; } = string.Empty;
|
||||
public MemoryStream Attachment { get; set; } = new MemoryStream();
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
public string Body { get; set; } = string.Empty;
|
||||
|
||||
public string? AttachmentPath { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace BankContracts.BindingModels;
|
||||
|
||||
public class ReportMailSendInfoBindingModel
|
||||
{
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public string Subject { get; set; } = string.Empty;
|
||||
public string Body { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CreditProgramReportMailSendInfoBindingModel : ReportMailSendInfoBindingModel
|
||||
{
|
||||
public List<string> CreditProgramIds { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DepositReportMailSendInfoBindingModel : ReportMailSendInfoBindingModel
|
||||
{
|
||||
// Для отчетов по депозитам дополнительные поля передаются через query параметры
|
||||
}
|
||||
@@ -4,16 +4,16 @@ namespace BankContracts.BusinessLogicContracts;
|
||||
|
||||
public interface IReportContract
|
||||
{
|
||||
Task<List<ClientsByCreditProgramDataModel>> GetDataClientsByCreditProgramAsync(CancellationToken ct);
|
||||
Task<Stream> CreateDocumentClientsByCreditProgramAsync(CancellationToken ct);
|
||||
Task<Stream> CreateExcelDocumentClientsByCreditProgramAsync(CancellationToken ct);
|
||||
Task<List<ClientsByCreditProgramDataModel>> GetDataClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<Stream> CreateDocumentClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<Stream> CreateExcelDocumentClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
|
||||
Task<List<ClientsByDepositDataModel>> GetDataClientsByDepositAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
Task<Stream> CreateDocumentClientsByDepositAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
Task<List<DepositByCreditProgramDataModel>> GetDataDepositByCreditProgramAsync(CancellationToken ct);
|
||||
Task<Stream> CreateDocumentDepositByCreditProgramAsync(CancellationToken ct);
|
||||
Task<Stream> CreateExcelDocumentDepositByCreditProgramAsync(CancellationToken ct);
|
||||
Task<List<DepositByCreditProgramDataModel>> GetDataDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<Stream> CreateDocumentDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
Task<Stream> CreateExcelDocumentDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct);
|
||||
|
||||
Task<List<CreditProgramAndDepositByCurrencyDataModel>> GetDataDepositAndCreditProgramByCurrencyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
Task<Stream> CreateDocumentDepositAndCreditProgramByCurrencyAsync(DateTime dateStart, DateTime dateFinish, CancellationToken ct);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
public class ClientsByCreditProgramDataModel
|
||||
{
|
||||
public required string CreditProgramId { get; set; }
|
||||
public required string CreditProgramName { get; set; }
|
||||
public required List<string> ClientSurname { get; set; }
|
||||
public required List<string> ClientName { get; set; }
|
||||
|
||||
@@ -28,7 +28,7 @@ public class OperationResponse
|
||||
}
|
||||
if (Result is Stream stream)
|
||||
{
|
||||
return new FileStreamResult(stream, "application/octetstream")
|
||||
return new FileStreamResult(stream, "application/octet-stream")
|
||||
{
|
||||
FileDownloadName = FileName
|
||||
};
|
||||
@@ -58,4 +58,8 @@ public class OperationResponse
|
||||
protected static TResult InternalServerError<TResult>(string? errorMessage = null)
|
||||
where TResult : OperationResponse, new() =>
|
||||
new() { StatusCode = HttpStatusCode.InternalServerError, Result = errorMessage };
|
||||
|
||||
protected static TResult Unauthorized<TResult>(string? errorMessage = null)
|
||||
where TResult : OperationResponse, new() =>
|
||||
new() { StatusCode = HttpStatusCode.Unauthorized, Result = errorMessage };
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ internal class BankDbContext(IConfigurationDatabase configurationDatabase) : DbC
|
||||
modelBuilder.Entity<CreditProgram>()
|
||||
.HasIndex(x => x.Name)
|
||||
.IsUnique();
|
||||
|
||||
|
||||
modelBuilder.Entity<Currency>()
|
||||
.HasIndex(x => x.Abbreviation)
|
||||
.IsUnique();
|
||||
@@ -80,17 +80,17 @@ internal class BankDbContext(IConfigurationDatabase configurationDatabase) : DbC
|
||||
public DbSet<Clerk> Clerks { get; set; }
|
||||
|
||||
public DbSet<Client> Clients { get; set; }
|
||||
|
||||
|
||||
public DbSet<CreditProgram> CreditPrograms { get; set; }
|
||||
|
||||
|
||||
public DbSet<Currency> Currencies { get; set; }
|
||||
|
||||
|
||||
public DbSet<Deposit> Deposits { get; set; }
|
||||
|
||||
|
||||
public DbSet<Period> Periods { get; set; }
|
||||
|
||||
|
||||
public DbSet<Replenishment> Replenishments { get; set; }
|
||||
|
||||
|
||||
public DbSet<Storekeeper> Storekeepers { get; set; }
|
||||
|
||||
public DbSet<DepositCurrency> DepositCurrencies { get; set; }
|
||||
|
||||
17
TheBank/BankDatabase/DesignTimeDbContextFactory.cs
Normal file
17
TheBank/BankDatabase/DesignTimeDbContextFactory.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using BankContracts.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
|
||||
namespace BankDatabase;
|
||||
|
||||
//public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<BankDbContext>
|
||||
//{
|
||||
// //public BankDbContext CreateDbContext(string[] args)
|
||||
// //{
|
||||
// // return new BankDbContext(new ConfigurationDatabase());
|
||||
// //}
|
||||
//}
|
||||
|
||||
internal class ConfigurationDatabase : IConfigurationDatabase
|
||||
{
|
||||
public string ConnectionString => "Host=127.0.0.1;Port=5432;Database=BankTest;Username=postgres;Password=admin123;";
|
||||
}
|
||||
@@ -85,7 +85,7 @@ internal class ClerkStorageContract : IClerkStorageContract
|
||||
_dbContext.Clerks.Add(_mapper.Map<Clerk>(clerkDataModel));
|
||||
_dbContext.SaveChanges();
|
||||
}
|
||||
catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict")
|
||||
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "PK_Clerks" })
|
||||
{
|
||||
_dbContext.ChangeTracker.Clear();
|
||||
throw new ElementExistsException($"Id {clerkDataModel.Id}");
|
||||
|
||||
@@ -109,7 +109,7 @@ internal class DepositStorageContract : IDepositStorageContract
|
||||
catch (InvalidOperationException ex) when (ex.TargetSite?.Name == "ThrowIdentityConflict")
|
||||
{
|
||||
_dbContext.ChangeTracker.Clear();
|
||||
throw new ElementExistsException($"Id {depositDataModel.Id }");
|
||||
throw new ElementExistsException($"Id {depositDataModel.Id}");
|
||||
}
|
||||
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Deposits_InterestRate" })
|
||||
{
|
||||
@@ -127,40 +127,76 @@ internal class DepositStorageContract : IDepositStorageContract
|
||||
{
|
||||
try
|
||||
{
|
||||
var transaction = _dbContext.Database.BeginTransaction();
|
||||
using var transaction = _dbContext.Database.BeginTransaction();
|
||||
try
|
||||
{
|
||||
var element = GetDepositById(depositDataModel.Id) ?? throw new ElementNotFoundException(depositDataModel.Id);
|
||||
// Загружаем существующий вклад со связями
|
||||
var existingDeposit = _dbContext.Deposits
|
||||
.Include(d => d.DepositCurrencies)
|
||||
.FirstOrDefault(d => d.Id == depositDataModel.Id);
|
||||
|
||||
if (existingDeposit == null)
|
||||
{
|
||||
throw new ElementNotFoundException(depositDataModel.Id);
|
||||
}
|
||||
|
||||
// Обновляем основные поля вклада
|
||||
existingDeposit.InterestRate = depositDataModel.InterestRate;
|
||||
existingDeposit.Cost = depositDataModel.Cost;
|
||||
existingDeposit.Period = depositDataModel.Period;
|
||||
existingDeposit.ClerkId = depositDataModel.ClerkId;
|
||||
|
||||
// Обновляем связи с валютами, если они переданы
|
||||
if (depositDataModel.Currencies != null)
|
||||
{
|
||||
if (element.DepositCurrencies != null || element.DepositCurrencies?.Count >= 0)
|
||||
// Удаляем все существующие связи
|
||||
if (existingDeposit.DepositCurrencies != null)
|
||||
{
|
||||
_dbContext.DepositCurrencies.RemoveRange(element.DepositCurrencies);
|
||||
_dbContext.DepositCurrencies.RemoveRange(existingDeposit.DepositCurrencies);
|
||||
}
|
||||
|
||||
element.DepositCurrencies = _mapper.Map<List<DepositCurrency>>(depositDataModel.Currencies);
|
||||
// Сохраняем изменения для применения удаления
|
||||
_dbContext.SaveChanges();
|
||||
|
||||
// Создаем новые связи
|
||||
existingDeposit.DepositCurrencies = depositDataModel.Currencies.Select(c =>
|
||||
new DepositCurrency
|
||||
{
|
||||
DepositId = existingDeposit.Id,
|
||||
CurrencyId = c.CurrencyId
|
||||
}).ToList();
|
||||
}
|
||||
_mapper.Map(depositDataModel, element);
|
||||
|
||||
// Сохраняем все изменения
|
||||
_dbContext.SaveChanges();
|
||||
transaction.Commit();
|
||||
|
||||
// Выводим отладочную информацию
|
||||
System.Console.WriteLine($"Updated deposit {existingDeposit.Id} with {existingDeposit.DepositCurrencies?.Count ?? 0} currency relations");
|
||||
foreach (var relation in existingDeposit.DepositCurrencies ?? Enumerable.Empty<DepositCurrency>())
|
||||
{
|
||||
System.Console.WriteLine($"Currency relation: DepositId={relation.DepositId}, CurrencyId={relation.CurrencyId}");
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
transaction.Rollback();
|
||||
throw;
|
||||
System.Console.WriteLine($"Error in transaction: {ex.Message}");
|
||||
if (ex is ElementNotFoundException)
|
||||
throw;
|
||||
throw new StorageException(ex.Message);
|
||||
}
|
||||
}
|
||||
catch (ElementNotFoundException)
|
||||
{
|
||||
_dbContext.ChangeTracker.Clear();
|
||||
throw;
|
||||
}
|
||||
catch (DbUpdateException ex) when (ex.InnerException is PostgresException { ConstraintName: "IX_Deposits_InterestRate" })
|
||||
{
|
||||
_dbContext.ChangeTracker.Clear();
|
||||
throw new ElementExistsException($"InterestRate {depositDataModel.InterestRate}");
|
||||
}
|
||||
catch (ElementNotFoundException)
|
||||
{
|
||||
_dbContext.ChangeTracker.Clear();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dbContext.ChangeTracker.Clear();
|
||||
|
||||
562
TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.Designer.cs
generated
Normal file
562
TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.Designer.cs
generated
Normal file
@@ -0,0 +1,562 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using BankDatabase;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BankDatabase.Migrations
|
||||
{
|
||||
[DbContext(typeof(BankDbContext))]
|
||||
[Migration("20250518195627_InitialCreate")]
|
||||
partial class InitialCreate
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.4")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Clerk", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Login")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MiddleName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Login")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("PhoneNumber")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Clerks");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Client", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Balance")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("ClerkId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClerkId");
|
||||
|
||||
b.ToTable("Clients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.ClientCreditProgram", b =>
|
||||
{
|
||||
b.Property<string>("ClientId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CreditProgramId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("ClientId", "CreditProgramId");
|
||||
|
||||
b.HasIndex("CreditProgramId");
|
||||
|
||||
b.ToTable("CreditProgramClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgram", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Cost")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal>("MaxCost")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PeriodId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("StorekeeperId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("PeriodId");
|
||||
|
||||
b.HasIndex("StorekeeperId");
|
||||
|
||||
b.ToTable("CreditPrograms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgramCurrency", b =>
|
||||
{
|
||||
b.Property<string>("CreditProgramId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CurrencyId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("CreditProgramId", "CurrencyId");
|
||||
|
||||
b.HasIndex("CurrencyId");
|
||||
|
||||
b.ToTable("CurrencyCreditPrograms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Currency", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Abbreviation")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Cost")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("StorekeeperId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Abbreviation")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("StorekeeperId");
|
||||
|
||||
b.ToTable("Currencies");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Deposit", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClerkId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Cost")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<float>("InterestRate")
|
||||
.HasColumnType("real");
|
||||
|
||||
b.Property<int>("Period")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClerkId");
|
||||
|
||||
b.ToTable("Deposits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.DepositClient", b =>
|
||||
{
|
||||
b.Property<string>("DepositId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("DepositId", "ClientId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.ToTable("DepositClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.DepositCurrency", b =>
|
||||
{
|
||||
b.Property<string>("DepositId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CurrencyId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("DepositId", "CurrencyId");
|
||||
|
||||
b.HasIndex("CurrencyId");
|
||||
|
||||
b.ToTable("DepositCurrencies");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Period", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("EndTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime>("StartTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("StorekeeperId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StorekeeperId");
|
||||
|
||||
b.ToTable("Periods");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Replenishment", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("ClerkId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("DepositId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClerkId");
|
||||
|
||||
b.HasIndex("DepositId");
|
||||
|
||||
b.ToTable("Replenishments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Storekeeper", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Login")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MiddleName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Login")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("PhoneNumber")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Storekeepers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Client", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Clerk", "Clerk")
|
||||
.WithMany("Clients")
|
||||
.HasForeignKey("ClerkId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Clerk");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.ClientCreditProgram", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Client", "Client")
|
||||
.WithMany("CreditProgramClients")
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.CreditProgram", "CreditProgram")
|
||||
.WithMany("CreditProgramClients")
|
||||
.HasForeignKey("CreditProgramId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Client");
|
||||
|
||||
b.Navigation("CreditProgram");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgram", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Period", "Period")
|
||||
.WithMany("CreditPrograms")
|
||||
.HasForeignKey("PeriodId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper")
|
||||
.WithMany("CreditPrograms")
|
||||
.HasForeignKey("StorekeeperId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Period");
|
||||
|
||||
b.Navigation("Storekeeper");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgramCurrency", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.CreditProgram", "CreditProgram")
|
||||
.WithMany("CurrencyCreditPrograms")
|
||||
.HasForeignKey("CreditProgramId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Currency", "Currency")
|
||||
.WithMany("CurrencyCreditPrograms")
|
||||
.HasForeignKey("CurrencyId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("CreditProgram");
|
||||
|
||||
b.Navigation("Currency");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Currency", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper")
|
||||
.WithMany("Currencies")
|
||||
.HasForeignKey("StorekeeperId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Storekeeper");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Deposit", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Clerk", "Clerk")
|
||||
.WithMany("Deposits")
|
||||
.HasForeignKey("ClerkId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Clerk");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.DepositClient", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Client", "Client")
|
||||
.WithMany("DepositClients")
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Deposit", "Deposit")
|
||||
.WithMany("DepositClients")
|
||||
.HasForeignKey("DepositId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Client");
|
||||
|
||||
b.Navigation("Deposit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.DepositCurrency", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Currency", "Currency")
|
||||
.WithMany("DepositCurrencies")
|
||||
.HasForeignKey("CurrencyId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Deposit", "Deposit")
|
||||
.WithMany("DepositCurrencies")
|
||||
.HasForeignKey("DepositId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Currency");
|
||||
|
||||
b.Navigation("Deposit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Period", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper")
|
||||
.WithMany("Periods")
|
||||
.HasForeignKey("StorekeeperId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Storekeeper");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Replenishment", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Clerk", "Clerk")
|
||||
.WithMany("Replenishments")
|
||||
.HasForeignKey("ClerkId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Deposit", "Deposit")
|
||||
.WithMany("Replenishments")
|
||||
.HasForeignKey("DepositId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Clerk");
|
||||
|
||||
b.Navigation("Deposit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Clerk", b =>
|
||||
{
|
||||
b.Navigation("Clients");
|
||||
|
||||
b.Navigation("Deposits");
|
||||
|
||||
b.Navigation("Replenishments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Client", b =>
|
||||
{
|
||||
b.Navigation("CreditProgramClients");
|
||||
|
||||
b.Navigation("DepositClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgram", b =>
|
||||
{
|
||||
b.Navigation("CreditProgramClients");
|
||||
|
||||
b.Navigation("CurrencyCreditPrograms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Currency", b =>
|
||||
{
|
||||
b.Navigation("CurrencyCreditPrograms");
|
||||
|
||||
b.Navigation("DepositCurrencies");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Deposit", b =>
|
||||
{
|
||||
b.Navigation("DepositClients");
|
||||
|
||||
b.Navigation("DepositCurrencies");
|
||||
|
||||
b.Navigation("Replenishments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Period", b =>
|
||||
{
|
||||
b.Navigation("CreditPrograms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Storekeeper", b =>
|
||||
{
|
||||
b.Navigation("CreditPrograms");
|
||||
|
||||
b.Navigation("Currencies");
|
||||
|
||||
b.Navigation("Periods");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
433
TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.cs
Normal file
433
TheBank/BankDatabase/Migrations/20250518195627_InitialCreate.cs
Normal file
@@ -0,0 +1,433 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BankDatabase.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialCreate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Clerks",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "text", nullable: false),
|
||||
Name = table.Column<string>(type: "text", nullable: false),
|
||||
Surname = table.Column<string>(type: "text", nullable: false),
|
||||
MiddleName = table.Column<string>(type: "text", nullable: false),
|
||||
Login = table.Column<string>(type: "text", nullable: false),
|
||||
Password = table.Column<string>(type: "text", nullable: false),
|
||||
Email = table.Column<string>(type: "text", nullable: false),
|
||||
PhoneNumber = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Clerks", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Storekeepers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "text", nullable: false),
|
||||
Name = table.Column<string>(type: "text", nullable: false),
|
||||
Surname = table.Column<string>(type: "text", nullable: false),
|
||||
MiddleName = table.Column<string>(type: "text", nullable: false),
|
||||
Login = table.Column<string>(type: "text", nullable: false),
|
||||
Password = table.Column<string>(type: "text", nullable: false),
|
||||
Email = table.Column<string>(type: "text", nullable: false),
|
||||
PhoneNumber = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Storekeepers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Clients",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "text", nullable: false),
|
||||
Name = table.Column<string>(type: "text", nullable: false),
|
||||
Surname = table.Column<string>(type: "text", nullable: false),
|
||||
Balance = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
ClerkId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Clients", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Clients_Clerks_ClerkId",
|
||||
column: x => x.ClerkId,
|
||||
principalTable: "Clerks",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Deposits",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "text", nullable: false),
|
||||
InterestRate = table.Column<float>(type: "real", nullable: false),
|
||||
Cost = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
Period = table.Column<int>(type: "integer", nullable: false),
|
||||
ClerkId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Deposits", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Deposits_Clerks_ClerkId",
|
||||
column: x => x.ClerkId,
|
||||
principalTable: "Clerks",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Currencies",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "text", nullable: false),
|
||||
Name = table.Column<string>(type: "text", nullable: false),
|
||||
Abbreviation = table.Column<string>(type: "text", nullable: false),
|
||||
Cost = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
StorekeeperId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Currencies", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Currencies_Storekeepers_StorekeeperId",
|
||||
column: x => x.StorekeeperId,
|
||||
principalTable: "Storekeepers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Periods",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "text", nullable: false),
|
||||
StartTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
EndTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
StorekeeperId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Periods", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Periods_Storekeepers_StorekeeperId",
|
||||
column: x => x.StorekeeperId,
|
||||
principalTable: "Storekeepers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DepositClients",
|
||||
columns: table => new
|
||||
{
|
||||
DepositId = table.Column<string>(type: "text", nullable: false),
|
||||
ClientId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_DepositClients", x => new { x.DepositId, x.ClientId });
|
||||
table.ForeignKey(
|
||||
name: "FK_DepositClients_Clients_ClientId",
|
||||
column: x => x.ClientId,
|
||||
principalTable: "Clients",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_DepositClients_Deposits_DepositId",
|
||||
column: x => x.DepositId,
|
||||
principalTable: "Deposits",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Replenishments",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "text", nullable: false),
|
||||
Amount = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
Date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
DepositId = table.Column<string>(type: "text", nullable: false),
|
||||
ClerkId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Replenishments", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Replenishments_Clerks_ClerkId",
|
||||
column: x => x.ClerkId,
|
||||
principalTable: "Clerks",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "FK_Replenishments_Deposits_DepositId",
|
||||
column: x => x.DepositId,
|
||||
principalTable: "Deposits",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DepositCurrencies",
|
||||
columns: table => new
|
||||
{
|
||||
DepositId = table.Column<string>(type: "text", nullable: false),
|
||||
CurrencyId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_DepositCurrencies", x => new { x.DepositId, x.CurrencyId });
|
||||
table.ForeignKey(
|
||||
name: "FK_DepositCurrencies_Currencies_CurrencyId",
|
||||
column: x => x.CurrencyId,
|
||||
principalTable: "Currencies",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_DepositCurrencies_Deposits_DepositId",
|
||||
column: x => x.DepositId,
|
||||
principalTable: "Deposits",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CreditPrograms",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "text", nullable: false),
|
||||
Name = table.Column<string>(type: "text", nullable: false),
|
||||
Cost = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
MaxCost = table.Column<decimal>(type: "numeric", nullable: false),
|
||||
StorekeeperId = table.Column<string>(type: "text", nullable: false),
|
||||
PeriodId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CreditPrograms", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CreditPrograms_Periods_PeriodId",
|
||||
column: x => x.PeriodId,
|
||||
principalTable: "Periods",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_CreditPrograms_Storekeepers_StorekeeperId",
|
||||
column: x => x.StorekeeperId,
|
||||
principalTable: "Storekeepers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CreditProgramClients",
|
||||
columns: table => new
|
||||
{
|
||||
ClientId = table.Column<string>(type: "text", nullable: false),
|
||||
CreditProgramId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CreditProgramClients", x => new { x.ClientId, x.CreditProgramId });
|
||||
table.ForeignKey(
|
||||
name: "FK_CreditProgramClients_Clients_ClientId",
|
||||
column: x => x.ClientId,
|
||||
principalTable: "Clients",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_CreditProgramClients_CreditPrograms_CreditProgramId",
|
||||
column: x => x.CreditProgramId,
|
||||
principalTable: "CreditPrograms",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CurrencyCreditPrograms",
|
||||
columns: table => new
|
||||
{
|
||||
CreditProgramId = table.Column<string>(type: "text", nullable: false),
|
||||
CurrencyId = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CurrencyCreditPrograms", x => new { x.CreditProgramId, x.CurrencyId });
|
||||
table.ForeignKey(
|
||||
name: "FK_CurrencyCreditPrograms_CreditPrograms_CreditProgramId",
|
||||
column: x => x.CreditProgramId,
|
||||
principalTable: "CreditPrograms",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_CurrencyCreditPrograms_Currencies_CurrencyId",
|
||||
column: x => x.CurrencyId,
|
||||
principalTable: "Currencies",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Clerks_Email",
|
||||
table: "Clerks",
|
||||
column: "Email",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Clerks_Login",
|
||||
table: "Clerks",
|
||||
column: "Login",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Clerks_PhoneNumber",
|
||||
table: "Clerks",
|
||||
column: "PhoneNumber",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Clients_ClerkId",
|
||||
table: "Clients",
|
||||
column: "ClerkId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CreditProgramClients_CreditProgramId",
|
||||
table: "CreditProgramClients",
|
||||
column: "CreditProgramId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CreditPrograms_Name",
|
||||
table: "CreditPrograms",
|
||||
column: "Name",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CreditPrograms_PeriodId",
|
||||
table: "CreditPrograms",
|
||||
column: "PeriodId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CreditPrograms_StorekeeperId",
|
||||
table: "CreditPrograms",
|
||||
column: "StorekeeperId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Currencies_Abbreviation",
|
||||
table: "Currencies",
|
||||
column: "Abbreviation",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Currencies_StorekeeperId",
|
||||
table: "Currencies",
|
||||
column: "StorekeeperId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CurrencyCreditPrograms_CurrencyId",
|
||||
table: "CurrencyCreditPrograms",
|
||||
column: "CurrencyId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DepositClients_ClientId",
|
||||
table: "DepositClients",
|
||||
column: "ClientId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DepositCurrencies_CurrencyId",
|
||||
table: "DepositCurrencies",
|
||||
column: "CurrencyId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Deposits_ClerkId",
|
||||
table: "Deposits",
|
||||
column: "ClerkId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Periods_StorekeeperId",
|
||||
table: "Periods",
|
||||
column: "StorekeeperId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Replenishments_ClerkId",
|
||||
table: "Replenishments",
|
||||
column: "ClerkId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Replenishments_DepositId",
|
||||
table: "Replenishments",
|
||||
column: "DepositId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Storekeepers_Email",
|
||||
table: "Storekeepers",
|
||||
column: "Email",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Storekeepers_Login",
|
||||
table: "Storekeepers",
|
||||
column: "Login",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Storekeepers_PhoneNumber",
|
||||
table: "Storekeepers",
|
||||
column: "PhoneNumber",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "CreditProgramClients");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CurrencyCreditPrograms");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "DepositClients");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "DepositCurrencies");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Replenishments");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CreditPrograms");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Clients");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Currencies");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Deposits");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Periods");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Clerks");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Storekeepers");
|
||||
}
|
||||
}
|
||||
}
|
||||
559
TheBank/BankDatabase/Migrations/BankDbContextModelSnapshot.cs
Normal file
559
TheBank/BankDatabase/Migrations/BankDbContextModelSnapshot.cs
Normal file
@@ -0,0 +1,559 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using BankDatabase;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BankDatabase.Migrations
|
||||
{
|
||||
[DbContext(typeof(BankDbContext))]
|
||||
partial class BankDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.4")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Clerk", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Login")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MiddleName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Login")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("PhoneNumber")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Clerks");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Client", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Balance")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("ClerkId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClerkId");
|
||||
|
||||
b.ToTable("Clients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.ClientCreditProgram", b =>
|
||||
{
|
||||
b.Property<string>("ClientId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CreditProgramId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("ClientId", "CreditProgramId");
|
||||
|
||||
b.HasIndex("CreditProgramId");
|
||||
|
||||
b.ToTable("CreditProgramClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgram", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Cost")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<decimal>("MaxCost")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PeriodId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("StorekeeperId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("PeriodId");
|
||||
|
||||
b.HasIndex("StorekeeperId");
|
||||
|
||||
b.ToTable("CreditPrograms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgramCurrency", b =>
|
||||
{
|
||||
b.Property<string>("CreditProgramId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CurrencyId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("CreditProgramId", "CurrencyId");
|
||||
|
||||
b.HasIndex("CurrencyId");
|
||||
|
||||
b.ToTable("CurrencyCreditPrograms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Currency", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Abbreviation")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Cost")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("StorekeeperId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Abbreviation")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("StorekeeperId");
|
||||
|
||||
b.ToTable("Currencies");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Deposit", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClerkId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Cost")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<float>("InterestRate")
|
||||
.HasColumnType("real");
|
||||
|
||||
b.Property<int>("Period")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClerkId");
|
||||
|
||||
b.ToTable("Deposits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.DepositClient", b =>
|
||||
{
|
||||
b.Property<string>("DepositId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("DepositId", "ClientId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.ToTable("DepositClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.DepositCurrency", b =>
|
||||
{
|
||||
b.Property<string>("DepositId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("CurrencyId")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("DepositId", "CurrencyId");
|
||||
|
||||
b.HasIndex("CurrencyId");
|
||||
|
||||
b.ToTable("DepositCurrencies");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Period", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("EndTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime>("StartTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("StorekeeperId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("StorekeeperId");
|
||||
|
||||
b.ToTable("Periods");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Replenishment", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("ClerkId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("DepositId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClerkId");
|
||||
|
||||
b.HasIndex("DepositId");
|
||||
|
||||
b.ToTable("Replenishments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Storekeeper", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Login")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("MiddleName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Login")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("PhoneNumber")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Storekeepers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Client", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Clerk", "Clerk")
|
||||
.WithMany("Clients")
|
||||
.HasForeignKey("ClerkId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Clerk");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.ClientCreditProgram", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Client", "Client")
|
||||
.WithMany("CreditProgramClients")
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.CreditProgram", "CreditProgram")
|
||||
.WithMany("CreditProgramClients")
|
||||
.HasForeignKey("CreditProgramId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Client");
|
||||
|
||||
b.Navigation("CreditProgram");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgram", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Period", "Period")
|
||||
.WithMany("CreditPrograms")
|
||||
.HasForeignKey("PeriodId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper")
|
||||
.WithMany("CreditPrograms")
|
||||
.HasForeignKey("StorekeeperId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Period");
|
||||
|
||||
b.Navigation("Storekeeper");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgramCurrency", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.CreditProgram", "CreditProgram")
|
||||
.WithMany("CurrencyCreditPrograms")
|
||||
.HasForeignKey("CreditProgramId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Currency", "Currency")
|
||||
.WithMany("CurrencyCreditPrograms")
|
||||
.HasForeignKey("CurrencyId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("CreditProgram");
|
||||
|
||||
b.Navigation("Currency");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Currency", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper")
|
||||
.WithMany("Currencies")
|
||||
.HasForeignKey("StorekeeperId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Storekeeper");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Deposit", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Clerk", "Clerk")
|
||||
.WithMany("Deposits")
|
||||
.HasForeignKey("ClerkId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Clerk");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.DepositClient", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Client", "Client")
|
||||
.WithMany("DepositClients")
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Deposit", "Deposit")
|
||||
.WithMany("DepositClients")
|
||||
.HasForeignKey("DepositId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Client");
|
||||
|
||||
b.Navigation("Deposit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.DepositCurrency", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Currency", "Currency")
|
||||
.WithMany("DepositCurrencies")
|
||||
.HasForeignKey("CurrencyId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Deposit", "Deposit")
|
||||
.WithMany("DepositCurrencies")
|
||||
.HasForeignKey("DepositId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Currency");
|
||||
|
||||
b.Navigation("Deposit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Period", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Storekeeper", "Storekeeper")
|
||||
.WithMany("Periods")
|
||||
.HasForeignKey("StorekeeperId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Storekeeper");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Replenishment", b =>
|
||||
{
|
||||
b.HasOne("BankDatabase.Models.Clerk", "Clerk")
|
||||
.WithMany("Replenishments")
|
||||
.HasForeignKey("ClerkId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("BankDatabase.Models.Deposit", "Deposit")
|
||||
.WithMany("Replenishments")
|
||||
.HasForeignKey("DepositId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Clerk");
|
||||
|
||||
b.Navigation("Deposit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Clerk", b =>
|
||||
{
|
||||
b.Navigation("Clients");
|
||||
|
||||
b.Navigation("Deposits");
|
||||
|
||||
b.Navigation("Replenishments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Client", b =>
|
||||
{
|
||||
b.Navigation("CreditProgramClients");
|
||||
|
||||
b.Navigation("DepositClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.CreditProgram", b =>
|
||||
{
|
||||
b.Navigation("CreditProgramClients");
|
||||
|
||||
b.Navigation("CurrencyCreditPrograms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Currency", b =>
|
||||
{
|
||||
b.Navigation("CurrencyCreditPrograms");
|
||||
|
||||
b.Navigation("DepositCurrencies");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Deposit", b =>
|
||||
{
|
||||
b.Navigation("DepositClients");
|
||||
|
||||
b.Navigation("DepositCurrencies");
|
||||
|
||||
b.Navigation("Replenishments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Period", b =>
|
||||
{
|
||||
b.Navigation("CreditPrograms");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("BankDatabase.Models.Storekeeper", b =>
|
||||
{
|
||||
b.Navigation("CreditPrograms");
|
||||
|
||||
b.Navigation("Currencies");
|
||||
|
||||
b.Navigation("Periods");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class Clerk
|
||||
public class Clerk
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class Client
|
||||
public class Client
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace BankDatabase.Models;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
class ClientCreditProgram
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
public class ClientCreditProgram
|
||||
{
|
||||
public required string ClientId { get; set; }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class CreditProgram
|
||||
public class CreditProgram
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class CreditProgramCurrency
|
||||
public class CreditProgramCurrency
|
||||
{
|
||||
public required string CreditProgramId { get; set; }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class Currency
|
||||
public class Currency
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class Deposit
|
||||
public class Deposit
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace BankDatabase.Models;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
class DepositClient
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
public class DepositClient
|
||||
{
|
||||
public required string DepositId { get; set; }
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace BankDatabase.Models;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
class DepositCurrency
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
public class DepositCurrency
|
||||
{
|
||||
public required string DepositId { get; set; }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class Period
|
||||
public class Period
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class Replenishment
|
||||
public class Replenishment
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace BankDatabase.Models;
|
||||
|
||||
class Storekeeper
|
||||
public class Storekeeper
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
|
||||
|
||||
@@ -5,5 +5,5 @@ namespace BankTests.Infrastructure;
|
||||
internal class ConfigurationDatabase : IConfigurationDatabase
|
||||
{
|
||||
public string ConnectionString =>
|
||||
"Host=127.0.0.1;Port=5432;Database=TitanicTest;Username=postgres;Password=postgres;Include Error Detail=true";
|
||||
"Host=127.0.0.1;Port=5432;Database=TitanicTest;Username=postgres;Password=admin123;Include Error Detail=true";
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Text;
|
||||
namespace BankTests.ReportContractTests;
|
||||
|
||||
[TestFixture]
|
||||
internal class ReportContractTestss
|
||||
internal class ReportContractTests
|
||||
{
|
||||
private ReportContract _reportContract;
|
||||
private Mock<IClientStorageContract> _clientStorage;
|
||||
@@ -65,12 +65,37 @@ internal class ReportContractTestss
|
||||
new DepositDataModel("d1", 5, 1000, 12, "cl", new List<DepositCurrencyDataModel>())
|
||||
});
|
||||
|
||||
var result = await _reportContract.GetDataDepositByCreditProgramAsync(ct);
|
||||
var result = await _reportContract.GetDataDepositByCreditProgramAsync(null, ct);
|
||||
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.Count, Is.GreaterThanOrEqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetDataDepositByCreditProgramAsync_WithFilter_ReturnsFilteredData()
|
||||
{
|
||||
var ct = CancellationToken.None;
|
||||
var creditProgramIds = new List<string> { "1" };
|
||||
|
||||
_creditProgramStorage.Setup(x => x.GetList(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Returns(new List<CreditProgramDataModel>
|
||||
{
|
||||
new CreditProgramDataModel("1", "Программа 1", 100, 200, "sk", "p", new List<CreditProgramCurrencyDataModel> { new() { CurrencyId = "1" } }),
|
||||
new CreditProgramDataModel("2", "Программа 2", 100, 200, "sk", "p", new List<CreditProgramCurrencyDataModel> { new() { CurrencyId = "1" } })
|
||||
});
|
||||
_depositStorage.Setup(x => x.GetList(It.IsAny<string>()))
|
||||
.Returns(new List<DepositDataModel>
|
||||
{
|
||||
new DepositDataModel("d1", 5, 1000, 12, "cl", new List<DepositCurrencyDataModel> { new() { CurrencyId = "1" } })
|
||||
});
|
||||
|
||||
var result = await _reportContract.GetDataDepositByCreditProgramAsync(creditProgramIds, ct);
|
||||
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.Count, Is.EqualTo(1));
|
||||
Assert.That(result[0].CreditProgramName, Is.EqualTo("Программа 1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CreateDocumentDepositByCreditProgramAsync_CallsWordBuilder()
|
||||
{
|
||||
@@ -78,12 +103,12 @@ internal class ReportContractTestss
|
||||
_creditProgramStorage.Setup(x => x.GetList(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Returns(new List<CreditProgramDataModel>
|
||||
{
|
||||
new CreditProgramDataModel("1", "Программа 1", 100, 200, "sk", "p", new List<CreditProgramCurrencyDataModel>())
|
||||
new CreditProgramDataModel("1", "Программа 1", 100, 200, "sk", "p", new List<CreditProgramCurrencyDataModel> { new() { CurrencyId = "1" } })
|
||||
});
|
||||
_depositStorage.Setup(x => x.GetList(It.IsAny<string>()))
|
||||
.Returns(new List<DepositDataModel>
|
||||
{
|
||||
new DepositDataModel("d1", 5, 1000, 12, "cl", new List<DepositCurrencyDataModel>())
|
||||
new DepositDataModel("d1", 5, 1000, 12, "cl", new List<DepositCurrencyDataModel> { new() { CurrencyId = "1" } })
|
||||
});
|
||||
|
||||
_baseWordBuilder.Setup(x => x.AddHeader(It.IsAny<string>())).Returns(_baseWordBuilder.Object);
|
||||
@@ -91,7 +116,7 @@ internal class ReportContractTestss
|
||||
_baseWordBuilder.Setup(x => x.AddTable(It.IsAny<int[]>(), It.IsAny<List<string[]>>())).Returns(_baseWordBuilder.Object);
|
||||
_baseWordBuilder.Setup(x => x.Build()).Returns(new MemoryStream(Encoding.UTF8.GetBytes("test")));
|
||||
|
||||
var stream = await _reportContract.CreateDocumentDepositByCreditProgramAsync(ct);
|
||||
var stream = await _reportContract.CreateDocumentDepositByCreditProgramAsync(new List<string> { "1" }, ct);
|
||||
|
||||
Assert.That(stream, Is.Not.Null);
|
||||
_baseWordBuilder.Verify(x => x.AddHeader(It.IsAny<string>()), Times.Once);
|
||||
@@ -163,6 +188,35 @@ internal class ReportContractTestss
|
||||
|
||||
[Test]
|
||||
public async Task CreateExcelDocumentDepositByCreditProgramAsync_CallsExcelBuilder()
|
||||
{
|
||||
var ct = CancellationToken.None;
|
||||
_creditProgramStorage.Setup(x => x.GetList(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Returns(new List<CreditProgramDataModel>
|
||||
{
|
||||
new CreditProgramDataModel("1", "Программа 1", 100, 200, "sk", "p", new List<CreditProgramCurrencyDataModel> { new() { CurrencyId = "1" } })
|
||||
});
|
||||
_depositStorage.Setup(x => x.GetList(It.IsAny<string>()))
|
||||
.Returns(new List<DepositDataModel>
|
||||
{
|
||||
new DepositDataModel("d1", 5, 1000, 12, "cl", new List<DepositCurrencyDataModel> { new() { CurrencyId = "1" } })
|
||||
});
|
||||
|
||||
_baseExcelBuilder.Setup(x => x.AddHeader(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>())).Returns(_baseExcelBuilder.Object);
|
||||
_baseExcelBuilder.Setup(x => x.AddParagraph(It.IsAny<string>(), It.IsAny<int>())).Returns(_baseExcelBuilder.Object);
|
||||
_baseExcelBuilder.Setup(x => x.AddTable(It.IsAny<int[]>(), It.IsAny<List<string[]>>())).Returns(_baseExcelBuilder.Object);
|
||||
_baseExcelBuilder.Setup(x => x.Build()).Returns(new MemoryStream(Encoding.UTF8.GetBytes("test")));
|
||||
|
||||
var stream = await _reportContract.CreateExcelDocumentDepositByCreditProgramAsync(new List<string> { "1" }, ct);
|
||||
|
||||
Assert.That(stream, Is.Not.Null);
|
||||
_baseExcelBuilder.Verify(x => x.AddHeader(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()), Times.Once);
|
||||
_baseExcelBuilder.Verify(x => x.AddParagraph(It.IsAny<string>(), It.IsAny<int>()), Times.Once);
|
||||
_baseExcelBuilder.Verify(x => x.AddTable(It.IsAny<int[]>(), It.IsAny<List<string[]>>()), Times.Once);
|
||||
_baseExcelBuilder.Verify(x => x.Build(), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetDataDepositByCreditProgramAsync_NoCurrencies_ThrowsException()
|
||||
{
|
||||
var ct = CancellationToken.None;
|
||||
_creditProgramStorage.Setup(x => x.GetList(It.IsAny<string>(), It.IsAny<string>()))
|
||||
@@ -176,17 +230,7 @@ internal class ReportContractTestss
|
||||
new DepositDataModel("d1", 5, 1000, 12, "cl", new List<DepositCurrencyDataModel>())
|
||||
});
|
||||
|
||||
_baseExcelBuilder.Setup(x => x.AddHeader(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>())).Returns(_baseExcelBuilder.Object);
|
||||
_baseExcelBuilder.Setup(x => x.AddParagraph(It.IsAny<string>(), It.IsAny<int>())).Returns(_baseExcelBuilder.Object);
|
||||
_baseExcelBuilder.Setup(x => x.AddTable(It.IsAny<int[]>(), It.IsAny<List<string[]>>())).Returns(_baseExcelBuilder.Object);
|
||||
_baseExcelBuilder.Setup(x => x.Build()).Returns(new MemoryStream(Encoding.UTF8.GetBytes("test")));
|
||||
|
||||
var stream = await _reportContract.CreateExcelDocumentDepositByCreditProgramAsync(ct);
|
||||
|
||||
Assert.That(stream, Is.Not.Null);
|
||||
_baseExcelBuilder.Verify(x => x.AddHeader(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()), Times.Once);
|
||||
_baseExcelBuilder.Verify(x => x.AddParagraph(It.IsAny<string>(), It.IsAny<int>()), Times.Once);
|
||||
_baseExcelBuilder.Verify(x => x.AddTable(It.IsAny<int[]>(), It.IsAny<List<string[]>>()), Times.Once);
|
||||
_baseExcelBuilder.Verify(x => x.Build(), Times.Once);
|
||||
Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
_reportContract.GetDataDepositByCreditProgramAsync(null, ct));
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ internal class BaseStorageContractTest
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
BankDbContext = new BankDbContext(new ConfigurationDatabase());
|
||||
BankDbContext = new BankDbContext(new Infrastructure.ConfigurationDatabase());
|
||||
|
||||
BankDbContext.Database.EnsureDeleted();
|
||||
BankDbContext.Database.EnsureCreated();
|
||||
|
||||
@@ -71,6 +71,186 @@ internal class CreditProgramStorageContractTests : BaseStorageContractTest
|
||||
Assert.That(list, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetList_WithCurrencyRelations_Test()
|
||||
{
|
||||
// Создаем storekeeper и сохраняем его
|
||||
var uniqueId = Guid.NewGuid();
|
||||
var storekeeper = BankDbContext.InsertStorekeeperToDatabaseAndReturn(
|
||||
login: $"storekeeper_{uniqueId}",
|
||||
email: $"storekeeper_{uniqueId}@email.com",
|
||||
phone: $"+7-777-777-{uniqueId.ToString().Substring(0, 4)}"
|
||||
);
|
||||
BankDbContext.SaveChanges();
|
||||
|
||||
// Проверяем, что storekeeper действительно сохранен
|
||||
var savedStorekeeper = BankDbContext.Storekeepers.FirstOrDefault(s => s.Id == storekeeper.Id);
|
||||
Assert.That(savedStorekeeper, Is.Not.Null, "Storekeeper не был сохранен в базе данных");
|
||||
var storekeeperId = savedStorekeeper.Id;
|
||||
|
||||
// Создаем несколько валют
|
||||
var currency1Id = BankDbContext.InsertCurrencyToDatabaseAndReturn(storekeeperId: storekeeperId, abbreviation: "USD").Id;
|
||||
var currency2Id = BankDbContext.InsertCurrencyToDatabaseAndReturn(storekeeperId: storekeeperId, abbreviation: "EUR").Id;
|
||||
|
||||
// Создаем кредитную программу с двумя валютами
|
||||
var creditProgram = BankDbContext.InsertCreditProgramToDatabaseAndReturn(
|
||||
storekeeperId: storekeeperId,
|
||||
periodId: _periodId,
|
||||
creditProgramCurrency: [
|
||||
(currency1Id, Guid.NewGuid().ToString()),
|
||||
(currency2Id, Guid.NewGuid().ToString())
|
||||
]
|
||||
);
|
||||
|
||||
var list = _storageContract.GetList();
|
||||
Assert.That(list, Is.Not.Null);
|
||||
Assert.That(list, Has.Count.EqualTo(1));
|
||||
|
||||
var result = list.First();
|
||||
Assert.That(result.Currencies, Is.Not.Null);
|
||||
Assert.That(result.Currencies, Has.Count.EqualTo(2));
|
||||
Assert.That(result.Currencies.Select(c => c.CurrencyId), Does.Contain(currency1Id));
|
||||
Assert.That(result.Currencies.Select(c => c.CurrencyId), Does.Contain(currency2Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_AddElement_WithCurrencyRelations_Test()
|
||||
{
|
||||
// Создаем storekeeper и сохраняем его
|
||||
var uniqueId = Guid.NewGuid();
|
||||
var storekeeper = BankDbContext.InsertStorekeeperToDatabaseAndReturn(
|
||||
login: $"storekeeper_{uniqueId}",
|
||||
email: $"storekeeper_{uniqueId}@email.com",
|
||||
phone: $"+7-777-777-{uniqueId.ToString().Substring(0, 4)}"
|
||||
);
|
||||
BankDbContext.SaveChanges();
|
||||
|
||||
// Проверяем, что storekeeper действительно сохранен
|
||||
var savedStorekeeper = BankDbContext.Storekeepers.FirstOrDefault(s => s.Id == storekeeper.Id);
|
||||
Assert.That(savedStorekeeper, Is.Not.Null, "Storekeeper не был сохранен в базе данных");
|
||||
var storekeeperId = savedStorekeeper.Id;
|
||||
|
||||
// Создаем валюту
|
||||
var currencyId = BankDbContext.InsertCurrencyToDatabaseAndReturn(storekeeperId: storekeeperId).Id;
|
||||
|
||||
// Создаем модель с валютой
|
||||
var creditProgram = CreateModel(
|
||||
name: "unique name",
|
||||
periodId: _periodId,
|
||||
storekeeperId: storekeeperId,
|
||||
currency: [
|
||||
new CreditProgramCurrencyDataModel(Guid.NewGuid().ToString(), currencyId)
|
||||
]
|
||||
);
|
||||
|
||||
_storageContract.AddElement(creditProgram);
|
||||
|
||||
var result = BankDbContext.GetCreditProgramFromDatabase(creditProgram.Id);
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.CurrencyCreditPrograms, Is.Not.Null);
|
||||
Assert.That(result.CurrencyCreditPrograms, Has.Count.EqualTo(1));
|
||||
Assert.That(result.CurrencyCreditPrograms.First().CurrencyId, Is.EqualTo(currencyId));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_UpdElement_WithCurrencyRelations_Test()
|
||||
{
|
||||
// Создаем storekeeper и сохраняем его
|
||||
var uniqueId = Guid.NewGuid();
|
||||
var storekeeper = BankDbContext.InsertStorekeeperToDatabaseAndReturn(
|
||||
login: $"storekeeper_{uniqueId}",
|
||||
email: $"storekeeper_{uniqueId}@email.com",
|
||||
phone: $"+7-777-777-{uniqueId.ToString().Substring(0, 4)}"
|
||||
);
|
||||
BankDbContext.SaveChanges();
|
||||
|
||||
// Проверяем, что storekeeper действительно сохранен
|
||||
var savedStorekeeper = BankDbContext.Storekeepers.FirstOrDefault(s => s.Id == storekeeper.Id);
|
||||
Assert.That(savedStorekeeper, Is.Not.Null, "Storekeeper не был сохранен в базе данных");
|
||||
var storekeeperId = savedStorekeeper.Id;
|
||||
|
||||
// Создаем две валюты
|
||||
var currency1Id = BankDbContext.InsertCurrencyToDatabaseAndReturn(storekeeperId: storekeeperId).Id;
|
||||
var currency2Id = BankDbContext.InsertCurrencyToDatabaseAndReturn(storekeeperId: storekeeperId).Id;
|
||||
|
||||
// Создаем кредитную программу с одной валютой
|
||||
var creditProgram = BankDbContext.InsertCreditProgramToDatabaseAndReturn(
|
||||
storekeeperId: storekeeperId,
|
||||
periodId: _periodId,
|
||||
creditProgramCurrency: [(currency1Id, Guid.NewGuid().ToString())]
|
||||
);
|
||||
|
||||
// Обновляем программу, добавляя вторую валюту
|
||||
var updatedModel = CreateModel(
|
||||
id: creditProgram.Id,
|
||||
name: creditProgram.Name,
|
||||
periodId: _periodId,
|
||||
storekeeperId: storekeeperId,
|
||||
currency: [
|
||||
new CreditProgramCurrencyDataModel(creditProgram.Id, currency1Id),
|
||||
new CreditProgramCurrencyDataModel(creditProgram.Id, currency2Id)
|
||||
]
|
||||
);
|
||||
|
||||
_storageContract.UpdElement(updatedModel);
|
||||
|
||||
var result = BankDbContext.GetCreditProgramFromDatabase(creditProgram.Id);
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.CurrencyCreditPrograms, Is.Not.Null);
|
||||
Assert.That(result.CurrencyCreditPrograms, Has.Count.EqualTo(2));
|
||||
Assert.That(result.CurrencyCreditPrograms.Select(c => c.CurrencyId), Does.Contain(currency1Id));
|
||||
Assert.That(result.CurrencyCreditPrograms.Select(c => c.CurrencyId), Does.Contain(currency2Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_UpdElement_RemoveCurrencyRelations_Test()
|
||||
{
|
||||
// Создаем storekeeper и сохраняем его
|
||||
var uniqueId = Guid.NewGuid();
|
||||
var storekeeper = BankDbContext.InsertStorekeeperToDatabaseAndReturn(
|
||||
login: $"storekeeper_{uniqueId}",
|
||||
email: $"storekeeper_{uniqueId}@email.com",
|
||||
phone: $"+7-777-777-{uniqueId.ToString().Substring(0, 4)}"
|
||||
);
|
||||
BankDbContext.SaveChanges();
|
||||
|
||||
// Проверяем, что storekeeper действительно сохранен
|
||||
var savedStorekeeper = BankDbContext.Storekeepers.FirstOrDefault(s => s.Id == storekeeper.Id);
|
||||
Assert.That(savedStorekeeper, Is.Not.Null, "Storekeeper не был сохранен в базе данных");
|
||||
var storekeeperId = savedStorekeeper.Id;
|
||||
|
||||
// Создаем две валюты
|
||||
var currency1Id = BankDbContext.InsertCurrencyToDatabaseAndReturn(storekeeperId: storekeeperId).Id;
|
||||
var currency2Id = BankDbContext.InsertCurrencyToDatabaseAndReturn(storekeeperId: storekeeperId).Id;
|
||||
|
||||
// Создаем кредитную программу с двумя валютами
|
||||
var creditProgram = BankDbContext.InsertCreditProgramToDatabaseAndReturn(
|
||||
storekeeperId: storekeeperId,
|
||||
periodId: _periodId,
|
||||
creditProgramCurrency: [
|
||||
(currency1Id, Guid.NewGuid().ToString()),
|
||||
(currency2Id, Guid.NewGuid().ToString())
|
||||
]
|
||||
);
|
||||
|
||||
// Обновляем программу, оставляя только одну валюту
|
||||
var updatedModel = CreateModel(
|
||||
id: creditProgram.Id,
|
||||
name: creditProgram.Name,
|
||||
periodId: _periodId,
|
||||
storekeeperId: storekeeperId,
|
||||
currency: [new CreditProgramCurrencyDataModel(creditProgram.Id, currency1Id)]
|
||||
);
|
||||
|
||||
_storageContract.UpdElement(updatedModel);
|
||||
|
||||
var result = BankDbContext.GetCreditProgramFromDatabase(creditProgram.Id);
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.CurrencyCreditPrograms, Is.Not.Null);
|
||||
Assert.That(result.CurrencyCreditPrograms, Has.Count.EqualTo(1));
|
||||
Assert.That(result.CurrencyCreditPrograms.First().CurrencyId, Is.EqualTo(currency1Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetElementById_WhenHaveRecord_Test()
|
||||
{
|
||||
|
||||
@@ -18,7 +18,12 @@ internal class DepositStorageContractTests : BaseStorageContractTest
|
||||
public void SetUp()
|
||||
{
|
||||
_storageContract = new DepositStorageContract(BankDbContext);
|
||||
_clerkId = BankDbContext.InsertClerkToDatabaseAndReturn().Id;
|
||||
var uniqueId = Guid.NewGuid();
|
||||
_clerkId = BankDbContext.InsertClerkToDatabaseAndReturn(
|
||||
login: $"clerk_{uniqueId}",
|
||||
email: $"clerk_{uniqueId}@email.com",
|
||||
phone: $"+7-777-777-{uniqueId.ToString().Substring(0, 4)}"
|
||||
).Id;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
@@ -93,6 +98,131 @@ internal class DepositStorageContractTests : BaseStorageContractTest
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetList_ByClerkId_Test()
|
||||
{
|
||||
var uniqueId1 = Guid.NewGuid();
|
||||
var uniqueId2 = Guid.NewGuid();
|
||||
var clerkId1 = BankDbContext.InsertClerkToDatabaseAndReturn(
|
||||
email: $"clerk1_{uniqueId1}@email.com",
|
||||
login: $"clerk1_{uniqueId1}",
|
||||
phone: $"+7-777-777-{uniqueId1.ToString().Substring(0, 4)}"
|
||||
).Id;
|
||||
var clerkId2 = BankDbContext.InsertClerkToDatabaseAndReturn(
|
||||
email: $"clerk2_{uniqueId2}@email.com",
|
||||
login: $"clerk2_{uniqueId2}",
|
||||
phone: $"+7-777-777-{uniqueId2.ToString().Substring(0, 4)}"
|
||||
).Id;
|
||||
|
||||
BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: clerkId1);
|
||||
BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: clerkId1);
|
||||
BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: clerkId2);
|
||||
|
||||
var list = _storageContract.GetList(clerkId1);
|
||||
Assert.That(list, Is.Not.Null);
|
||||
Assert.That(list, Has.Count.EqualTo(2));
|
||||
Assert.That(list.All(x => x.ClerkId == clerkId1), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetElementByInterestRate_WhenHaveRecord_Test()
|
||||
{
|
||||
var deposit = BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: _clerkId, interestRate: 15.5f);
|
||||
var result = _storageContract.GetElementByInterestRate(15.5f);
|
||||
Assert.That(result, Is.Not.Null);
|
||||
AssertElement(result, deposit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetElementByInterestRate_WhenNoRecord_Test()
|
||||
{
|
||||
var result = _storageContract.GetElementByInterestRate(15.5f);
|
||||
Assert.That(result, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_AddElement_WhenHaveRecordWithSameInterestRate_Test()
|
||||
{
|
||||
// Создаем первый депозит с определенной процентной ставкой
|
||||
var deposit1 = CreateModel(clerkId: _clerkId, interestRate: 10.5f);
|
||||
_storageContract.AddElement(deposit1);
|
||||
|
||||
// Создаем второй депозит с такой же процентной ставкой
|
||||
var deposit2 = CreateModel(clerkId: _clerkId, interestRate: 10.5f);
|
||||
|
||||
// Проверяем, что можно добавить депозит с такой же процентной ставкой
|
||||
_storageContract.AddElement(deposit2);
|
||||
var result = BankDbContext.GetDepositFromDatabase(deposit2.Id);
|
||||
Assert.That(result, Is.Not.Null);
|
||||
AssertElement(result, deposit2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_UpdElement_WithCurrencies_Test()
|
||||
{
|
||||
// Создаем валюты
|
||||
var storekeeperId = BankDbContext.InsertStorekeeperToDatabaseAndReturn(
|
||||
login: $"storekeeper_{Guid.NewGuid()}",
|
||||
email: $"storekeeper_{Guid.NewGuid()}@email.com",
|
||||
phone: $"+7-777-777-{Guid.NewGuid().ToString().Substring(0, 4)}"
|
||||
).Id;
|
||||
|
||||
var currency1 = BankDbContext.InsertCurrencyToDatabaseAndReturn(
|
||||
abbreviation: "USD",
|
||||
storekeeperId: storekeeperId
|
||||
);
|
||||
var currency2 = BankDbContext.InsertCurrencyToDatabaseAndReturn(
|
||||
abbreviation: "EUR",
|
||||
storekeeperId: storekeeperId
|
||||
);
|
||||
|
||||
// Создаем депозит
|
||||
var deposit = BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: _clerkId);
|
||||
|
||||
// Обновляем депозит с валютами
|
||||
var updatedDeposit = CreateModel(
|
||||
id: deposit.Id,
|
||||
clerkId: _clerkId,
|
||||
deposits: new List<DepositCurrencyDataModel>
|
||||
{
|
||||
new(deposit.Id, currency1.Id),
|
||||
new(deposit.Id, currency2.Id)
|
||||
}
|
||||
);
|
||||
|
||||
_storageContract.UpdElement(updatedDeposit);
|
||||
var result = BankDbContext.GetDepositFromDatabase(deposit.Id);
|
||||
Assert.That(result.DepositCurrencies, Has.Count.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Try_GetListAsync_ByDateRange_Test()
|
||||
{
|
||||
var startDate = DateTime.Now.AddDays(-1);
|
||||
var endDate = DateTime.Now.AddDays(1);
|
||||
|
||||
var deposit = BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: _clerkId);
|
||||
|
||||
var list = await _storageContract.GetListAsync(startDate, endDate, CancellationToken.None);
|
||||
Assert.That(list, Is.Not.Null);
|
||||
Assert.That(list, Has.Count.EqualTo(1));
|
||||
AssertElement(list.First(), deposit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_AddElement_WhenDatabaseError_Test()
|
||||
{
|
||||
var deposit = CreateModel(clerkId: _clerkId);
|
||||
// Симулируем ошибку базы данных, пытаясь добавить депозит с несуществующим ID клерка
|
||||
var nonExistentClerkId = Guid.NewGuid().ToString();
|
||||
var depositWithInvalidClerk = CreateModel(clerkId: nonExistentClerkId);
|
||||
|
||||
Assert.That(
|
||||
() => _storageContract.AddElement(depositWithInvalidClerk),
|
||||
Throws.TypeOf<StorageException>()
|
||||
);
|
||||
}
|
||||
|
||||
private static DepositDataModel CreateModel(
|
||||
string? id = null,
|
||||
float interestRate = 10,
|
||||
|
||||
@@ -20,7 +20,12 @@ internal class ReplenishmentStorageContractTests : BaseStorageContractTest
|
||||
public void SetUp()
|
||||
{
|
||||
_storageContract = new ReplenishmentStorageContract(BankDbContext);
|
||||
_clerkId = BankDbContext.InsertClerkToDatabaseAndReturn().Id;
|
||||
var uniqueId = Guid.NewGuid();
|
||||
_clerkId = BankDbContext.InsertClerkToDatabaseAndReturn(
|
||||
login: $"clerk_{uniqueId}",
|
||||
email: $"clerk_{uniqueId}@email.com",
|
||||
phone: $"+7-777-777-{uniqueId.ToString().Substring(0, 4)}"
|
||||
).Id;
|
||||
_depositId = BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: _clerkId).Id;
|
||||
}
|
||||
|
||||
@@ -62,6 +67,120 @@ internal class ReplenishmentStorageContractTests : BaseStorageContractTest
|
||||
Assert.That(list, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetList_WithDateFilters_Test()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var pastDate = now.AddDays(-1);
|
||||
var futureDate = now.AddDays(1);
|
||||
|
||||
// Insert replenishments with different dates
|
||||
var pastReplenishment = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: _clerkId,
|
||||
depositId: _depositId,
|
||||
date: pastDate
|
||||
);
|
||||
var currentReplenishment = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: _clerkId,
|
||||
depositId: _depositId,
|
||||
date: now
|
||||
);
|
||||
var futureReplenishment = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: _clerkId,
|
||||
depositId: _depositId,
|
||||
date: futureDate
|
||||
);
|
||||
|
||||
// Test date range filter
|
||||
var filteredList = _storageContract.GetList(fromDate: pastDate, toDate: now);
|
||||
Assert.That(filteredList, Has.Count.EqualTo(2));
|
||||
Assert.That(filteredList.Select(x => x.Id), Does.Contain(pastReplenishment.Id));
|
||||
Assert.That(filteredList.Select(x => x.Id), Does.Contain(currentReplenishment.Id));
|
||||
Assert.That(filteredList.Select(x => x.Id), Does.Not.Contain(futureReplenishment.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetList_WithClerkIdFilter_Test()
|
||||
{
|
||||
var otherClerkId = BankDbContext.InsertClerkToDatabaseAndReturn(
|
||||
login: $"clerk_other",
|
||||
email: "clerk_other@email.com",
|
||||
phone: "+7-777-777-0000"
|
||||
).Id;
|
||||
|
||||
// Insert replenishments for different clerks
|
||||
var replenishment1 = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: _clerkId,
|
||||
depositId: _depositId
|
||||
);
|
||||
var replenishment2 = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: otherClerkId,
|
||||
depositId: _depositId
|
||||
);
|
||||
|
||||
var filteredList = _storageContract.GetList(clerkId: _clerkId);
|
||||
Assert.That(filteredList, Has.Count.EqualTo(1));
|
||||
Assert.That(filteredList.First().Id, Is.EqualTo(replenishment1.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetList_WithDepositIdFilter_Test()
|
||||
{
|
||||
var otherDepositId = BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: _clerkId).Id;
|
||||
|
||||
// Insert replenishments for different deposits
|
||||
var replenishment1 = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: _clerkId,
|
||||
depositId: _depositId
|
||||
);
|
||||
var replenishment2 = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: _clerkId,
|
||||
depositId: otherDepositId
|
||||
);
|
||||
|
||||
var filteredList = _storageContract.GetList(depositId: _depositId);
|
||||
Assert.That(filteredList, Has.Count.EqualTo(1));
|
||||
Assert.That(filteredList.First().Id, Is.EqualTo(replenishment1.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetList_WithCombinedFilters_Test()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var otherClerkId = BankDbContext.InsertClerkToDatabaseAndReturn(
|
||||
login: $"clerk_other",
|
||||
email: "clerk_other@email.com",
|
||||
phone: "+7-777-777-0000"
|
||||
).Id;
|
||||
var otherDepositId = BankDbContext.InsertDepositToDatabaseAndReturn(clerkId: _clerkId).Id;
|
||||
|
||||
// Insert replenishments with different combinations
|
||||
var replenishment1 = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: _clerkId,
|
||||
depositId: _depositId,
|
||||
date: now
|
||||
);
|
||||
var replenishment2 = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: otherClerkId,
|
||||
depositId: _depositId,
|
||||
date: now
|
||||
);
|
||||
var replenishment3 = BankDbContext.InsertReplenishmentToDatabaseAndReturn(
|
||||
clerkId: _clerkId,
|
||||
depositId: otherDepositId,
|
||||
date: now
|
||||
);
|
||||
|
||||
var filteredList = _storageContract.GetList(
|
||||
fromDate: now,
|
||||
toDate: now,
|
||||
clerkId: _clerkId,
|
||||
depositId: _depositId
|
||||
);
|
||||
Assert.That(filteredList, Has.Count.EqualTo(1));
|
||||
Assert.That(filteredList.First().Id, Is.EqualTo(replenishment1.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Try_GetElementById_WhenHaveRecord_Test()
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@ internal class ClerkControllerTests : BaseWebApiControllerTest
|
||||
// Arrange
|
||||
var model = CreateModel();
|
||||
// Act
|
||||
var response = await HttpClient.PostAsJsonAsync("/api/clerks", model);
|
||||
var response = await HttpClient.PostAsJsonAsync("/api/clerks/register", model);
|
||||
// Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.NoContent));
|
||||
AssertElement(BankDbContext.GetClerkFromDatabase(model.Id!), model);
|
||||
@@ -85,7 +85,7 @@ internal class ClerkControllerTests : BaseWebApiControllerTest
|
||||
var model = CreateModel();
|
||||
BankDbContext.InsertClerkToDatabaseAndReturn(id: model.Id);
|
||||
// Act
|
||||
var response = await HttpClient.PostAsJsonAsync("/api/clerks", model);
|
||||
var response = await HttpClient.PostAsJsonAsync("/api/clerks/register", model);
|
||||
// Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
|
||||
}
|
||||
@@ -94,7 +94,7 @@ internal class ClerkControllerTests : BaseWebApiControllerTest
|
||||
public async Task Post_WhenSendEmptyData_ShouldBadRequest_Test()
|
||||
{
|
||||
// Act
|
||||
var response = await HttpClient.PostAsync("/api/clerks", MakeContent(string.Empty));
|
||||
var response = await HttpClient.PostAsync("/api/clerks/register", MakeContent(string.Empty));
|
||||
// Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ internal class ClientControllerTests : BaseWebApiControllerTest
|
||||
var client1 = BankDbContext.InsertClientToDatabaseAndReturn(name: "Иван", surname: "Иванов", clerkId: _clerk.Id);
|
||||
var client2 = BankDbContext.InsertClientToDatabaseAndReturn(name: "Петр", surname: "Петров", clerkId: _clerk.Id);
|
||||
// Act
|
||||
var response = await HttpClient.GetAsync("/api/clients/getrecords");
|
||||
var response = await HttpClient.GetAsync("/api/clients/getallrecords");
|
||||
// Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||
var data = await GetModelFromResponseAsync<List<ClientViewModel>>(response);
|
||||
@@ -48,7 +48,7 @@ internal class ClientControllerTests : BaseWebApiControllerTest
|
||||
public async Task GetList_WhenNoRecords_ShouldSuccess_Test()
|
||||
{
|
||||
// Act
|
||||
var response = await HttpClient.GetAsync("/api/clients/getrecords");
|
||||
var response = await HttpClient.GetAsync("/api/clients/getallrecords");
|
||||
// Assert
|
||||
Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||
var data = await GetModelFromResponseAsync<List<ClientViewModel>>(response);
|
||||
@@ -81,7 +81,7 @@ internal class ClientControllerTests : BaseWebApiControllerTest
|
||||
public async Task Post_ShouldSuccess_Test()
|
||||
{
|
||||
// Arrange
|
||||
var model = CreateModel();
|
||||
var model = CreateModel(clerkId: _clerk.Id);
|
||||
// Act
|
||||
var response = await HttpClient.PostAsJsonAsync("/api/clients/register", model);
|
||||
// Assert
|
||||
@@ -114,7 +114,7 @@ internal class ClientControllerTests : BaseWebApiControllerTest
|
||||
public async Task Put_ShouldSuccess_Test()
|
||||
{
|
||||
// Arrange
|
||||
var model = CreateModel();
|
||||
var model = CreateModel(name: "slava", surname: "fomichev", balance: 1_000_000, clerkId: _clerk.Id);
|
||||
BankDbContext.InsertClientToDatabaseAndReturn(id: model.Id, clerkId: _clerk.Id);
|
||||
// Act
|
||||
var response = await HttpClient.PutAsJsonAsync("/api/clients/changeinfo", model);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AutoMapper;
|
||||
using BankBusinessLogic.Implementations;
|
||||
using BankContracts.AdapterContracts;
|
||||
using BankContracts.AdapterContracts.OperationResponses;
|
||||
using BankContracts.BindingModels;
|
||||
@@ -6,6 +7,7 @@ using BankContracts.BusinessLogicContracts;
|
||||
using BankContracts.DataModels;
|
||||
using BankContracts.Exceptions;
|
||||
using BankContracts.ViewModels;
|
||||
using BankWebApi.Infrastructure;
|
||||
|
||||
namespace BankWebApi.Adapters;
|
||||
|
||||
@@ -13,11 +15,13 @@ public class ClerkAdapter : IClerkAdapter
|
||||
{
|
||||
private readonly IClerkBusinessLogicContract _clerkBusinessLogicContract;
|
||||
|
||||
private readonly IJwtProvider _jwtProvider;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly Mapper _mapper;
|
||||
|
||||
public ClerkAdapter(IClerkBusinessLogicContract clerkBusinessLogicContract, ILogger logger)
|
||||
public ClerkAdapter(IClerkBusinessLogicContract clerkBusinessLogicContract, ILogger logger, IJwtProvider jwtProvider)
|
||||
{
|
||||
_clerkBusinessLogicContract = clerkBusinessLogicContract;
|
||||
_logger = logger;
|
||||
@@ -27,6 +31,7 @@ public class ClerkAdapter : IClerkAdapter
|
||||
cfg.CreateMap<ClerkDataModel, ClerkViewModel>();
|
||||
});
|
||||
_mapper = new Mapper(config);
|
||||
_jwtProvider = jwtProvider;
|
||||
}
|
||||
|
||||
public ClerkOperationResponse GetList()
|
||||
@@ -170,4 +175,30 @@ public class ClerkAdapter : IClerkAdapter
|
||||
return ClerkOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public ClerkOperationResponse Login(LoginBindingModel clerkModel, out string token)
|
||||
{
|
||||
token = string.Empty;
|
||||
try
|
||||
{
|
||||
var clerk = _clerkBusinessLogicContract.GetClerkByData(clerkModel.Login);
|
||||
|
||||
|
||||
var result = clerkModel.Password == clerk.Password;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
return ClerkOperationResponse.Unauthorized("Password are incorrect");
|
||||
}
|
||||
|
||||
token = _jwtProvider.GenerateToken(clerk);
|
||||
|
||||
return ClerkOperationResponse.OK(_mapper.Map<ClerkViewModel>(clerk));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception in Login");
|
||||
return ClerkOperationResponse.InternalServerError($"Exception in Login {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,25 @@ public class ClientAdapter : IClientAdapter
|
||||
_logger = logger;
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
{
|
||||
// Mapping for Client
|
||||
cfg.CreateMap<ClientBindingModel, ClientDataModel>();
|
||||
cfg.CreateMap<DepositDataModel, DepositViewModel>();
|
||||
cfg.CreateMap<ClientDataModel, ClientViewModel>()
|
||||
.ForMember(dest => dest.DepositClients, opt => opt.MapFrom(src => src.DepositClients))
|
||||
.ForMember(dest => dest.CreditProgramClients, opt => opt.MapFrom(src => src.CreditProgramClients));
|
||||
|
||||
// Mapping for Deposit
|
||||
cfg.CreateMap<DepositDataModel, DepositViewModel>()
|
||||
.ForMember(dest => dest.DepositCurrencies, opt => opt.MapFrom(src => src.Currencies)); // Adjust if Currencies is meant to map to DepositClients
|
||||
|
||||
// Mapping for ClientCreditProgram
|
||||
cfg.CreateMap<ClientCreditProgramBindingModel, ClientCreditProgramDataModel>();
|
||||
cfg.CreateMap<ClientCreditProgramDataModel, ClientCreditProgramViewModel>();
|
||||
|
||||
// Mapping for DepositClient
|
||||
cfg.CreateMap<DepositClientBindingModel, DepositClientDataModel>();
|
||||
cfg.CreateMap<DepositClientDataModel, DepositClientViewModel>();
|
||||
});
|
||||
|
||||
_mapper = new Mapper(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public class CreditProgramAdapter : ICreditProgramAdapter
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return CreditProgramOperationResponse.InternalServerError(
|
||||
$"Error while working with data storage:{ex.InnerException!.Message}"
|
||||
$"Error while working with data storage:{ex.InnerException?.Message}"
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -86,7 +86,7 @@ public class CreditProgramAdapter : ICreditProgramAdapter
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return CreditProgramOperationResponse.InternalServerError(
|
||||
$"Error while working with data storage: {ex.InnerException!.Message}"
|
||||
$"Error while working with data storage: {ex.InnerException?.Message}"
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -122,7 +122,7 @@ public class CreditProgramAdapter : ICreditProgramAdapter
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return CreditProgramOperationResponse.BadRequest(
|
||||
$"Error while working with data storage: {ex.InnerException!.Message}"
|
||||
$"Error while working with data storage: {ex.InnerException?.Message}"
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -164,7 +164,7 @@ public class CreditProgramAdapter : ICreditProgramAdapter
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return CreditProgramOperationResponse.BadRequest(
|
||||
$"Error while working with data storage: {ex.InnerException!.Message}"
|
||||
$"Error while working with data storage: {ex.InnerException?.Message}"
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -195,7 +195,7 @@ public class CreditProgramAdapter : ICreditProgramAdapter
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return CreditProgramOperationResponse.InternalServerError(
|
||||
$"Error while working with data storage:{ex.InnerException!.Message}"
|
||||
$"Error while working with data storage:{ex.InnerException?.Message}"
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -226,7 +226,7 @@ public class CreditProgramAdapter : ICreditProgramAdapter
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return CreditProgramOperationResponse.InternalServerError(
|
||||
$"Error while working with data storage:{ex.InnerException!.Message}"
|
||||
$"Error while working with data storage:{ex.InnerException?.Message}"
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -23,10 +23,34 @@ public class DepositAdapter : IDepositAdapter
|
||||
_logger = logger;
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
{
|
||||
cfg.CreateMap<DepositBindingModel, DepositDataModel>();
|
||||
cfg.CreateMap<DepositDataModel, DepositViewModel>();
|
||||
cfg.CreateMap<DepositCurrencyBindingModel, DepositCurrencyDataModel>();
|
||||
// DepositBindingModel -> DepositDataModel
|
||||
cfg.CreateMap<DepositBindingModel, DepositDataModel>()
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id ?? string.Empty))
|
||||
.ForMember(dest => dest.InterestRate, opt => opt.MapFrom(src => src.InterestRate))
|
||||
.ForMember(dest => dest.Cost, opt => opt.MapFrom(src => src.Cost))
|
||||
.ForMember(dest => dest.Period, opt => opt.MapFrom(src => src.Period))
|
||||
.ForMember(dest => dest.ClerkId, opt => opt.MapFrom(src => src.ClerkId ?? string.Empty))
|
||||
.ForMember(dest => dest.Currencies, opt => opt.MapFrom(src => src.DepositCurrencies ?? new List<DepositCurrencyBindingModel>()));
|
||||
|
||||
// DepositDataModel -> DepositViewModel
|
||||
cfg.CreateMap<DepositDataModel, DepositViewModel>()
|
||||
.ForMember(dest => dest.DepositCurrencies, opt => opt.MapFrom(src => src.Currencies != null ? src.Currencies : new List<DepositCurrencyDataModel>()));
|
||||
|
||||
// DepositCurrencyBindingModel -> DepositCurrencyDataModel
|
||||
cfg.CreateMap<DepositCurrencyBindingModel, DepositCurrencyDataModel>()
|
||||
.ForMember(dest => dest.DepositId, opt => opt.MapFrom(src => src.DepositId ?? string.Empty))
|
||||
.ForMember(dest => dest.CurrencyId, opt => opt.MapFrom(src => src.CurrencyId ?? string.Empty));
|
||||
|
||||
// DepositCurrencyDataModel -> DepositCurrencyViewModel
|
||||
cfg.CreateMap<DepositCurrencyDataModel, DepositCurrencyViewModel>();
|
||||
|
||||
// DepositCurrencyViewModel -> DepositCurrencyBindingModel
|
||||
cfg.CreateMap<DepositCurrencyViewModel, DepositCurrencyBindingModel>();
|
||||
|
||||
// Явный маппинг DepositCurrencyDataModel -> DepositCurrencyBindingModel
|
||||
cfg.CreateMap<DepositCurrencyDataModel, DepositCurrencyBindingModel>()
|
||||
.ForMember(dest => dest.DepositId, opt => opt.MapFrom(src => src.DepositId))
|
||||
.ForMember(dest => dest.CurrencyId, opt => opt.MapFrom(src => src.CurrencyId));
|
||||
});
|
||||
_mapper = new Mapper(config);
|
||||
}
|
||||
@@ -117,7 +141,7 @@ public class DepositAdapter : IDepositAdapter
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return DepositOperationResponse.BadRequest(
|
||||
$"Error while working with data storage: {ex.InnerException!.Message}"
|
||||
$"Error while working with data storage: {ex.InnerException?.Message}"
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -21,9 +21,17 @@ public class PeriodAdapter : IPeriodAdapter
|
||||
{
|
||||
_periodBusinessLogicContract = periodBusinessLogicContract;
|
||||
_logger = logger;
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
var config = new MapperConfiguration(cfg =>
|
||||
{
|
||||
cfg.CreateMap<PeriodBindingModel, PeriodDataModel>();
|
||||
cfg.CreateMap<PeriodBindingModel, PeriodDataModel>()
|
||||
.ConstructUsing(src => new PeriodDataModel(
|
||||
src.Id,
|
||||
src.StartTime,
|
||||
src.EndTime,
|
||||
src.StorekeeperId
|
||||
));
|
||||
|
||||
// Маппинг PeriodDataModel -> PeriodViewModel
|
||||
cfg.CreateMap<PeriodDataModel, PeriodViewModel>();
|
||||
});
|
||||
_mapper = new Mapper(config);
|
||||
|
||||
@@ -36,16 +36,12 @@ public class ReportAdapter : IReportAdapter
|
||||
return ReportOperationResponse.OK(stream, fileName);
|
||||
}
|
||||
|
||||
public async Task<ReportOperationResponse> CreateDocumentClientsByCreditProgramAsync(CancellationToken ct)
|
||||
public async Task<ReportOperationResponse> CreateDocumentClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return SendStream(await _reportContract.CreateDocumentClientsByCreditProgramAsync(ct), "clientbycreditprogram.docx");
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
_logger.LogError(ex, "IncorrectDatesException");
|
||||
return ReportOperationResponse.BadRequest($"Incorrect dates: {ex.Message}");
|
||||
return SendStream(await _reportContract.CreateDocumentClientsByCreditProgramAsync(creditProgramIds, ct),
|
||||
"clientsbycreditprogram.docx");
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
@@ -60,21 +56,16 @@ public class ReportAdapter : IReportAdapter
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception");
|
||||
return
|
||||
ReportOperationResponse.InternalServerError(ex.Message);
|
||||
return ReportOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ReportOperationResponse> CreateExcelDocumentClientsByCreditProgramAsync(CancellationToken ct)
|
||||
public async Task<ReportOperationResponse> CreateExcelDocumentClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return SendStream(await _reportContract.CreateExcelDocumentClientsByCreditProgramAsync(ct), "clientbycreditprogram.xlsx");
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
_logger.LogError(ex, "IncorrectDatesException");
|
||||
return ReportOperationResponse.BadRequest($"Incorrect dates: {ex.Message}");
|
||||
return SendStream(await _reportContract.CreateExcelDocumentClientsByCreditProgramAsync(creditProgramIds, ct),
|
||||
"clientsbycreditprogram.xlsx");
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
@@ -89,8 +80,7 @@ public class ReportAdapter : IReportAdapter
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception");
|
||||
return
|
||||
ReportOperationResponse.InternalServerError(ex.Message);
|
||||
return ReportOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,8 +88,7 @@ public class ReportAdapter : IReportAdapter
|
||||
{
|
||||
try
|
||||
{
|
||||
return SendStream(await _reportContract.CreateDocumentClientsByDepositAsync(dateStart, dateFinish, ct),
|
||||
"clientbydeposit.pdf");
|
||||
return SendStream(await _reportContract.CreateDocumentClientsByDepositAsync(dateStart, dateFinish, ct), "clientbydeposit.pdf");
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
@@ -154,11 +143,11 @@ public class ReportAdapter : IReportAdapter
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ReportOperationResponse> CreateDocumentDepositByCreditProgramAsync(CancellationToken ct)
|
||||
public async Task<ReportOperationResponse> CreateDocumentDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return SendStream(await _reportContract.CreateDocumentDepositByCreditProgramAsync(ct), "depositbycreditprogram.docx");
|
||||
return SendStream(await _reportContract.CreateDocumentDepositByCreditProgramAsync(creditProgramIds, ct), "depositbycreditprogram.docx");
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
@@ -187,11 +176,11 @@ public class ReportAdapter : IReportAdapter
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ReportOperationResponse> CreateExcelDocumentDepositByCreditProgramAsync(CancellationToken ct)
|
||||
public async Task<ReportOperationResponse> CreateExcelDocumentDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return SendStream(await _reportContract.CreateExcelDocumentDepositByCreditProgramAsync(ct), "depositbycreditprogram.xlsx");
|
||||
return SendStream(await _reportContract.CreateExcelDocumentDepositByCreditProgramAsync(creditProgramIds, ct), "depositbycreditprogram.xlsx");
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
@@ -216,21 +205,16 @@ public class ReportAdapter : IReportAdapter
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception");
|
||||
return
|
||||
ReportOperationResponse.InternalServerError(ex.Message);
|
||||
return ReportOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ReportOperationResponse> GetDataClientsByCreditProgramAsync(CancellationToken ct)
|
||||
public async Task<ReportOperationResponse> GetDataClientsByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReportOperationResponse.OK([.. (await _reportContract.GetDataClientsByCreditProgramAsync(ct)).Select(x => _mapper.Map<ClientsByCreditProgramViewModel>(x))]);
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
_logger.LogError(ex, "IncorrectDatesException");
|
||||
return ReportOperationResponse.BadRequest($"Incorrect dates: {ex.Message}");
|
||||
return ReportOperationResponse.OK((await _reportContract.GetDataClientsByCreditProgramAsync(creditProgramIds, ct))
|
||||
.Select(x => _mapper.Map<ClientsByCreditProgramViewModel>(x)).ToList());
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
@@ -245,8 +229,7 @@ public class ReportAdapter : IReportAdapter
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception");
|
||||
return
|
||||
ReportOperationResponse.InternalServerError(ex.Message);
|
||||
return ReportOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,11 +293,11 @@ public class ReportAdapter : IReportAdapter
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ReportOperationResponse> GetDataDepositByCreditProgramAsync(CancellationToken ct)
|
||||
public async Task<ReportOperationResponse> GetDataDepositByCreditProgramAsync(List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReportOperationResponse.OK([.. (await _reportContract.GetDataDepositByCreditProgramAsync(ct)).Select(x => _mapper.Map<DepositByCreditProgramViewModel>(x))]);
|
||||
return ReportOperationResponse.OK([.. (await _reportContract.GetDataDepositByCreditProgramAsync(creditProgramIds, ct)).Select(x => _mapper.Map<DepositByCreditProgramViewModel>(x))]);
|
||||
}
|
||||
catch (IncorrectDatesException ex)
|
||||
{
|
||||
@@ -334,8 +317,7 @@ public class ReportAdapter : IReportAdapter
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception");
|
||||
return
|
||||
ReportOperationResponse.InternalServerError(ex.Message);
|
||||
return ReportOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ using BankContracts.BusinessLogicContracts;
|
||||
using BankContracts.DataModels;
|
||||
using BankContracts.Exceptions;
|
||||
using BankContracts.ViewModels;
|
||||
using BankWebApi.Infrastructure;
|
||||
using System.Buffers;
|
||||
|
||||
namespace BankWebApi.Adapters;
|
||||
|
||||
@@ -14,11 +16,13 @@ public class StorekeeperAdapter : IStorekeeperAdapter
|
||||
{
|
||||
private readonly IStorekeeperBusinessLogicContract _storekeeperBusinessLogicContract;
|
||||
|
||||
private readonly IJwtProvider _jwtProvider;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly Mapper _mapper;
|
||||
|
||||
public StorekeeperAdapter(IStorekeeperBusinessLogicContract storekeeperBusinessLogicContract, ILogger logger)
|
||||
public StorekeeperAdapter(IStorekeeperBusinessLogicContract storekeeperBusinessLogicContract, IJwtProvider jwtProvider, ILogger logger)
|
||||
{
|
||||
_storekeeperBusinessLogicContract = storekeeperBusinessLogicContract;
|
||||
_logger = logger;
|
||||
@@ -28,6 +32,7 @@ public class StorekeeperAdapter : IStorekeeperAdapter
|
||||
cfg.CreateMap<StorekeeperDataModel, StorekeeperViewModel>();
|
||||
});
|
||||
_mapper = new Mapper(config);
|
||||
_jwtProvider = jwtProvider;
|
||||
}
|
||||
|
||||
public StorekeeperOperationResponse GetList()
|
||||
@@ -119,7 +124,7 @@ public class StorekeeperAdapter : IStorekeeperAdapter
|
||||
{
|
||||
_logger.LogError(ex, "StorageException");
|
||||
return StorekeeperOperationResponse.BadRequest(
|
||||
$"Error while working with data storage: {ex.InnerException!.Message}"
|
||||
$"Error while working with data storage: {ex.InnerException?.Message}"
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -170,5 +175,31 @@ public class StorekeeperAdapter : IStorekeeperAdapter
|
||||
_logger.LogError(ex, "Exception");
|
||||
return StorekeeperOperationResponse.InternalServerError(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StorekeeperOperationResponse Login(LoginBindingModel storekeeperAuth, out string token)
|
||||
{
|
||||
token = string.Empty;
|
||||
try
|
||||
{
|
||||
var storekeeper = _storekeeperBusinessLogicContract.GetStorekeeperByData(storekeeperAuth.Login);
|
||||
|
||||
|
||||
var result = storekeeperAuth.Password == storekeeper.Password;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
return StorekeeperOperationResponse.Unauthorized("Password are incorrect");
|
||||
}
|
||||
|
||||
token = _jwtProvider.GenerateToken(storekeeper);
|
||||
|
||||
return StorekeeperOperationResponse.OK(_mapper.Map<StorekeeperViewModel>(storekeeper));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception in Login");
|
||||
return StorekeeperOperationResponse.InternalServerError($"Exception in Login {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace BankWebApi;
|
||||
/// </summary>
|
||||
public class AuthOptions
|
||||
{
|
||||
public const string CookieName = "bank";
|
||||
public const string ISSUER = "Bank_AuthServer"; // издатель токена
|
||||
public const string AUDIENCE = "Bank_AuthClient"; // потребитель токена
|
||||
const string KEY = "banksuperpupersecret_secretsecretsecretkey!"; // ключ для шифрации
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using BankContracts.BindingModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace BankWebApi.Controllers;
|
||||
|
||||
@@ -39,7 +40,8 @@ public class ClerksController(IClerkAdapter adapter) : ControllerBase
|
||||
/// </summary>
|
||||
/// <param name="model">модель от пользователя</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[HttpPost("register")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Register([FromBody] ClerkBindingModel model)
|
||||
{
|
||||
return _adapter.RegisterClerk(model).GetResponse(Request, Response);
|
||||
@@ -55,4 +57,58 @@ public class ClerksController(IClerkAdapter adapter) : ControllerBase
|
||||
{
|
||||
return _adapter.ChangeClerkInfo(model).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// вход для клерка
|
||||
/// </summary>
|
||||
/// <param name="model">модель с логином и паролем</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("login")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Login([FromBody] LoginBindingModel model)
|
||||
{
|
||||
var res = _adapter.Login(model, out string token);
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
return res.GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
Response.Cookies.Append(AuthOptions.CookieName, token, new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
SameSite = SameSiteMode.None,
|
||||
Secure = true,
|
||||
Expires = DateTime.UtcNow.AddDays(2)
|
||||
});
|
||||
|
||||
return res.GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных текущего клерка
|
||||
/// </summary>
|
||||
/// <returns>Данные кладовщика</returns>
|
||||
[HttpGet("me")]
|
||||
public IActionResult GetCurrentUser()
|
||||
{
|
||||
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var response = _adapter.GetElement(userId);
|
||||
return response.GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выход клерка
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("logout")]
|
||||
public IActionResult Logout()
|
||||
{
|
||||
Response.Cookies.Delete(AuthOptions.CookieName);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using BankContracts.AdapterContracts;
|
||||
using BankContracts.BindingModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace BankWebApi.Controllers;
|
||||
@@ -10,7 +9,7 @@ namespace BankWebApi.Controllers;
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
[Produces("application/json")]
|
||||
public class PeriodController(IPeriodAdapter adapter) : ControllerBase
|
||||
public class PeriodsController(IPeriodAdapter adapter) : ControllerBase
|
||||
{
|
||||
private readonly IPeriodAdapter _adapter = adapter;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using BankBusinessLogic.Implementations;
|
||||
using BankContracts.AdapterContracts;
|
||||
using BankContracts.BindingModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@@ -8,42 +9,56 @@ namespace BankWebApi.Controllers;
|
||||
[Authorize]
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class ReportController : ControllerBase
|
||||
public class ReportController(IReportAdapter adapter) : ControllerBase
|
||||
{
|
||||
private readonly IReportAdapter _adapter;
|
||||
private readonly EmailService _emailService;
|
||||
|
||||
public ReportController(IReportAdapter adapter)
|
||||
{
|
||||
_adapter = adapter;
|
||||
_emailService = EmailService.CreateYandexService();
|
||||
}
|
||||
private readonly IReportAdapter _adapter = adapter;
|
||||
private readonly EmailService _emailService = EmailService.CreateYandexService();
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных Клиента по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/json")]
|
||||
public async Task<IActionResult> GetClientByCreditProgram(CancellationToken ct)
|
||||
public async Task<IActionResult> GetClientByCreditProgram([FromQuery] List<string>? creditProgramIds, CancellationToken ct)
|
||||
{
|
||||
return (await
|
||||
_adapter.GetDataClientsByCreditProgramAsync(ct)).GetResponse(Request, Response);
|
||||
return (await _adapter.GetDataClientsByCreditProgramAsync(creditProgramIds, ct)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Отчет word Клиента по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/octet-stream")]
|
||||
public async Task<IActionResult> LoadClientsByCreditProgram(CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> LoadClientsByCreditProgram([FromQuery] List<string>? creditProgramIds, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await
|
||||
_adapter.CreateDocumentClientsByCreditProgramAsync(cancellationToken)).GetResponse(Request, Response);
|
||||
return (await _adapter.CreateDocumentClientsByCreditProgramAsync(creditProgramIds, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отчет excel Клиента по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/octet-stream")]
|
||||
public async Task<IActionResult> LoadExcelClientByCreditProgram(CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> LoadExcelClientByCreditProgram([FromQuery] List<string>? creditProgramIds, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await
|
||||
_adapter.CreateExcelDocumentClientsByCreditProgramAsync(cancellationToken)).GetResponse(Request, Response);
|
||||
return (await _adapter.CreateExcelDocumentClientsByCreditProgramAsync(creditProgramIds, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных Клиента по Вкладам
|
||||
/// </summary>
|
||||
/// <param name="fromDate"></param>
|
||||
/// <param name="toDate"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/json")]
|
||||
public async Task<IActionResult> GetClientByDeposit(DateTime fromDate, DateTime toDate, CancellationToken cancellationToken)
|
||||
@@ -51,43 +66,82 @@ public class ReportController : ControllerBase
|
||||
return (await _adapter.GetDataClientsByDepositAsync(fromDate, toDate, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отчет word Клиента по Вкладам
|
||||
/// </summary>
|
||||
/// <param name="fromDate"></param>
|
||||
/// <param name="toDate"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/octet-stream")]
|
||||
public async Task<IActionResult> LoadClientsByDeposit(DateTime fromDate, DateTime toDate, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await _adapter.CreateDocumentClientsByDepositAsync(fromDate,
|
||||
toDate, cancellationToken)).GetResponse(Request, Response);
|
||||
return (await _adapter.CreateDocumentClientsByDepositAsync(fromDate, toDate, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных Вклада по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/json")]
|
||||
public async Task<IActionResult> GetDepositByCreditProgram(CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> GetDepositByCreditProgram([FromQuery] List<string>? creditProgramIds, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await _adapter.GetDataDepositByCreditProgramAsync(cancellationToken)).GetResponse(Request, Response);
|
||||
return (await _adapter.GetDataDepositByCreditProgramAsync(creditProgramIds, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отчет word Вклада по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/octet-stream")]
|
||||
public async Task<IActionResult> LoadDepositByCreditProgram(CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> LoadDepositByCreditProgram([FromQuery] List<string>? creditProgramIds, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await _adapter.CreateDocumentDepositByCreditProgramAsync(cancellationToken)).GetResponse(Request, Response);
|
||||
return (await _adapter.CreateDocumentDepositByCreditProgramAsync(creditProgramIds, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отчет excel Вклада по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="creditProgramIds"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/octet-stream")]
|
||||
public async Task<IActionResult> LoadExcelDepositByCreditProgram(CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> LoadExcelDepositByCreditProgram([FromQuery] List<string>? creditProgramIds, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await _adapter.CreateExcelDocumentDepositByCreditProgramAsync(cancellationToken)).GetResponse(Request, Response);
|
||||
return (await _adapter.CreateExcelDocumentDepositByCreditProgramAsync(creditProgramIds, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных Вклада и Кредитных программам по Валютам
|
||||
/// кладовщик pdf
|
||||
/// </summary>
|
||||
/// <param name="fromDate"></param>
|
||||
/// <param name="toDate"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/json")]
|
||||
public async Task<IActionResult> GetDepositAndCreditProgramByCurrency(DateTime fromDate, DateTime toDate, CancellationToken cancellationToken)
|
||||
{
|
||||
return (await _adapter.GetDataDepositAndCreditProgramByCurrencyAsync(fromDate, toDate,
|
||||
cancellationToken)).GetResponse(Request, Response);
|
||||
return (await _adapter.GetDataDepositAndCreditProgramByCurrencyAsync(fromDate, toDate, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отчет pdf Вклада и Кредитных программам по Валютам
|
||||
/// кладовщик pdf
|
||||
/// </summary>
|
||||
/// <param name="fromDate"></param>
|
||||
/// <param name="toDate"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Consumes("application/octet-stream")]
|
||||
public async Task<IActionResult> LoadDepositAndCreditProgramByCurrency(DateTime fromDate, DateTime toDate, CancellationToken cancellationToken)
|
||||
@@ -95,30 +149,39 @@ public class ReportController : ControllerBase
|
||||
return (await _adapter.CreateDocumentDepositAndCreditProgramByCurrencyAsync(fromDate, toDate, cancellationToken)).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка word отчета Клиентов по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="mailInfo"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> SendReportByCreditProgram(string email, CancellationToken ct)
|
||||
public async Task<IActionResult> SendReportByCreditProgram([FromBody] CreditProgramReportMailSendInfoBindingModel mailInfo, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var report = await _adapter.CreateDocumentClientsByCreditProgramAsync(ct);
|
||||
var report = await _adapter.CreateDocumentClientsByCreditProgramAsync(mailInfo.CreditProgramIds, ct);
|
||||
var response = report.GetResponse(Request, Response);
|
||||
|
||||
|
||||
if (response is FileStreamResult fileResult)
|
||||
{
|
||||
var tempPath = Path.GetTempFileName();
|
||||
using (var fileStream = new FileStream(tempPath, FileMode.Create))
|
||||
var tempPathWithExtension = Path.ChangeExtension(tempPath, ".docx");
|
||||
|
||||
using (var fileStream = new FileStream(tempPathWithExtension, FileMode.Create))
|
||||
{
|
||||
await fileResult.FileStream.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
await _emailService.SendReportAsync(
|
||||
toEmail: email,
|
||||
subject: "Отчет по клиентам по кредитным программам",
|
||||
body: "<h1>Отчет по клиентам по кредитным программам</h1><p>В приложении находится отчет по клиентам по кредитным программам.</p>",
|
||||
attachmentPath: tempPath
|
||||
toEmail: mailInfo.Email,
|
||||
subject: mailInfo.Subject,
|
||||
body: mailInfo.Body,
|
||||
attachmentPath: tempPathWithExtension
|
||||
);
|
||||
|
||||
System.IO.File.Delete(tempPath);
|
||||
System.IO.File.Delete(tempPathWithExtension);
|
||||
return Ok("Отчет успешно отправлен на почту");
|
||||
}
|
||||
|
||||
@@ -130,30 +193,41 @@ public class ReportController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка pdf отчета Клиентов по Депозитам
|
||||
/// </summary>
|
||||
/// <param name="mailInfo"></param>
|
||||
/// <param name="fromDate"></param>
|
||||
/// <param name="toDate"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> SendReportByDeposit(string email, DateTime fromDate, DateTime toDate, CancellationToken ct)
|
||||
public async Task<IActionResult> SendReportByDeposit([FromBody] DepositReportMailSendInfoBindingModel mailInfo, DateTime fromDate, DateTime toDate, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var report = await _adapter.CreateDocumentClientsByDepositAsync(fromDate, toDate, ct);
|
||||
var response = report.GetResponse(Request, Response);
|
||||
|
||||
|
||||
if (response is FileStreamResult fileResult)
|
||||
{
|
||||
var tempPath = Path.GetTempFileName();
|
||||
using (var fileStream = new FileStream(tempPath, FileMode.Create))
|
||||
var tempPathWithExtension = Path.ChangeExtension(tempPath, ".pdf");
|
||||
|
||||
using (var fileStream = new FileStream(tempPathWithExtension, FileMode.Create))
|
||||
{
|
||||
await fileResult.FileStream.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
await _emailService.SendReportAsync(
|
||||
toEmail: email,
|
||||
subject: "Отчет по клиентам по вкладам",
|
||||
body: $"<h1>Отчет по клиентам по вкладам</h1><p>Отчет за период с {fromDate:dd.MM.yyyy} по {toDate:dd.MM.yyyy}</p>",
|
||||
attachmentPath: tempPath
|
||||
toEmail: mailInfo.Email,
|
||||
subject: mailInfo.Subject,
|
||||
body: mailInfo.Body,
|
||||
attachmentPath: tempPathWithExtension
|
||||
);
|
||||
|
||||
System.IO.File.Delete(tempPath);
|
||||
System.IO.File.Delete(tempPathWithExtension);
|
||||
return Ok("Отчет успешно отправлен на почту");
|
||||
}
|
||||
|
||||
@@ -165,30 +239,42 @@ public class ReportController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка pdf отчета Вкладов и Кредитных программ по Валютам
|
||||
/// кладовщик pdf
|
||||
/// </summary>
|
||||
/// <param name="mailInfo"></param>
|
||||
/// <param name="fromDate"></param>
|
||||
/// <param name="toDate"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> SendReportByCurrency(string email, DateTime fromDate, DateTime toDate, CancellationToken ct)
|
||||
public async Task<IActionResult> SendReportByCurrency([FromBody] DepositReportMailSendInfoBindingModel mailInfo, DateTime fromDate, DateTime toDate, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var report = await _adapter.CreateDocumentDepositAndCreditProgramByCurrencyAsync(fromDate, toDate, ct);
|
||||
var response = report.GetResponse(Request, Response);
|
||||
|
||||
|
||||
if (response is FileStreamResult fileResult)
|
||||
{
|
||||
var tempPath = Path.GetTempFileName();
|
||||
using (var fileStream = new FileStream(tempPath, FileMode.Create))
|
||||
var tempPathWithExtension = Path.ChangeExtension(tempPath, ".pdf");
|
||||
|
||||
using (var fileStream = new FileStream(tempPathWithExtension, FileMode.Create))
|
||||
{
|
||||
await fileResult.FileStream.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
await _emailService.SendReportAsync(
|
||||
toEmail: email,
|
||||
subject: "Отчет по вкладам и кредитным программам по валютам",
|
||||
body: $"<h1>Отчет по вкладам и кредитным программам по валютам</h1><p>Отчет за период с {fromDate:dd.MM.yyyy} по {toDate:dd.MM.yyyy}</p>",
|
||||
attachmentPath: tempPath
|
||||
toEmail: mailInfo.Email,
|
||||
subject: mailInfo.Subject,
|
||||
body: mailInfo.Body,
|
||||
attachmentPath: tempPathWithExtension
|
||||
);
|
||||
|
||||
System.IO.File.Delete(tempPath);
|
||||
System.IO.File.Delete(tempPathWithExtension);
|
||||
return Ok("Отчет успешно отправлен на почту");
|
||||
}
|
||||
|
||||
@@ -200,30 +286,39 @@ public class ReportController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка excel отчета Клиентов по Кредитным программам
|
||||
/// </summary>
|
||||
/// <param name="mailInfo"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> SendExcelReportByCreditProgram(string email, CancellationToken ct)
|
||||
public async Task<IActionResult> SendExcelReportByCreditProgram([FromBody] CreditProgramReportMailSendInfoBindingModel mailInfo, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var report = await _adapter.CreateExcelDocumentClientsByCreditProgramAsync(ct);
|
||||
var report = await _adapter.CreateExcelDocumentClientsByCreditProgramAsync(mailInfo.CreditProgramIds, ct);
|
||||
var response = report.GetResponse(Request, Response);
|
||||
|
||||
|
||||
if (response is FileStreamResult fileResult)
|
||||
{
|
||||
var tempPath = Path.GetTempFileName();
|
||||
using (var fileStream = new FileStream(tempPath, FileMode.Create))
|
||||
var tempPathWithExtension = Path.ChangeExtension(tempPath, ".xlsx");
|
||||
|
||||
using (var fileStream = new FileStream(tempPathWithExtension, FileMode.Create))
|
||||
{
|
||||
await fileResult.FileStream.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
await _emailService.SendReportAsync(
|
||||
toEmail: email,
|
||||
subject: "Excel отчет по клиентам по кредитным программам",
|
||||
body: "<h1>Excel отчет по клиентам по кредитным программам</h1><p>В приложении находится Excel отчет по клиентам по кредитным программам.</p>",
|
||||
attachmentPath: tempPath
|
||||
toEmail: mailInfo.Email,
|
||||
subject: mailInfo.Subject,
|
||||
body: mailInfo.Body,
|
||||
attachmentPath: tempPathWithExtension
|
||||
);
|
||||
|
||||
System.IO.File.Delete(tempPath);
|
||||
System.IO.File.Delete(tempPathWithExtension);
|
||||
return Ok("Excel отчет успешно отправлен на почту");
|
||||
}
|
||||
|
||||
@@ -235,30 +330,39 @@ public class ReportController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка word отчета Вкладов по Кредитных программ
|
||||
/// </summary>
|
||||
/// <param name="mailInfo"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> SendReportDepositByCreditProgram(string email, CancellationToken ct)
|
||||
public async Task<IActionResult> SendReportDepositByCreditProgram([FromBody] CreditProgramReportMailSendInfoBindingModel mailInfo, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var report = await _adapter.CreateDocumentDepositByCreditProgramAsync(ct);
|
||||
var report = await _adapter.CreateDocumentDepositByCreditProgramAsync(mailInfo.CreditProgramIds, ct);
|
||||
var response = report.GetResponse(Request, Response);
|
||||
|
||||
|
||||
if (response is FileStreamResult fileResult)
|
||||
{
|
||||
var tempPath = Path.GetTempFileName();
|
||||
using (var fileStream = new FileStream(tempPath, FileMode.Create))
|
||||
var tempPathWithExtension = Path.ChangeExtension(tempPath, ".docx");
|
||||
|
||||
using (var fileStream = new FileStream(tempPathWithExtension, FileMode.Create))
|
||||
{
|
||||
await fileResult.FileStream.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
await _emailService.SendReportAsync(
|
||||
toEmail: email,
|
||||
subject: "Отчет по вкладам по кредитным программам",
|
||||
body: "<h1>Отчет по вкладам по кредитным программам</h1><p>В приложении находится отчет по вкладам по кредитным программам.</p>",
|
||||
attachmentPath: tempPath
|
||||
toEmail: mailInfo.Email,
|
||||
subject: mailInfo.Subject,
|
||||
body: mailInfo.Body,
|
||||
attachmentPath: tempPathWithExtension
|
||||
);
|
||||
|
||||
System.IO.File.Delete(tempPath);
|
||||
System.IO.File.Delete(tempPathWithExtension);
|
||||
return Ok("Отчет успешно отправлен на почту");
|
||||
}
|
||||
|
||||
@@ -270,30 +374,39 @@ public class ReportController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправка excel отчета Вкладов по Кредитных программ
|
||||
/// </summary>
|
||||
/// <param name="mailInfo"></param>
|
||||
/// <param name="ct"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> SendExcelReportDepositByCreditProgram(string email, CancellationToken ct)
|
||||
public async Task<IActionResult> SendExcelReportDepositByCreditProgram([FromBody] CreditProgramReportMailSendInfoBindingModel mailInfo, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
var report = await _adapter.CreateExcelDocumentDepositByCreditProgramAsync(ct);
|
||||
var report = await _adapter.CreateExcelDocumentDepositByCreditProgramAsync(mailInfo.CreditProgramIds, ct);
|
||||
var response = report.GetResponse(Request, Response);
|
||||
|
||||
|
||||
if (response is FileStreamResult fileResult)
|
||||
{
|
||||
var tempPath = Path.GetTempFileName();
|
||||
using (var fileStream = new FileStream(tempPath, FileMode.Create))
|
||||
var tempPathWithExtension = Path.ChangeExtension(tempPath, ".xlsx");
|
||||
|
||||
using (var fileStream = new FileStream(tempPathWithExtension, FileMode.Create))
|
||||
{
|
||||
await fileResult.FileStream.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
await _emailService.SendReportAsync(
|
||||
toEmail: email,
|
||||
subject: "Excel отчет по вкладам по кредитным программам",
|
||||
body: "<h1>Excel отчет по вкладам по кредитным программам</h1><p>В приложении находится Excel отчет по вкладам по кредитным программам.</p>",
|
||||
attachmentPath: tempPath
|
||||
toEmail: mailInfo.Email,
|
||||
subject: mailInfo.Subject,
|
||||
body: mailInfo.Body,
|
||||
attachmentPath: tempPathWithExtension
|
||||
);
|
||||
|
||||
System.IO.File.Delete(tempPath);
|
||||
System.IO.File.Delete(tempPathWithExtension);
|
||||
return Ok("Excel отчет успешно отправлен на почту");
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using BankContracts.BindingModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace BankWebApi.Controllers;
|
||||
|
||||
@@ -39,7 +40,8 @@ public class StorekeepersController(IStorekeeperAdapter adapter) : ControllerBas
|
||||
/// </summary>
|
||||
/// <param name="model">модель от пользователя</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[HttpPost("register")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Register([FromBody] StorekeeperBindingModel model)
|
||||
{
|
||||
return _adapter.RegisterStorekeeper(model).GetResponse(Request, Response);
|
||||
@@ -55,4 +57,58 @@ public class StorekeepersController(IStorekeeperAdapter adapter) : ControllerBas
|
||||
{
|
||||
return _adapter.ChangeStorekeeperInfo(model).GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// вход для кладовщика
|
||||
/// </summary>
|
||||
/// <param name="model">модель с логином и паролем</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("login")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Login([FromBody] LoginBindingModel model)
|
||||
{
|
||||
var res = _adapter.Login(model, out string token);
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
return res.GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
Response.Cookies.Append(AuthOptions.CookieName, token, new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
SameSite = SameSiteMode.None,
|
||||
Secure = true,
|
||||
Expires = DateTime.UtcNow.AddDays(2)
|
||||
});
|
||||
|
||||
return res.GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных текущего кладовщика
|
||||
/// </summary>
|
||||
/// <returns>Данные кладовщика</returns>
|
||||
[HttpGet("me")]
|
||||
public IActionResult GetCurrentUser()
|
||||
{
|
||||
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var response = _adapter.GetElement(userId);
|
||||
return response.GetResponse(Request, Response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выход кладовщика
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("logout")]
|
||||
public IActionResult Logout()
|
||||
{
|
||||
Response.Cookies.Delete(AuthOptions.CookieName);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
74
TheBank/BankWebApi/Controllers/clerkReports.http
Normal file
74
TheBank/BankWebApi/Controllers/clerkReports.http
Normal file
@@ -0,0 +1,74 @@
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD> Word <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
GET /api/Report/LoadClientsByCreditProgram?creditProgramIds={{creditProgramIds}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/octet-stream
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, ClientSurname, ClientName, ClientBalance
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Word-<2D><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD> Excel <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
GET /api/Report/LoadExcelClientByCreditProgram?creditProgramIds={{creditProgramIds}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/octet-stream
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, ClientSurname, ClientName, ClientBalance
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel-<2D><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD> PDF <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
GET /api/Report/LoadClientsByDeposit?fromDate={{fromDate}}&toDate={{toDate}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/octet-stream
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: ClientSurname, ClientName, ClientBalance, DepositRate, DepositPeriod, FromPeriod, ToPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> PDF-<2D><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataClientsByDepositAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (JSON)
|
||||
GET /api/Report/GetClientByCreditProgram?creditProgramIds={{creditProgramIds}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramId, CreditProgramName, ClientSurname, ClientName, ClientBalance
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (JSON)
|
||||
GET /api/Report/GetClientByDeposit?fromDate={{fromDate}}&toDate={{toDate}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: ClientSurname, ClientName, ClientBalance, DepositRate, DepositPeriod, FromPeriod, ToPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataClientsByDepositAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Word <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> email: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
POST /api/Report/SendReportByCreditProgram HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
{
|
||||
"email": "{{email}}",
|
||||
"creditProgramIds": {{creditProgramIds}}
|
||||
}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, ClientSurname, ClientName, ClientBalance
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Word-<2D><><EFBFBD><EFBFBD><EFBFBD> <20><> email.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> email: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
POST /api/Report/SendExcelReportByCreditProgram HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
{
|
||||
"email": "{{email}}",
|
||||
"creditProgramIds": {{creditProgramIds}}
|
||||
}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, ClientSurname, ClientName, ClientBalance
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel-<2D><><EFBFBD><EFBFBD><EFBFBD> <20><> email.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> PDF <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> email: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
POST /api/Report/SendReportByDeposit?fromDate={{fromDate}}&toDate={{toDate}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
{
|
||||
"email": "{{email}}"
|
||||
}
|
||||
# <20><><EFBFBD><EFBFBD>: ClientSurname, ClientName, ClientBalance, DepositRate, DepositPeriod, FromPeriod, ToPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> PDF-<2D><><EFBFBD><EFBFBD><EFBFBD> <20><> email. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataClientsByDepositAsync.
|
||||
76
TheBank/BankWebApi/Controllers/storekeeperReports.http
Normal file
76
TheBank/BankWebApi/Controllers/storekeeperReports.http
Normal file
@@ -0,0 +1,76 @@
|
||||
```
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD> Word <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
GET /api/Report/LoadDepositByCreditProgram?creditProgramIds={{creditProgramIds}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/octet-stream
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, DepositRate, DepositCost, DepositPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Word-<2D><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataDepositByCreditProgramAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD> Excel <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
GET /api/Report/LoadExcelDepositByCreditProgram?creditProgramIds={{creditProgramIds}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/octet-stream
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, DepositRate, DepositCost, DepositPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel-<2D><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataDepositByCreditProgramAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD> PDF <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
GET /api/Report/LoadDepositAndCreditProgramByCurrency?fromDate={{fromDate}}&toDate={{toDate}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/octet-stream
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: CurrencyName, CreditProgramName, CreditProgramMaxCost, DepositRate, DepositPeriod, FromPeriod, ToPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> PDF-<2D><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataDepositAndCreditProgramByCurrencyAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (JSON)
|
||||
GET /api/Report/GetDepositByCreditProgram?creditProgramIds={{creditProgramIds}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, DepositRate, DepositCost, DepositPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataDepositByCreditProgramAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (JSON)
|
||||
GET /api/Report/GetDepositAndCreditProgramByCurrency?fromDate={{fromDate}}&toDate={{toDate}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
# <20><><EFBFBD><EFBFBD>: CurrencyName, CreditProgramName, CreditProgramMaxCost, DepositRate, DepositPeriod, FromPeriod, ToPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataDepositAndCreditProgramByCurrencyAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Word <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> email: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
POST /api/Report/SendReportDepositByCreditProgram HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
{
|
||||
"email": "{{email}}",
|
||||
"creditProgramIds": {{creditProgramIds}}
|
||||
}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, DepositRate, DepositCost, DepositPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Word-<2D><><EFBFBD><EFBFBD><EFBFBD> <20><> email. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataDepositByCreditProgramAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> email: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
POST /api/Report/SendExcelReportDepositByCreditProgram HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
{
|
||||
"email": "{{email}}",
|
||||
"creditProgramIds": {{creditProgramIds}}
|
||||
}
|
||||
# <20><><EFBFBD><EFBFBD>: CreditProgramName, DepositRate, DepositCost, DepositPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel-<2D><><EFBFBD><EFBFBD><EFBFBD> <20><> email. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataDepositByCreditProgramAsync.
|
||||
|
||||
### <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> PDF <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> email: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
POST /api/Report/SendReportByCurrency?fromDate={{fromDate}}&toDate={{toDate}} HTTP/1.1
|
||||
Host: localhost
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
{
|
||||
"email": "{{email}}"
|
||||
}
|
||||
# <20><><EFBFBD><EFBFBD>: CurrencyName, CreditProgramName, CreditProgramMaxCost, DepositRate, DepositPeriod, FromPeriod, ToPeriod
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> PDF-<2D><><EFBFBD><EFBFBD><EFBFBD> <20><> email. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> currencyIds <20> GetDataDepositAndCreditProgramByCurrencyAsync.
|
||||
```
|
||||
10
TheBank/BankWebApi/Infrastructure/IJwtProvider.cs
Normal file
10
TheBank/BankWebApi/Infrastructure/IJwtProvider.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using BankContracts.DataModels;
|
||||
|
||||
namespace BankWebApi.Infrastructure;
|
||||
|
||||
public interface IJwtProvider
|
||||
{
|
||||
string GenerateToken(StorekeeperDataModel dataModel);
|
||||
|
||||
string GenerateToken(ClerkDataModel dataModel);
|
||||
}
|
||||
31
TheBank/BankWebApi/Infrastructure/JwtProvider.cs
Normal file
31
TheBank/BankWebApi/Infrastructure/JwtProvider.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using BankContracts.DataModels;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace BankWebApi.Infrastructure;
|
||||
|
||||
public class JwtProvider : IJwtProvider
|
||||
{
|
||||
public string GenerateToken(StorekeeperDataModel dataModel)
|
||||
{
|
||||
return GenerateToken(dataModel.Id);
|
||||
}
|
||||
|
||||
public string GenerateToken(ClerkDataModel dataModel)
|
||||
{
|
||||
return GenerateToken(dataModel.Id);
|
||||
}
|
||||
|
||||
private static string GenerateToken(string id)
|
||||
{
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: AuthOptions.ISSUER,
|
||||
audience: AuthOptions.AUDIENCE,
|
||||
claims: [new(ClaimTypes.NameIdentifier, id)],
|
||||
expires: DateTime.UtcNow.Add(TimeSpan.FromDays(2)),
|
||||
signingCredentials: new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256));
|
||||
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
}
|
||||
10
TheBank/BankWebApi/Infrastructure/PasswordHelper.cs
Normal file
10
TheBank/BankWebApi/Infrastructure/PasswordHelper.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace BankWebApi.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// да пох на это
|
||||
/// </summary>
|
||||
public class PasswordHelper
|
||||
{
|
||||
public static string HashPassword(string password) => BCrypt.Net.BCrypt.HashPassword(password);
|
||||
public static bool VerifyPassword(string password, string hash) => BCrypt.Net.BCrypt.Verify(password, hash);
|
||||
}
|
||||
@@ -29,12 +29,11 @@ builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Bank API", Version = "v1" });
|
||||
|
||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> XML-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD>)
|
||||
// Включение XML-комментариев (если они есть)
|
||||
var xmlFile = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
c.IncludeXmlComments(xmlPath, includeControllerXmlComments: true);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> JWT-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> Swagger UI
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Description = "JWT Authorization header using the Bearer scheme. Example: 'Bearer {token}'",
|
||||
@@ -79,13 +78,33 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
|
||||
|
||||
ValidateIssuerSigningKey = true,
|
||||
|
||||
};
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
context.Token = context.Request.Cookies[AuthOptions.CookieName];
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowFrontend", policy =>
|
||||
{
|
||||
policy.WithOrigins("http://localhost:26312", "http://localhost:3654")
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials();
|
||||
});
|
||||
});
|
||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||
builder.Services.AddOpenApi();
|
||||
builder.Services.AddSingleton<IConfigurationDatabase, ConfigurationDatabase>();
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
builder.Services.AddSingleton<IConfigurationDatabase, BankWebApi.Infrastructure.ConfigurationDatabase>();
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
builder.Services.AddTransient<IClerkBusinessLogicContract, ClerkBusinessLogicContract>();
|
||||
builder.Services.AddTransient<IPeriodBusinessLogicContract, PeriodBusinessLogicContract>();
|
||||
builder.Services.AddTransient<IDepositBusinessLogicContract, DepositBusinessLogicContract>();
|
||||
@@ -94,7 +113,7 @@ builder.Services.AddTransient<ICreditProgramBusinessLogicContract, CreditProgram
|
||||
builder.Services.AddTransient<ICurrencyBusinessLogicContract, CurrencyBusinessLogicContract>();
|
||||
builder.Services.AddTransient<IStorekeeperBusinessLogicContract, StorekeeperBusinessLogicContract>();
|
||||
builder.Services.AddTransient<IReplenishmentBusinessLogicContract, ReplenishmentBusinessLogicContract>();
|
||||
// <20><>
|
||||
// <20><>
|
||||
builder.Services.AddTransient<BankDbContext>();
|
||||
builder.Services.AddTransient<IClerkStorageContract, ClerkStorageContract>();
|
||||
builder.Services.AddTransient<IPeriodStorageContract, PeriodStorageContract>();
|
||||
@@ -104,7 +123,7 @@ builder.Services.AddTransient<ICreditProgramStorageContract, CreditProgramStorag
|
||||
builder.Services.AddTransient<ICurrencyStorageContract, CurrencyStorageContract>();
|
||||
builder.Services.AddTransient<IStorekeeperStorageContract, StorekeeperStorageContract>();
|
||||
builder.Services.AddTransient<IReplenishmentStorageContract, ReplenishmentStorageContract>();
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
builder.Services.AddTransient<IClerkAdapter, ClerkAdapter>();
|
||||
builder.Services.AddTransient<IPeriodAdapter, PeriodAdapter>();
|
||||
builder.Services.AddTransient<IDepositAdapter, DepositAdapter>();
|
||||
@@ -118,6 +137,8 @@ builder.Services.AddTransient<IReportAdapter, ReportAdapter>();
|
||||
builder.Services.AddTransient<BaseWordBuilder, OpenXmlWordBuilder>();
|
||||
builder.Services.AddTransient<BaseExcelBuilder, OpenXmlExcelBuilder>();
|
||||
builder.Services.AddTransient<BasePdfBuilder, MigraDocPdfBuilder>();
|
||||
// shit
|
||||
builder.Services.AddTransient<IJwtProvider, JwtProvider>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
@@ -129,7 +150,7 @@ if (app.Environment.IsDevelopment())
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Bank API V1");
|
||||
c.RoutePrefix = "swagger"; // Swagger UI <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> /swagger
|
||||
c.RoutePrefix = "swagger"; // Swagger UI <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> /swagger
|
||||
});
|
||||
}
|
||||
if (app.Environment.IsProduction())
|
||||
@@ -141,11 +162,19 @@ if (app.Environment.IsProduction())
|
||||
dbContext.Database.Migrate();
|
||||
}
|
||||
}
|
||||
|
||||
app.UseCors("AllowFrontend");
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseCookiePolicy(new CookiePolicyOptions
|
||||
{
|
||||
HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always,
|
||||
Secure = app.Environment.IsProduction() ? CookieSecurePolicy.Always : CookieSecurePolicy.None
|
||||
});
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
// это для тестов
|
||||
app.Map("/login/{username}", (string username) =>
|
||||
{
|
||||
return new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken(
|
||||
|
||||
@@ -13,6 +13,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BankTests", "BankTests\Bank
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BankWebApi", "BankWebApi\BankWebApi.csproj", "{C8A3A3BB-A096-429F-A763-5465C5CB735F}"
|
||||
EndProject
|
||||
Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "bankui", "BankUI\bankui.esproj", "{12D5DDAD-F24A-41B0-9FBC-BEFBFB01067D}"
|
||||
EndProject
|
||||
Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "bankuiclerk", "BankUIClerk\bankuiclerk.esproj", "{FD37483B-1D73-44B8-9D8B-38FE8F039E48}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -39,6 +43,18 @@ Global
|
||||
{C8A3A3BB-A096-429F-A763-5465C5CB735F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C8A3A3BB-A096-429F-A763-5465C5CB735F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C8A3A3BB-A096-429F-A763-5465C5CB735F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{12D5DDAD-F24A-41B0-9FBC-BEFBFB01067D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{12D5DDAD-F24A-41B0-9FBC-BEFBFB01067D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{12D5DDAD-F24A-41B0-9FBC-BEFBFB01067D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{12D5DDAD-F24A-41B0-9FBC-BEFBFB01067D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{12D5DDAD-F24A-41B0-9FBC-BEFBFB01067D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{12D5DDAD-F24A-41B0-9FBC-BEFBFB01067D}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{FD37483B-1D73-44B8-9D8B-38FE8F039E48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD37483B-1D73-44B8-9D8B-38FE8F039E48}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD37483B-1D73-44B8-9D8B-38FE8F039E48}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{FD37483B-1D73-44B8-9D8B-38FE8F039E48}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD37483B-1D73-44B8-9D8B-38FE8F039E48}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FD37483B-1D73-44B8-9D8B-38FE8F039E48}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
2
TheBank/bankui/.env
Normal file
2
TheBank/bankui/.env
Normal file
@@ -0,0 +1,2 @@
|
||||
VITE_API_URL=https://localhost:7204
|
||||
# VITE_API_URL=http://localhost:5189
|
||||
26
TheBank/bankui/.gitignore
vendored
Normal file
26
TheBank/bankui/.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
package-lock.json
|
||||
7
TheBank/bankui/.prettierrc
Normal file
7
TheBank/bankui/.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"semi": true,
|
||||
"jsxSingleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
12
TheBank/bankui/CHANGELOG.md
Normal file
12
TheBank/bankui/CHANGELOG.md
Normal file
@@ -0,0 +1,12 @@
|
||||
This file explains how Visual Studio created the project.
|
||||
|
||||
The following tools were used to generate this project:
|
||||
- create-vite
|
||||
|
||||
The following steps were used to generate this project:
|
||||
- Create react project with create-vite: `npm init --yes vite@latest bankui -- --template=react-ts`.
|
||||
- Updating vite.config.ts with port.
|
||||
- Create project file (`bankui.esproj`).
|
||||
- Create `launch.json` to enable debugging.
|
||||
- Add project to solution.
|
||||
- Write this file.
|
||||
54
TheBank/bankui/README.md
Normal file
54
TheBank/bankui/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# React + TypeScript + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
||||
|
||||
```js
|
||||
export default tseslint.config({
|
||||
extends: [
|
||||
// Remove ...tseslint.configs.recommended and replace with this
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
// Alternatively, use this for stricter rules
|
||||
...tseslint.configs.strictTypeChecked,
|
||||
// Optionally, add this for stylistic rules
|
||||
...tseslint.configs.stylisticTypeChecked,
|
||||
],
|
||||
languageOptions: {
|
||||
// other options...
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
||||
|
||||
```js
|
||||
// eslint.config.js
|
||||
import reactX from 'eslint-plugin-react-x'
|
||||
import reactDom from 'eslint-plugin-react-dom'
|
||||
|
||||
export default tseslint.config({
|
||||
plugins: {
|
||||
// Add the react-x and react-dom plugins
|
||||
'react-x': reactX,
|
||||
'react-dom': reactDom,
|
||||
},
|
||||
rules: {
|
||||
// other rules...
|
||||
// Enable its recommended typescript rules
|
||||
...reactX.configs['recommended-typescript'].rules,
|
||||
...reactDom.configs.recommended.rules,
|
||||
},
|
||||
})
|
||||
```
|
||||
11
TheBank/bankui/bankui.esproj
Normal file
11
TheBank/bankui/bankui.esproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/1.0.1738743">
|
||||
<PropertyGroup>
|
||||
<StartupCommand>npm run dev</StartupCommand>
|
||||
<JavaScriptTestRoot>src\</JavaScriptTestRoot>
|
||||
<JavaScriptTestFramework>Jest</JavaScriptTestFramework>
|
||||
<!-- Allows the build (or compile) script located on package.json to run on Build -->
|
||||
<ShouldRunBuildScript>false</ShouldRunBuildScript>
|
||||
<!-- Folder where production build objects will be placed -->
|
||||
<BuildOutputFolder>$(MSBuildProjectDirectory)\dist</BuildOutputFolder>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
BIN
TheBank/bankui/bun.lockb
Normal file
BIN
TheBank/bankui/bun.lockb
Normal file
Binary file not shown.
21
TheBank/bankui/components.json
Normal file
21
TheBank/bankui/components.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
28
TheBank/bankui/eslint.config.js
Normal file
28
TheBank/bankui/eslint.config.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['dist'] },
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
13
TheBank/bankui/index.html
Normal file
13
TheBank/bankui/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Шрек</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root" class="roboto"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
4796
TheBank/bankui/package-lock.json
generated
4796
TheBank/bankui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
63
TheBank/bankui/package.json
Normal file
63
TheBank/bankui/package.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"name": "bankui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.0.1",
|
||||
"@radix-ui/react-avatar": "^1.1.9",
|
||||
"@radix-ui/react-checkbox": "^1.3.1",
|
||||
"@radix-ui/react-dialog": "^1.1.14",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.14",
|
||||
"@radix-ui/react-label": "^2.1.6",
|
||||
"@radix-ui/react-menubar": "^1.1.14",
|
||||
"@radix-ui/react-popover": "^1.1.13",
|
||||
"@radix-ui/react-radio-group": "^1.3.7",
|
||||
"@radix-ui/react-select": "^2.2.4",
|
||||
"@radix-ui/react-separator": "^1.1.6",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-tabs": "^1.1.11",
|
||||
"@radix-ui/react-tooltip": "^1.2.6",
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"@tanstack/react-query": "^5.76.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.511.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"pdfjs-dist": "^5.2.133",
|
||||
"react": "^19.1.0",
|
||||
"react-day-picker": "8.10.1",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-hook-form": "^7.56.4",
|
||||
"react-pdf": "^9.2.1",
|
||||
"react-router-dom": "^7.6.0",
|
||||
"sonner": "^2.0.3",
|
||||
"tailwind-merge": "^3.3.0",
|
||||
"tailwindcss": "^4.1.7",
|
||||
"tw-animate-css": "^1.3.0",
|
||||
"zod": "^3.24.4",
|
||||
"zustand": "^5.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.25.0",
|
||||
"@types/node": "^22.15.18",
|
||||
"@types/react": "^19.1.2",
|
||||
"@types/react-dom": "^19.1.2",
|
||||
"@vitejs/plugin-react": "^4.4.1",
|
||||
"eslint": "^9.25.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"globals": "^16.0.0",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.30.1",
|
||||
"vite": "^6.3.5"
|
||||
}
|
||||
}
|
||||
BIN
TheBank/bankui/public/Shrek.png
Normal file
BIN
TheBank/bankui/public/Shrek.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
1
TheBank/bankui/public/icons/excel.svg
Normal file
1
TheBank/bankui/public/icons/excel.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path fill="#169154" d="M29,6H15.744C14.781,6,14,6.781,14,7.744v7.259h15V6z"/><path fill="#18482a" d="M14,33.054v7.202C14,41.219,14.781,42,15.743,42H29v-8.946H14z"/><path fill="#0c8045" d="M14 15.003H29V24.005000000000003H14z"/><path fill="#17472a" d="M14 24.005H29V33.055H14z"/><g><path fill="#29c27f" d="M42.256,6H29v9.003h15V7.744C44,6.781,43.219,6,42.256,6z"/><path fill="#27663f" d="M29,33.054V42h13.257C43.219,42,44,41.219,44,40.257v-7.202H29z"/><path fill="#19ac65" d="M29 15.003H44V24.005000000000003H29z"/><path fill="#129652" d="M29 24.005H44V33.055H29z"/></g><path fill="#0c7238" d="M22.319,34H5.681C4.753,34,4,33.247,4,32.319V15.681C4,14.753,4.753,14,5.681,14h16.638 C23.247,14,24,14.753,24,15.681v16.638C24,33.247,23.247,34,22.319,34z"/><path fill="#fff" d="M9.807 19L12.193 19 14.129 22.754 16.175 19 18.404 19 15.333 24 18.474 29 16.123 29 14.013 25.07 11.912 29 9.526 29 12.719 23.982z"/></svg>
|
||||
|
After Width: | Height: | Size: 998 B |
4
TheBank/bankui/public/icons/pdf.svg
Normal file
4
TheBank/bankui/public/icons/pdf.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="35px" height="35px" viewBox="-4 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M25.6686 26.0962C25.1812 26.2401 24.4656 26.2563 23.6984 26.145C22.875 26.0256 22.0351 25.7739 21.2096 25.403C22.6817 25.1888 23.8237 25.2548 24.8005 25.6009C25.0319 25.6829 25.412 25.9021 25.6686 26.0962ZM17.4552 24.7459C17.3953 24.7622 17.3363 24.7776 17.2776 24.7939C16.8815 24.9017 16.4961 25.0069 16.1247 25.1005L15.6239 25.2275C14.6165 25.4824 13.5865 25.7428 12.5692 26.0529C12.9558 25.1206 13.315 24.178 13.6667 23.2564C13.9271 22.5742 14.193 21.8773 14.468 21.1894C14.6075 21.4198 14.7531 21.6503 14.9046 21.8814C15.5948 22.9326 16.4624 23.9045 17.4552 24.7459ZM14.8927 14.2326C14.958 15.383 14.7098 16.4897 14.3457 17.5514C13.8972 16.2386 13.6882 14.7889 14.2489 13.6185C14.3927 13.3185 14.5105 13.1581 14.5869 13.0744C14.7049 13.2566 14.8601 13.6642 14.8927 14.2326ZM9.63347 28.8054C9.38148 29.2562 9.12426 29.6782 8.86063 30.0767C8.22442 31.0355 7.18393 32.0621 6.64941 32.0621C6.59681 32.0621 6.53316 32.0536 6.44015 31.9554C6.38028 31.8926 6.37069 31.8476 6.37359 31.7862C6.39161 31.4337 6.85867 30.8059 7.53527 30.2238C8.14939 29.6957 8.84352 29.2262 9.63347 28.8054ZM27.3706 26.1461C27.2889 24.9719 25.3123 24.2186 25.2928 24.2116C24.5287 23.9407 23.6986 23.8091 22.7552 23.8091C21.7453 23.8091 20.6565 23.9552 19.2582 24.2819C18.014 23.3999 16.9392 22.2957 16.1362 21.0733C15.7816 20.5332 15.4628 19.9941 15.1849 19.4675C15.8633 17.8454 16.4742 16.1013 16.3632 14.1479C16.2737 12.5816 15.5674 11.5295 14.6069 11.5295C13.948 11.5295 13.3807 12.0175 12.9194 12.9813C12.0965 14.6987 12.3128 16.8962 13.562 19.5184C13.1121 20.5751 12.6941 21.6706 12.2895 22.7311C11.7861 24.0498 11.2674 25.4103 10.6828 26.7045C9.04334 27.3532 7.69648 28.1399 6.57402 29.1057C5.8387 29.7373 4.95223 30.7028 4.90163 31.7107C4.87693 32.1854 5.03969 32.6207 5.37044 32.9695C5.72183 33.3398 6.16329 33.5348 6.6487 33.5354C8.25189 33.5354 9.79489 31.3327 10.0876 30.8909C10.6767 30.0029 11.2281 29.0124 11.7684 27.8699C13.1292 27.3781 14.5794 27.011 15.985 26.6562L16.4884 26.5283C16.8668 26.4321 17.2601 26.3257 17.6635 26.2153C18.0904 26.0999 18.5296 25.9802 18.976 25.8665C20.4193 26.7844 21.9714 27.3831 23.4851 27.6028C24.7601 27.7883 25.8924 27.6807 26.6589 27.2811C27.3486 26.9219 27.3866 26.3676 27.3706 26.1461ZM30.4755 36.2428C30.4755 38.3932 28.5802 38.5258 28.1978 38.5301H3.74486C1.60224 38.5301 1.47322 36.6218 1.46913 36.2428L1.46884 3.75642C1.46884 1.6039 3.36763 1.4734 3.74457 1.46908H20.263L20.2718 1.4778V7.92396C20.2718 9.21763 21.0539 11.6669 24.0158 11.6669H30.4203L30.4753 11.7218L30.4755 36.2428ZM28.9572 10.1976H24.0169C21.8749 10.1976 21.7453 8.29969 21.7424 7.92417V2.95307L28.9572 10.1976ZM31.9447 36.2428V11.1157L21.7424 0.871022V0.823357H21.6936L20.8742 0H3.74491C2.44954 0 0 0.785336 0 3.75711V36.2435C0 37.5427 0.782956 40 3.74491 40H28.2001C29.4952 39.9997 31.9447 39.2143 31.9447 36.2428Z" fill="#EB5757"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
1
TheBank/bankui/public/icons/word.svg
Normal file
1
TheBank/bankui/public/icons/word.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="50px" height="50px"><path d="M 28.8125 0.03125 L 0.8125 5.34375 C 0.339844 5.433594 0 5.863281 0 6.34375 L 0 43.65625 C 0 44.136719 0.339844 44.566406 0.8125 44.65625 L 28.8125 49.96875 C 28.875 49.980469 28.9375 50 29 50 C 29.230469 50 29.445313 49.929688 29.625 49.78125 C 29.855469 49.589844 30 49.296875 30 49 L 30 1 C 30 0.703125 29.855469 0.410156 29.625 0.21875 C 29.394531 0.0273438 29.105469 -0.0234375 28.8125 0.03125 Z M 32 6 L 32 13 L 44 13 L 44 15 L 32 15 L 32 20 L 44 20 L 44 22 L 32 22 L 32 27 L 44 27 L 44 29 L 32 29 L 32 35 L 44 35 L 44 37 L 32 37 L 32 44 L 47 44 C 48.101563 44 49 43.101563 49 42 L 49 8 C 49 6.898438 48.101563 6 47 6 Z M 4.625 15.65625 L 8.1875 15.65625 L 10.21875 28.09375 C 10.308594 28.621094 10.367188 29.355469 10.40625 30.25 L 10.46875 30.25 C 10.496094 29.582031 10.613281 28.855469 10.78125 28.0625 L 13.40625 15.65625 L 16.90625 15.65625 L 19.28125 28.21875 C 19.367188 28.679688 19.433594 29.339844 19.5 30.21875 L 19.53125 30.21875 C 19.558594 29.53125 19.632813 28.828125 19.75 28.125 L 21.75 15.65625 L 25.0625 15.65625 L 21.21875 34.34375 L 17.59375 34.34375 L 15.1875 22.375 C 15.058594 21.75 14.996094 21.023438 14.96875 20.25 L 14.9375 20.25 C 14.875 21.101563 14.769531 21.824219 14.65625 22.375 L 12.1875 34.34375 L 8.4375 34.34375 Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
TheBank/bankui/public/vite.svg
Normal file
1
TheBank/bankui/public/vite.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
51
TheBank/bankui/src/App.tsx
Normal file
51
TheBank/bankui/src/App.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useAuthCheck } from '@/hooks/useAuthCheck';
|
||||
import { useAuthStore } from '@/store/workerStore';
|
||||
import { Link, Navigate, Outlet, useLocation } from 'react-router-dom';
|
||||
import { Header } from '@/components/layout/Header';
|
||||
import { Footer } from '@/components/layout/Footer';
|
||||
import { Suspense } from 'react';
|
||||
import { Button } from './components/ui/button';
|
||||
|
||||
function App() {
|
||||
const user = useAuthStore((store) => store.user);
|
||||
const { isLoading } = useAuthCheck();
|
||||
const location = useLocation();
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
const redirect = encodeURIComponent(location.pathname + location.search);
|
||||
return <Navigate to={`/auth?redirect=${redirect}`} replace />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{location.pathname === '/' && (
|
||||
<main className="flex justify-center items-center">
|
||||
<div className="flex-1 flex justify-center items-center">
|
||||
<img className="block" src="/Shrek.png" alt="кладовщик" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div>Удобный сервис для кладовщиков</div>
|
||||
<Link to="/storekeepers">
|
||||
<Button>За работу</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</main>
|
||||
)}
|
||||
{location.pathname !== '/' && (
|
||||
<>
|
||||
<Header />
|
||||
<Suspense fallback={<p>Loading...</p>}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</>
|
||||
)}
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
135
TheBank/bankui/src/api/api.ts
Normal file
135
TheBank/bankui/src/api/api.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import {
|
||||
getData,
|
||||
getSingleData,
|
||||
postData,
|
||||
postLoginData,
|
||||
putData,
|
||||
} from './client';
|
||||
import type {
|
||||
ClientBindingModel,
|
||||
ClerkBindingModel,
|
||||
CreditProgramBindingModel,
|
||||
CurrencyBindingModel,
|
||||
DepositBindingModel,
|
||||
PeriodBindingModel,
|
||||
ReplenishmentBindingModel,
|
||||
StorekeeperBindingModel,
|
||||
LoginBindingModel,
|
||||
} from '../types/types';
|
||||
|
||||
// Clients API
|
||||
export const clientsApi = {
|
||||
getAll: () => getData<ClientBindingModel>('api/Clients/GetAllRecords'),
|
||||
getById: (id: string) =>
|
||||
getData<ClientBindingModel>(`api/Clients/GetRecord/${id}`),
|
||||
getByClerk: (clerkId: string) =>
|
||||
getData<ClientBindingModel>(`api/Clients/GetRecordByClerk/${clerkId}`),
|
||||
create: (data: ClientBindingModel) => postData('api/Clients/Register', data),
|
||||
update: (data: ClientBindingModel) => putData('api/Clients/ChangeInfo', data),
|
||||
};
|
||||
|
||||
// Clerks API
|
||||
export const clerksApi = {
|
||||
getAll: () => getData<ClerkBindingModel>('api/Clerks'),
|
||||
getById: (id: string) => getData<ClerkBindingModel>(`api/Clerks/${id}`),
|
||||
create: (data: ClerkBindingModel) => postData('api/Clerks/Register', data),
|
||||
update: (data: ClerkBindingModel) => putData('api/Clerks/ChangeInfo', data),
|
||||
};
|
||||
|
||||
// Credit Programs API
|
||||
export const creditProgramsApi = {
|
||||
getAll: () =>
|
||||
getData<CreditProgramBindingModel>('api/CreditPrograms/GetAllRecords'),
|
||||
getById: (id: string) =>
|
||||
getData<CreditProgramBindingModel>(`api/CreditPrograms/GetRecord/${id}`),
|
||||
getByStorekeeper: (storekeeperId: string) =>
|
||||
getData<CreditProgramBindingModel>(
|
||||
`api/CreditPrograms/GetRecordByStorekeeper/${storekeeperId}`,
|
||||
),
|
||||
create: (data: CreditProgramBindingModel) =>
|
||||
postData('api/CreditPrograms/Register', data),
|
||||
update: (data: CreditProgramBindingModel) =>
|
||||
putData('api/CreditPrograms/ChangeInfo', data),
|
||||
};
|
||||
|
||||
// Currencies API
|
||||
export const currenciesApi = {
|
||||
getAll: () => getData<CurrencyBindingModel>('api/Currencies/GetAllRecords'),
|
||||
getById: (id: string) =>
|
||||
getData<CurrencyBindingModel>(`api/Currencies/GetRecord/${id}`),
|
||||
getByStorekeeper: (storekeeperId: string) =>
|
||||
getData<CurrencyBindingModel>(
|
||||
`api/Currencies/GetRecordByStorekeeper/${storekeeperId}`,
|
||||
),
|
||||
create: (data: CurrencyBindingModel) =>
|
||||
postData('api/Currencies/Register', data),
|
||||
update: (data: CurrencyBindingModel) =>
|
||||
putData('api/Currencies/ChangeInfo', data),
|
||||
};
|
||||
|
||||
// Deposits API
|
||||
export const depositsApi = {
|
||||
getAll: () => getData<DepositBindingModel>('api/Deposits/GetAllRecords'),
|
||||
getById: (id: string) =>
|
||||
getData<DepositBindingModel>(`api/Deposits/GetRecord/${id}`),
|
||||
getByClerk: (clerkId: string) =>
|
||||
getData<DepositBindingModel>(`api/Deposits/GetRecordByClerk/${clerkId}`),
|
||||
create: (data: DepositBindingModel) =>
|
||||
postData('api/Deposits/Register', data),
|
||||
update: (data: DepositBindingModel) =>
|
||||
putData('api/Deposits/ChangeInfo', data),
|
||||
};
|
||||
|
||||
// Periods API
|
||||
export const periodsApi = {
|
||||
getAll: () => getData<PeriodBindingModel>('api/Periods/GetAllRecords'),
|
||||
getById: (id: string) =>
|
||||
getData<PeriodBindingModel>(`api/Periods/GetRecord/${id}`),
|
||||
getByStorekeeper: (storekeeperId: string) =>
|
||||
getData<PeriodBindingModel>(
|
||||
`api/Period/GetRecordByStorekeeper/${storekeeperId}`,
|
||||
),
|
||||
create: (data: PeriodBindingModel) => postData('api/Periods/Register', data),
|
||||
update: (data: PeriodBindingModel) => putData('api/Periods/ChangeInfo', data),
|
||||
};
|
||||
|
||||
// Replenishments API
|
||||
export const replenishmentsApi = {
|
||||
getAll: () =>
|
||||
getData<ReplenishmentBindingModel>('api/Replenishments/GetAllRecords'),
|
||||
getById: (id: string) =>
|
||||
getData<ReplenishmentBindingModel>(`api/Replenishments/GetRecord/${id}`),
|
||||
getByDeposit: (depositId: string) =>
|
||||
getData<ReplenishmentBindingModel>(
|
||||
`api/Replenishments/GetRecordByDeposit/${depositId}`,
|
||||
),
|
||||
getByClerk: (clerkId: string) =>
|
||||
getData<ReplenishmentBindingModel>(
|
||||
`api/Replenishments/GetRecordByClerk/${clerkId}`,
|
||||
),
|
||||
create: (data: ReplenishmentBindingModel) =>
|
||||
postData('api/Replenishments/Register', data),
|
||||
update: (data: ReplenishmentBindingModel) =>
|
||||
putData('api/Replenishments/ChangeInfo', data),
|
||||
};
|
||||
|
||||
// Storekeepers API
|
||||
export const storekeepersApi = {
|
||||
getAll: () => getData<StorekeeperBindingModel>('api/storekeepers'),
|
||||
getById: (id: string) =>
|
||||
getData<StorekeeperBindingModel>(`api/Storekeepers/GetRecord/${id}`),
|
||||
create: (data: StorekeeperBindingModel) =>
|
||||
postData('api/Storekeepers/Register', data),
|
||||
update: (data: StorekeeperBindingModel) => putData('api/Storekeepers', data),
|
||||
// auth
|
||||
login: (data: LoginBindingModel) =>
|
||||
postLoginData('api/Storekeepers/login', data),
|
||||
logout: () => postData('api/storekeepers/logout', {}),
|
||||
getCurrentUser: () =>
|
||||
getSingleData<StorekeeperBindingModel>('api/storekeepers/me'),
|
||||
};
|
||||
|
||||
//Reports API
|
||||
export const reportsApi = {
|
||||
// loadClientsByCreditProgram: () => getReport('path'),
|
||||
};
|
||||
124
TheBank/bankui/src/api/client.ts
Normal file
124
TheBank/bankui/src/api/client.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { ConfigManager } from '@/lib/config';
|
||||
import type { MailSendInfoBindingModel } from '@/types/types';
|
||||
const API_URL = ConfigManager.loadUrl();
|
||||
// Устанавливаем прямой URL к API серверу ASP.NET
|
||||
// const API_URL = 'https://localhost:7224'; // URL API сервера ASP.NET
|
||||
|
||||
export async function getData<T>(path: string): Promise<T[]> {
|
||||
const res = await fetch(`${API_URL}/${path}`, {
|
||||
credentials: 'include',
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не получается загрузить ${path}: ${res.statusText}`);
|
||||
}
|
||||
const data = (await res.json()) as T[];
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function postData<T>(path: string, data: T) {
|
||||
const res = await fetch(`${API_URL}/${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// mode: 'no-cors',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не получается загрузить ${path}: ${res.statusText}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSingleData<T>(path: string): Promise<T> {
|
||||
const res = await fetch(`${API_URL}/${path}`, {
|
||||
credentials: 'include',
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не получается загрузить ${path}: ${res.statusText}`);
|
||||
}
|
||||
const data = (await res.json()) as T;
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function postLoginData<T>(path: string, data: T): Promise<T> {
|
||||
const res = await fetch(`${API_URL}/${path}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не получается загрузить ${path}: ${await res.text()}`);
|
||||
}
|
||||
|
||||
const userData = (await res.json()) as T;
|
||||
return userData;
|
||||
}
|
||||
|
||||
export async function putData<T>(path: string, data: T) {
|
||||
const res = await fetch(`${API_URL}/${path}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не получается загрузить ${path}: ${res.statusText}`);
|
||||
}
|
||||
}
|
||||
|
||||
// report api
|
||||
export interface ReportParams {
|
||||
fromDate?: string; // Например, '2025-01-01'
|
||||
toDate?: string; // Например, '2025-05-21'
|
||||
}
|
||||
|
||||
export type ReportType =
|
||||
| 'depositByCreditProgram'
|
||||
| 'depositAndCreditProgramByCurrency';
|
||||
export type ReportFormat = 'word' | 'excel' | 'pdf';
|
||||
|
||||
export async function sendReportByEmail(
|
||||
reportType: ReportType,
|
||||
format: ReportFormat,
|
||||
mailInfo: MailSendInfoBindingModel,
|
||||
params?: ReportParams,
|
||||
): Promise<void> {
|
||||
const actionMap: Record<ReportType, Record<ReportFormat, string>> = {
|
||||
depositByCreditProgram: {
|
||||
word: 'SendReportDepositByCreditProgram',
|
||||
excel: 'SendExcelReportDepositByCreditProgram',
|
||||
pdf: 'SendReportDepositByCreditProgram',
|
||||
},
|
||||
depositAndCreditProgramByCurrency: {
|
||||
word: 'SendReportByCurrency',
|
||||
excel: 'SendReportByCurrency',
|
||||
pdf: 'SendReportByCurrency',
|
||||
},
|
||||
};
|
||||
|
||||
const action = actionMap[reportType][format];
|
||||
|
||||
// Формируем тело запроса
|
||||
const requestBody = { ...mailInfo, ...params };
|
||||
|
||||
const res = await fetch(`${API_URL}/api/Report/${action}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(requestBody),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(
|
||||
`Не удалось отправить отчет ${reportType} (${format}): ${res.statusText}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
162
TheBank/bankui/src/api/reports.ts
Normal file
162
TheBank/bankui/src/api/reports.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { ConfigManager } from '@/lib/config';
|
||||
import type {
|
||||
CreditProgramReportMailSendInfoBindingModel,
|
||||
DepositReportMailSendInfoBindingModel,
|
||||
} from '@/types/types';
|
||||
|
||||
const API_URL = ConfigManager.loadUrl();
|
||||
|
||||
export const reportsApi = {
|
||||
// PDF отчеты
|
||||
getPdfReport: async (fromDate: string, toDate: string) => {
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/Report/LoadDepositAndCreditProgramByCurrency?fromDate=${fromDate}&toDate=${toDate}`,
|
||||
{
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не удалось загрузить PDF отчет: ${res.statusText}`);
|
||||
}
|
||||
return res.blob();
|
||||
},
|
||||
|
||||
sendPdfReportByEmail: async (
|
||||
mailInfo: DepositReportMailSendInfoBindingModel,
|
||||
fromDate: string,
|
||||
toDate: string,
|
||||
) => {
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/Report/SendReportByCurrency?fromDate=${fromDate}&toDate=${toDate}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(mailInfo),
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не удалось отправить PDF отчет: ${res.statusText}`);
|
||||
}
|
||||
},
|
||||
|
||||
// Word отчеты
|
||||
getWordReport: async (creditProgramIds: string[]) => {
|
||||
const idsParam = creditProgramIds.reduce((prev, curr, index) => {
|
||||
return (prev += `${index === 0 ? '' : '&'}creditProgramIds=${curr}`);
|
||||
}, '');
|
||||
console.log('idsParam', idsParam);
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/Report/LoadDepositByCreditProgram?creditProgramIds=${idsParam}`,
|
||||
{
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не удалось загрузить Word отчет: ${res.statusText}`);
|
||||
}
|
||||
return res.blob();
|
||||
},
|
||||
|
||||
sendWordReportByEmail: async (
|
||||
mailInfo: CreditProgramReportMailSendInfoBindingModel,
|
||||
) => {
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/Report/SendReportDepositByCreditProgram`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(mailInfo),
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не удалось отправить Word отчет: ${res.statusText}`);
|
||||
}
|
||||
},
|
||||
|
||||
// Excel отчеты
|
||||
getExcelReport: async (creditProgramIds: string[]) => {
|
||||
const idsParam = creditProgramIds.reduce((prev, curr, index) => {
|
||||
return (prev += `${index === 0 ? '' : '&'}creditProgramIds=${curr}`);
|
||||
}, '');
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/Report/LoadExcelDepositByCreditProgram?${idsParam}`,
|
||||
{
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не удалось загрузить Excel отчет: ${res.statusText}`);
|
||||
}
|
||||
return res.blob();
|
||||
},
|
||||
|
||||
sendExcelReportByEmail: async (
|
||||
mailInfo: CreditProgramReportMailSendInfoBindingModel,
|
||||
) => {
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/Report/SendExcelReportDepositByCreditProgram`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(mailInfo),
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не удалось отправить Excel отчет: ${res.statusText}`);
|
||||
}
|
||||
},
|
||||
|
||||
// Получение данных для предпросмотра
|
||||
getReportData: async (creditProgramIds: string[]) => {
|
||||
const idsParam = creditProgramIds.join(',');
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/Report/GetDepositByCreditProgram?creditProgramIds=${idsParam}`,
|
||||
{
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Не удалось загрузить данные отчета: ${res.statusText}`);
|
||||
}
|
||||
return res.json();
|
||||
},
|
||||
|
||||
getReportDataByCurrency: async (fromDate: string, toDate: string) => {
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/Report/GetDepositAndCreditProgramByCurrency?fromDate=${fromDate}&toDate=${toDate}`,
|
||||
{
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(
|
||||
`Не удалось загрузить данные отчета по валюте: ${res.statusText}`,
|
||||
);
|
||||
}
|
||||
return res.json();
|
||||
},
|
||||
};
|
||||
1
TheBank/bankui/src/assets/react.svg
Normal file
1
TheBank/bankui/src/assets/react.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
281
TheBank/bankui/src/components/features/CreditProgramForm.tsx
Normal file
281
TheBank/bankui/src/components/features/CreditProgramForm.tsx
Normal file
@@ -0,0 +1,281 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import type { CreditProgramBindingModel } from '@/types/types';
|
||||
import { useAuthStore } from '@/store/workerStore';
|
||||
import { usePeriods } from '@/hooks/usePeriods';
|
||||
|
||||
type BaseFormValues = {
|
||||
id?: string;
|
||||
name: string;
|
||||
cost: number;
|
||||
maxCost: number;
|
||||
periodId: string;
|
||||
};
|
||||
|
||||
type EditFormValues = Partial<BaseFormValues>;
|
||||
|
||||
const baseSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().min(1, 'Название обязательно'),
|
||||
cost: z.coerce.number().min(0, 'Стоимость не может быть отрицательной'),
|
||||
maxCost: z.coerce
|
||||
.number()
|
||||
.min(0, 'Максимальная стоимость не может быть отрицательной'),
|
||||
periodId: z.string().min(1, 'Выберите период'),
|
||||
});
|
||||
|
||||
const addSchema = baseSchema;
|
||||
|
||||
const editSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().min(1, 'Название обязательно').optional(),
|
||||
cost: z.coerce
|
||||
.number()
|
||||
.min(0, 'Стоимость не может быть отрицательной')
|
||||
.optional(),
|
||||
maxCost: z.coerce
|
||||
.number()
|
||||
.min(0, 'Максимальная стоимость не может быть отрицательной')
|
||||
.optional(),
|
||||
periodId: z.string().min(1, 'Выберите период').optional(),
|
||||
});
|
||||
|
||||
interface BaseCreditProgramFormProps {
|
||||
onSubmit: (data: CreditProgramBindingModel) => void;
|
||||
schema: z.ZodType<BaseFormValues | EditFormValues>;
|
||||
defaultValues?: Partial<BaseFormValues>;
|
||||
}
|
||||
|
||||
const BaseCreditProgramForm = ({
|
||||
onSubmit,
|
||||
schema,
|
||||
defaultValues,
|
||||
}: BaseCreditProgramFormProps): React.JSX.Element => {
|
||||
const form = useForm<BaseFormValues | EditFormValues>({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: defaultValues
|
||||
? {
|
||||
id: defaultValues.id ?? '',
|
||||
name: defaultValues.name ?? '',
|
||||
cost: defaultValues.cost ?? 0,
|
||||
maxCost: defaultValues.maxCost ?? 0,
|
||||
periodId: defaultValues.periodId ?? '',
|
||||
}
|
||||
: {
|
||||
id: '',
|
||||
name: '',
|
||||
cost: 0,
|
||||
maxCost: 0,
|
||||
periodId: '',
|
||||
},
|
||||
});
|
||||
|
||||
const { periods } = usePeriods();
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultValues) {
|
||||
form.reset({
|
||||
id: defaultValues.id ?? '',
|
||||
name: defaultValues.name ?? '',
|
||||
cost: defaultValues.cost ?? 0,
|
||||
maxCost: defaultValues.maxCost ?? 0,
|
||||
periodId: defaultValues.periodId ?? '',
|
||||
});
|
||||
}
|
||||
}, [defaultValues, form]);
|
||||
|
||||
const storekeeper = useAuthStore((store) => store.user);
|
||||
|
||||
const handleSubmit = (data: BaseFormValues | EditFormValues) => {
|
||||
if (!storekeeper?.id) {
|
||||
console.error('Storekeeper ID is not available.');
|
||||
return;
|
||||
}
|
||||
|
||||
let payload: CreditProgramBindingModel;
|
||||
|
||||
if (schema === addSchema) {
|
||||
const addData = data as BaseFormValues;
|
||||
payload = {
|
||||
id: addData.id || crypto.randomUUID(),
|
||||
storekeeperId: storekeeper.id,
|
||||
name: addData.name,
|
||||
cost: addData.cost,
|
||||
maxCost: addData.maxCost,
|
||||
periodId: addData.periodId,
|
||||
};
|
||||
} else {
|
||||
const editData = data as EditFormValues;
|
||||
const currentDefaultValues = defaultValues as Partial<BaseFormValues>;
|
||||
|
||||
const changedData: Partial<CreditProgramBindingModel> = {};
|
||||
|
||||
if (editData.id !== undefined && editData.id !== currentDefaultValues?.id)
|
||||
changedData.id = editData.id;
|
||||
if (
|
||||
editData.name !== undefined &&
|
||||
editData.name !== currentDefaultValues?.name
|
||||
)
|
||||
changedData.name = editData.name;
|
||||
if (
|
||||
editData.cost !== undefined &&
|
||||
editData.cost !== currentDefaultValues?.cost
|
||||
)
|
||||
changedData.cost = editData.cost;
|
||||
if (
|
||||
editData.maxCost !== undefined &&
|
||||
editData.maxCost !== currentDefaultValues?.maxCost
|
||||
)
|
||||
changedData.maxCost = editData.maxCost;
|
||||
if (
|
||||
editData.periodId !== undefined &&
|
||||
editData.periodId !== currentDefaultValues?.periodId
|
||||
)
|
||||
changedData.periodId = editData.periodId;
|
||||
|
||||
if (currentDefaultValues?.id) changedData.id = currentDefaultValues.id;
|
||||
changedData.storekeeperId = storekeeper.id;
|
||||
|
||||
payload = {
|
||||
...(defaultValues as CreditProgramBindingModel),
|
||||
...changedData,
|
||||
};
|
||||
}
|
||||
|
||||
onSubmit(payload);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSubmit)}
|
||||
className="space-y-4 max-w-md mx-auto p-4"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="id"
|
||||
render={({ field }) => <input type="hidden" {...field} />}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Название</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Название" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cost"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Стоимость</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" placeholder="Стоимость" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="maxCost"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Максимальная стоимость</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Максимальная стоимость"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="periodId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Период</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value || ''}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Выберите период" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{periods &&
|
||||
periods?.map((period) => (
|
||||
<SelectItem key={period.id} value={period.id}>
|
||||
{`${new Date(
|
||||
period.startTime,
|
||||
).toLocaleDateString()} - ${new Date(
|
||||
period.endTime,
|
||||
).toLocaleDateString()}`}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
Сохранить
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export const CreditProgramFormAdd = ({
|
||||
onSubmit,
|
||||
}: {
|
||||
onSubmit: (data: CreditProgramBindingModel) => void;
|
||||
}): React.JSX.Element => {
|
||||
return <BaseCreditProgramForm onSubmit={onSubmit} schema={addSchema} />;
|
||||
};
|
||||
|
||||
export const CreditProgramFormEdit = ({
|
||||
onSubmit,
|
||||
defaultValues,
|
||||
}: {
|
||||
onSubmit: (data: CreditProgramBindingModel) => void;
|
||||
defaultValues: Partial<BaseFormValues>;
|
||||
}): React.JSX.Element => {
|
||||
return (
|
||||
<BaseCreditProgramForm
|
||||
onSubmit={onSubmit}
|
||||
schema={editSchema}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
);
|
||||
};
|
||||
180
TheBank/bankui/src/components/features/CurrencyForm.tsx
Normal file
180
TheBank/bankui/src/components/features/CurrencyForm.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import type { CurrencyBindingModel } from '@/types/types';
|
||||
import { useAuthStore } from '@/store/workerStore';
|
||||
|
||||
type BaseFormValues = {
|
||||
id?: string;
|
||||
name: string;
|
||||
abbreviation: string;
|
||||
cost: number;
|
||||
};
|
||||
|
||||
type EditFormValues = {
|
||||
id?: string;
|
||||
name?: string;
|
||||
abbreviation?: string;
|
||||
cost?: number;
|
||||
};
|
||||
|
||||
const baseSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string({ message: 'Введите название' }),
|
||||
abbreviation: z.string({ message: 'Введите аббревиатуру' }),
|
||||
cost: z.coerce.number({ message: 'Введите стоимость' }),
|
||||
});
|
||||
|
||||
const addSchema = baseSchema;
|
||||
|
||||
const editSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().min(1, 'Укажите название валюты').optional(),
|
||||
abbreviation: z.string().min(1, 'Укажите аббревиатуру').optional(),
|
||||
cost: z.coerce
|
||||
.number()
|
||||
.min(0, 'Стоимость не может быть отрицательной')
|
||||
.optional(),
|
||||
});
|
||||
|
||||
interface BaseCurrencyFormProps {
|
||||
onSubmit: (data: CurrencyBindingModel) => void;
|
||||
schema: z.ZodType<BaseFormValues | EditFormValues>;
|
||||
defaultValues?: Partial<BaseFormValues | EditFormValues>;
|
||||
}
|
||||
|
||||
const BaseCurrencyForm = ({
|
||||
onSubmit,
|
||||
schema,
|
||||
defaultValues,
|
||||
}: BaseCurrencyFormProps): React.JSX.Element => {
|
||||
const form = useForm<BaseFormValues | EditFormValues>({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: {
|
||||
id: defaultValues?.id || '',
|
||||
name: defaultValues?.name || '',
|
||||
abbreviation: defaultValues?.abbreviation || '',
|
||||
cost: defaultValues?.cost || 0,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultValues) {
|
||||
form.reset({
|
||||
id: defaultValues.id || '',
|
||||
name: defaultValues.name || '',
|
||||
abbreviation: defaultValues.abbreviation || '',
|
||||
cost: defaultValues.cost || 0,
|
||||
});
|
||||
}
|
||||
}, [defaultValues, form]);
|
||||
|
||||
const storekeeper = useAuthStore((store) => store.user);
|
||||
|
||||
const handleSubmit = (data: BaseFormValues | EditFormValues) => {
|
||||
const payload: CurrencyBindingModel = {
|
||||
id: data.id || crypto.randomUUID(),
|
||||
storekeeperId: storekeeper?.id,
|
||||
name: 'name' in data && data.name !== undefined ? data.name : '',
|
||||
abbreviation:
|
||||
'abbreviation' in data && data.abbreviation !== undefined
|
||||
? data.abbreviation
|
||||
: '',
|
||||
cost: 'cost' in data && data.cost !== undefined ? data.cost : 0,
|
||||
};
|
||||
|
||||
onSubmit(payload);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSubmit)}
|
||||
className="space-y-4 max-w-md mx-auto p-4"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="id"
|
||||
render={({ field }) => <input type="hidden" {...field} />}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Название</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Например, Доллар США" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="abbreviation"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Аббревиатура</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Например, USD" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cost"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Стоимость</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" placeholder="Например, 1.0" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" className="w-full">
|
||||
Сохранить
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export const CurrencyFormAdd = ({
|
||||
onSubmit,
|
||||
}: {
|
||||
onSubmit: (data: CurrencyBindingModel) => void;
|
||||
}): React.JSX.Element => {
|
||||
return <BaseCurrencyForm onSubmit={onSubmit} schema={addSchema} />;
|
||||
};
|
||||
|
||||
export const CurrencyFormEdit = ({
|
||||
onSubmit,
|
||||
defaultValues,
|
||||
}: {
|
||||
onSubmit: (data: CurrencyBindingModel) => void;
|
||||
defaultValues: Partial<BaseFormValues>;
|
||||
}): React.JSX.Element => {
|
||||
return (
|
||||
<BaseCurrencyForm
|
||||
onSubmit={onSubmit}
|
||||
schema={editSchema}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
);
|
||||
};
|
||||
82
TheBank/bankui/src/components/features/LoginForm.tsx
Normal file
82
TheBank/bankui/src/components/features/LoginForm.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import type { LoginBindingModel } from '@/types/types';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import React from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '../ui/form';
|
||||
import { Input } from '../ui/input';
|
||||
import { Button } from '../ui/button';
|
||||
|
||||
interface LoginFormProps {
|
||||
onSubmit: (data: LoginBindingModel) => void;
|
||||
defaultValues?: Partial<LoginBindingModel>;
|
||||
}
|
||||
const loginFormSchema = z.object({
|
||||
login: z.string().min(3, 'Логин должен быть не короче 3 символов'),
|
||||
password: z.string().min(6, 'Пароль должен быть не короче 6 символов'),
|
||||
});
|
||||
|
||||
type FormValues = z.infer<typeof loginFormSchema>;
|
||||
|
||||
export const LoginForm = ({
|
||||
onSubmit,
|
||||
defaultValues,
|
||||
}: LoginFormProps): React.JSX.Element => {
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(loginFormSchema),
|
||||
defaultValues: {
|
||||
login: defaultValues?.login || '',
|
||||
password: defaultValues?.password || '',
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = (data: FormValues) => {
|
||||
const payload: LoginBindingModel = {
|
||||
...data,
|
||||
};
|
||||
onSubmit(payload);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="login"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Логин</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Логин" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Пароль</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="Пароль" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" className="w-full">
|
||||
Войти
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
115
TheBank/bankui/src/components/features/PdfViewer.tsx
Normal file
115
TheBank/bankui/src/components/features/PdfViewer.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import React from 'react';
|
||||
import { Document, Page, pdfjs } from 'react-pdf';
|
||||
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
||||
import 'react-pdf/dist/esm/Page/TextLayer.css';
|
||||
import { Button } from '../ui/button';
|
||||
|
||||
// Настройка worker для PDF.js
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.worker.mjs`;
|
||||
|
||||
interface PdfViewerProps {
|
||||
report: { blob: Blob; fileName: string; mimeType: string } | undefined | null;
|
||||
}
|
||||
|
||||
export const PdfViewer = ({ report }: PdfViewerProps) => {
|
||||
const [numPages, setNumPages] = React.useState<number | null>(null);
|
||||
const [pageNumber, setPageNumber] = React.useState(1);
|
||||
const [pdfUrl, setPdfUrl] = React.useState<string | null>(null);
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (report?.blob) {
|
||||
const url = URL.createObjectURL(report.blob);
|
||||
setPdfUrl(url);
|
||||
setError(null);
|
||||
|
||||
return () => {
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
} else {
|
||||
setPdfUrl(null);
|
||||
setNumPages(null);
|
||||
setPageNumber(1);
|
||||
}
|
||||
}, [report]);
|
||||
|
||||
const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {
|
||||
setNumPages(numPages);
|
||||
setPageNumber(1);
|
||||
setError(null);
|
||||
};
|
||||
|
||||
const onDocumentLoadError = (error: Error) => {
|
||||
console.error('Ошибка загрузки PDF:', error);
|
||||
setError(
|
||||
'Ошибка при загрузке PDF документа. Пожалуйста, попробуйте снова.',
|
||||
);
|
||||
};
|
||||
|
||||
const handlePrevPage = () => {
|
||||
setPageNumber((prev) => Math.max(prev - 1, 1));
|
||||
};
|
||||
|
||||
const handleNextPage = () => {
|
||||
setPageNumber((prev) => Math.min(prev + 1, numPages || 1));
|
||||
};
|
||||
|
||||
if (!pdfUrl) {
|
||||
return (
|
||||
<div className="p-4 text-center">
|
||||
{report
|
||||
? 'Подготовка PDF для отображения...'
|
||||
: 'Нет данных для отображения PDF.'}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<Document
|
||||
file={pdfUrl}
|
||||
onLoadSuccess={onDocumentLoadSuccess}
|
||||
onLoadError={onDocumentLoadError}
|
||||
loading={<div className="text-center py-4">Загрузка PDF...</div>}
|
||||
error={
|
||||
<div className="text-center text-red-500 py-4">
|
||||
Не удалось загрузить PDF
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Page
|
||||
pageNumber={pageNumber}
|
||||
renderTextLayer={false}
|
||||
renderAnnotationLayer={false}
|
||||
scale={1.2}
|
||||
loading={<div className="text-center py-2">Загрузка страницы...</div>}
|
||||
error={
|
||||
<div className="text-center text-red-500 py-2">
|
||||
Ошибка загрузки страницы
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Document>
|
||||
|
||||
{error ? (
|
||||
<div className="text-red-500 py-2 text-center">{error}</div>
|
||||
) : numPages ? (
|
||||
<div className="flex justify-between items-center mt-4">
|
||||
<Button onClick={handlePrevPage} disabled={pageNumber <= 1}>
|
||||
Предыдущая
|
||||
</Button>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Страница {pageNumber} из {numPages}
|
||||
</p>
|
||||
<Button onClick={handleNextPage} disabled={pageNumber >= numPages}>
|
||||
Следующая
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-2 text-muted-foreground">
|
||||
Загрузка документа...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
235
TheBank/bankui/src/components/features/PeriodForm.tsx
Normal file
235
TheBank/bankui/src/components/features/PeriodForm.tsx
Normal file
@@ -0,0 +1,235 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import type { PeriodBindingModel } from '@/types/types';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { format } from 'date-fns';
|
||||
import { CalendarIcon } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import { useAuthStore } from '@/store/workerStore';
|
||||
|
||||
type BaseFormValues = {
|
||||
id?: string;
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
};
|
||||
|
||||
type EditFormValues = {
|
||||
id?: string;
|
||||
startTime?: Date;
|
||||
endTime?: Date;
|
||||
};
|
||||
|
||||
const baseSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
startTime: z.date({
|
||||
required_error: 'Укажите время начала',
|
||||
invalid_type_error: 'Неверный формат даты',
|
||||
}),
|
||||
endTime: z.date({
|
||||
required_error: 'Укажите время окончания',
|
||||
invalid_type_error: 'Неверный формат даты',
|
||||
}),
|
||||
});
|
||||
|
||||
const addSchema = baseSchema;
|
||||
|
||||
const editSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
startTime: z
|
||||
.date({
|
||||
required_error: 'Укажите время начала',
|
||||
invalid_type_error: 'Неверный формат даты',
|
||||
})
|
||||
.optional(),
|
||||
endTime: z
|
||||
.date({
|
||||
required_error: 'Укажите время окончания',
|
||||
invalid_type_error: 'Неверный формат даты',
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
|
||||
interface BasePeriodFormProps {
|
||||
onSubmit: (data: PeriodBindingModel) => void;
|
||||
schema: z.ZodType<BaseFormValues | EditFormValues>;
|
||||
defaultValues?: Partial<BaseFormValues | EditFormValues>;
|
||||
}
|
||||
|
||||
const BasePeriodForm = ({
|
||||
onSubmit,
|
||||
schema,
|
||||
defaultValues,
|
||||
}: BasePeriodFormProps): React.JSX.Element => {
|
||||
const form = useForm<BaseFormValues | EditFormValues>({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: {
|
||||
id: defaultValues?.id || '',
|
||||
startTime: defaultValues?.startTime || new Date(),
|
||||
endTime: defaultValues?.endTime || new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultValues) {
|
||||
form.reset({
|
||||
id: defaultValues.id || '',
|
||||
startTime: defaultValues.startTime || new Date(),
|
||||
endTime: defaultValues.endTime || new Date(),
|
||||
});
|
||||
}
|
||||
}, [defaultValues, form]);
|
||||
|
||||
const storekeeper = useAuthStore((store) => store.user);
|
||||
|
||||
const handleSubmit = (data: BaseFormValues | EditFormValues) => {
|
||||
const payload: PeriodBindingModel = {
|
||||
id: data.id || crypto.randomUUID(),
|
||||
storekeeperId: storekeeper?.id,
|
||||
startTime:
|
||||
'startTime' in data && data.startTime !== undefined
|
||||
? data.startTime
|
||||
: new Date(),
|
||||
endTime:
|
||||
'endTime' in data && data.endTime !== undefined
|
||||
? data.endTime
|
||||
: new Date(),
|
||||
};
|
||||
|
||||
onSubmit(payload);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSubmit)}
|
||||
className="space-y-4 max-w-md mx-auto p-4"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="id"
|
||||
render={({ field }) => <input type="hidden" {...field} />}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="startTime"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Время начала</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className={cn(
|
||||
'w-full pl-3 text-left font-normal',
|
||||
!field.value && 'text-muted-foreground',
|
||||
)}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, 'PPP')
|
||||
) : (
|
||||
<span>Выберите дату</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="endTime"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Время окончания</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
className={cn(
|
||||
'w-full pl-3 text-left font-normal',
|
||||
!field.value && 'text-muted-foreground',
|
||||
)}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, 'PPP')
|
||||
) : (
|
||||
<span>Выберите дату</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
Сохранить
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export const PeriodFormAdd = ({
|
||||
onSubmit,
|
||||
}: {
|
||||
onSubmit: (data: PeriodBindingModel) => void;
|
||||
}): React.JSX.Element => {
|
||||
return <BasePeriodForm onSubmit={onSubmit} schema={addSchema} />;
|
||||
};
|
||||
|
||||
export const PeriodFormEdit = ({
|
||||
onSubmit,
|
||||
defaultValues,
|
||||
}: {
|
||||
onSubmit: (data: PeriodBindingModel) => void;
|
||||
defaultValues: Partial<BaseFormValues>;
|
||||
}): React.JSX.Element => {
|
||||
return (
|
||||
<BasePeriodForm
|
||||
onSubmit={onSubmit}
|
||||
schema={editSchema}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
);
|
||||
};
|
||||
180
TheBank/bankui/src/components/features/ProfileForm.tsx
Normal file
180
TheBank/bankui/src/components/features/ProfileForm.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import type { StorekeeperBindingModel } from '@/types/types';
|
||||
|
||||
// Схема для редактирования профиля (все поля опциональны)
|
||||
const profileEditSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
surname: z.string().optional(),
|
||||
middleName: z.string().optional(),
|
||||
login: z.string().optional(),
|
||||
email: z.string().email('Неверный формат email').optional(),
|
||||
phoneNumber: z.string().optional(),
|
||||
// Пароль, вероятно, должен редактироваться отдельно, но добавим опционально
|
||||
password: z.string().optional(),
|
||||
});
|
||||
|
||||
type ProfileFormValues = z.infer<typeof profileEditSchema>;
|
||||
|
||||
interface ProfileFormProps {
|
||||
onSubmit: (data: Partial<StorekeeperBindingModel>) => void;
|
||||
defaultValues: ProfileFormValues;
|
||||
}
|
||||
|
||||
export const ProfileForm = ({
|
||||
onSubmit,
|
||||
defaultValues,
|
||||
}: ProfileFormProps): React.JSX.Element => {
|
||||
const form = useForm<ProfileFormValues>({
|
||||
resolver: zodResolver(profileEditSchema),
|
||||
defaultValues: defaultValues,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultValues) {
|
||||
form.reset(defaultValues);
|
||||
}
|
||||
}, [defaultValues, form]);
|
||||
|
||||
const handleSubmit = (data: ProfileFormValues) => {
|
||||
const changedData: ProfileFormValues = {};
|
||||
(Object.keys(data) as (keyof ProfileFormValues)[]).forEach((key) => {
|
||||
changedData[key] = data[key];
|
||||
if (data[key] !== defaultValues[key]) {
|
||||
changedData[key] = data[key];
|
||||
}
|
||||
});
|
||||
|
||||
if (defaultValues.id) {
|
||||
changedData.id = defaultValues.id;
|
||||
}
|
||||
|
||||
onSubmit(changedData);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSubmit)}
|
||||
className="space-y-4 max-w-md mx-auto p-4"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="id"
|
||||
render={({ field }) => <input type="hidden" {...field} />}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Имя</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Имя" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="surname"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Фамилия</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Фамилия" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="middleName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Отчество</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Отчество" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="login"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Логин</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Логин" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Email" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="phoneNumber"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Номер телефона</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Номер телефона" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{/* Поле пароля можно добавить здесь, если требуется его редактирование */}
|
||||
{/*
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Новый пароль (оставьте пустым, если не меняете)</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="Пароль" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
*/}
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
Сохранить изменения
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
166
TheBank/bankui/src/components/features/RegisterForm.tsx
Normal file
166
TheBank/bankui/src/components/features/RegisterForm.tsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import React from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import type { StorekeeperBindingModel } from '@/types/types';
|
||||
|
||||
interface RegisterFormProps {
|
||||
onSubmit: (data: StorekeeperBindingModel) => void;
|
||||
defaultValues?: Partial<StorekeeperBindingModel>;
|
||||
}
|
||||
|
||||
const registerFormSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
name: z.string().min(1, 'Имя обязательно'),
|
||||
surname: z.string().min(1, 'Фамилия обязательна'),
|
||||
middleName: z.string().min(1, 'Отчество обязательно'),
|
||||
login: z.string().min(3, 'Логин должен быть не короче 3 символов'),
|
||||
password: z.string().min(6, 'Пароль должен быть не короче 6 символов'),
|
||||
email: z.string().email('Введите корректный email'),
|
||||
phoneNumber: z.string().min(10, 'Введите корректный номер телефона'),
|
||||
});
|
||||
|
||||
type FormValues = z.infer<typeof registerFormSchema>;
|
||||
|
||||
export const RegisterForm = ({
|
||||
onSubmit,
|
||||
defaultValues,
|
||||
}: RegisterFormProps): React.JSX.Element => {
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(registerFormSchema),
|
||||
defaultValues: {
|
||||
id: defaultValues?.id || crypto.randomUUID(),
|
||||
name: defaultValues?.name || '',
|
||||
surname: defaultValues?.surname || '',
|
||||
middleName: defaultValues?.middleName || '',
|
||||
login: defaultValues?.login || '',
|
||||
password: defaultValues?.password || '',
|
||||
email: defaultValues?.email || '',
|
||||
phoneNumber: defaultValues?.phoneNumber || '',
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = (data: FormValues) => {
|
||||
const payload: StorekeeperBindingModel = {
|
||||
...data,
|
||||
id: data.id || crypto.randomUUID(),
|
||||
};
|
||||
onSubmit(payload);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="id"
|
||||
render={({ field }) => <input type="hidden" {...field} />}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Имя</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Имя" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="surname"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Фамилия</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Фамилия" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="middleName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Отчество</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Отчество" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="login"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Логин</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Логин" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Пароль</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="Пароль" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="email" placeholder="Email" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="phoneNumber"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Номер телефона</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Номер телефона" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit" className="w-full">
|
||||
Зарегистрировать
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
342
TheBank/bankui/src/components/features/ReportViewer.tsx
Normal file
342
TheBank/bankui/src/components/features/ReportViewer.tsx
Normal file
@@ -0,0 +1,342 @@
|
||||
import React from 'react';
|
||||
import { PdfViewer } from './PdfViewer';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { format } from 'date-fns';
|
||||
import { CalendarIcon, FileText, FileSpreadsheet } from 'lucide-react';
|
||||
import { ru } from 'date-fns/locale';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
import { useCreditPrograms } from '@/hooks/useCreditPrograms';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
|
||||
type ReportCategory = 'pdf' | 'word-excel' | null;
|
||||
type FileFormat = 'doc' | 'xls';
|
||||
|
||||
interface ReportViewerProps {
|
||||
selectedCategory: ReportCategory;
|
||||
onGeneratePdf: (fromDate: Date, toDate: Date) => void;
|
||||
onDownloadPdf: (fromDate: Date, toDate: Date) => void;
|
||||
onSendPdfEmail: (fromDate: Date, toDate: Date) => void;
|
||||
onDownloadWordExcel: (format: FileFormat, creditProgramIds: string[]) => void;
|
||||
onSendWordExcelEmail: (
|
||||
format: FileFormat,
|
||||
creditProgramIds: string[],
|
||||
) => void;
|
||||
pdfReport?: { blob: Blob; fileName: string; mimeType: string } | null;
|
||||
}
|
||||
|
||||
export const ReportViewer = ({
|
||||
selectedCategory,
|
||||
onGeneratePdf,
|
||||
onDownloadPdf,
|
||||
onSendPdfEmail,
|
||||
onDownloadWordExcel,
|
||||
onSendWordExcelEmail,
|
||||
pdfReport,
|
||||
}: ReportViewerProps): React.JSX.Element => {
|
||||
const { creditPrograms } = useCreditPrograms();
|
||||
|
||||
const [fromDate, setFromDate] = React.useState<Date>();
|
||||
const [toDate, setToDate] = React.useState<Date>();
|
||||
const [fileFormat, setFileFormat] = React.useState<FileFormat>('doc');
|
||||
const [selectedCreditProgramIds, setSelectedCreditProgramIds] =
|
||||
React.useState<string[]>([]);
|
||||
|
||||
const isPdfDatesValid = fromDate && toDate;
|
||||
const isWordExcelDataValid = selectedCreditProgramIds.length > 0;
|
||||
|
||||
const handleCreditProgramSelect = (creditProgramId: string) => {
|
||||
setSelectedCreditProgramIds((prev) => {
|
||||
if (prev.includes(creditProgramId)) {
|
||||
return prev.filter((id) => id !== creditProgramId);
|
||||
} else {
|
||||
return [...prev, creditProgramId];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const removeCreditProgram = (creditProgramId: string) => {
|
||||
setSelectedCreditProgramIds((prev) =>
|
||||
prev.filter((id) => id !== creditProgramId),
|
||||
);
|
||||
};
|
||||
|
||||
if (!selectedCategory) {
|
||||
return (
|
||||
<div className="flex-1 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-semibold mb-2">Выберите тип отчета</h2>
|
||||
<p className="text-muted-foreground">
|
||||
Выберите категорию отчета в боковой панели для начала работы
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (selectedCategory === 'pdf') {
|
||||
return (
|
||||
<div className="flex-1 flex flex-col">
|
||||
{/* Панель управления PDF */}
|
||||
<div className="border-b p-4 bg-background">
|
||||
<h2 className="text-xl font-semibold mb-4">
|
||||
PDF Отчет по валютам и периодам
|
||||
</h2>
|
||||
|
||||
{/* Выбор дат */}
|
||||
<div className="flex gap-4 mb-4">
|
||||
<div className="flex-1">
|
||||
<Label>Дата начала</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'w-full pl-3 text-left font-normal',
|
||||
!fromDate && 'text-muted-foreground',
|
||||
)}
|
||||
>
|
||||
{fromDate ? (
|
||||
format(fromDate, 'PPP', { locale: ru })
|
||||
) : (
|
||||
<span>Выберите дату</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={fromDate}
|
||||
onSelect={setFromDate}
|
||||
locale={ru}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<Label>Дата окончания</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'w-full pl-3 text-left font-normal',
|
||||
!toDate && 'text-muted-foreground',
|
||||
)}
|
||||
>
|
||||
{toDate ? (
|
||||
format(toDate, 'PPP', { locale: ru })
|
||||
) : (
|
||||
<span>Выберите дату</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={toDate}
|
||||
onSelect={setToDate}
|
||||
locale={ru}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Кнопки действий */}
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={() =>
|
||||
isPdfDatesValid && onGeneratePdf(fromDate!, toDate!)
|
||||
}
|
||||
disabled={!isPdfDatesValid}
|
||||
>
|
||||
Сгенерировать на странице
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>
|
||||
isPdfDatesValid && onDownloadPdf(fromDate!, toDate!)
|
||||
}
|
||||
disabled={!isPdfDatesValid}
|
||||
variant="outline"
|
||||
>
|
||||
Скачать
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>
|
||||
isPdfDatesValid && onSendPdfEmail(fromDate!, toDate!)
|
||||
}
|
||||
disabled={!isPdfDatesValid}
|
||||
variant="outline"
|
||||
>
|
||||
Отправить на почту
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Область просмотра PDF */}
|
||||
<div className="flex-1 overflow-auto">
|
||||
{pdfReport ? (
|
||||
<PdfViewer report={pdfReport} />
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<p className="text-muted-foreground">
|
||||
Выберите даты и нажмите "Сгенерировать на странице" для
|
||||
просмотра отчета
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (selectedCategory === 'word-excel') {
|
||||
return (
|
||||
<div className="flex-1 p-6">
|
||||
<h2 className="text-xl font-semibold mb-6">
|
||||
Word/Excel Отчет по кредитным программам
|
||||
</h2>
|
||||
|
||||
{/* Выбор формата файла */}
|
||||
<div className="mb-6">
|
||||
<Label className="text-base font-medium mb-3 block">
|
||||
Формат файла
|
||||
</Label>
|
||||
<RadioGroup
|
||||
value={fileFormat}
|
||||
onValueChange={(value) => setFileFormat(value as FileFormat)}
|
||||
className="flex gap-6"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="doc" id="doc" />
|
||||
<Label
|
||||
htmlFor="doc"
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<FileText className="h-4 w-4" />
|
||||
Microsoft Word
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="xls" id="xls" />
|
||||
<Label
|
||||
htmlFor="xls"
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<FileSpreadsheet className="h-4 w-4" />
|
||||
Microsoft Excel
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
{/* Выбор кредитных программ */}
|
||||
<div className="mb-6">
|
||||
<Label className="text-base font-medium mb-3 block">
|
||||
Кредитные программы
|
||||
</Label>
|
||||
<Select
|
||||
onValueChange={(value) => {
|
||||
if (!selectedCreditProgramIds.includes(value)) {
|
||||
handleCreditProgramSelect(value);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Выберите кредитные программы" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{creditPrograms?.map((program) => (
|
||||
<SelectItem
|
||||
key={program.id}
|
||||
value={program.id || ''}
|
||||
className={cn(
|
||||
selectedCreditProgramIds.includes(program.id || '') &&
|
||||
'bg-muted',
|
||||
)}
|
||||
>
|
||||
{program.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
{/* Отображение выбранных программ */}
|
||||
<div className="flex flex-wrap gap-2 mt-3">
|
||||
{selectedCreditProgramIds.map((programId) => {
|
||||
const program = creditPrograms?.find((p) => p.id === programId);
|
||||
return (
|
||||
<div
|
||||
key={programId}
|
||||
className="bg-muted px-3 py-1 rounded-md flex items-center gap-2"
|
||||
>
|
||||
<span>{program?.name || programId}</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-4 w-4 rounded-full"
|
||||
onClick={() => removeCreditProgram(programId)}
|
||||
>
|
||||
×
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Кнопки действий */}
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={() =>
|
||||
isWordExcelDataValid &&
|
||||
onDownloadWordExcel(fileFormat, selectedCreditProgramIds)
|
||||
}
|
||||
disabled={!isWordExcelDataValid}
|
||||
>
|
||||
Скачать
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>
|
||||
isWordExcelDataValid &&
|
||||
onSendWordExcelEmail(fileFormat, selectedCreditProgramIds)
|
||||
}
|
||||
disabled={!isWordExcelDataValid}
|
||||
variant="outline"
|
||||
>
|
||||
Отправить на почту
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{!isWordExcelDataValid && (
|
||||
<p className="text-sm text-muted-foreground mt-4">
|
||||
Выберите хотя бы одну кредитную программу для активации кнопок
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <div></div>;
|
||||
};
|
||||
86
TheBank/bankui/src/components/layout/DataTable.tsx
Normal file
86
TheBank/bankui/src/components/layout/DataTable.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '../ui/table';
|
||||
import { Checkbox } from '../ui/checkbox';
|
||||
|
||||
type DataTableProps<T> = {
|
||||
data: T[];
|
||||
columns: ColumnDef<T>[];
|
||||
selectedRow?: string;
|
||||
onRowSelected: (id: string | undefined) => void;
|
||||
};
|
||||
|
||||
export type ColumnDef<T> = {
|
||||
accessorKey: keyof T | string;
|
||||
header: string;
|
||||
renderCell?: (item: T) => React.ReactNode;
|
||||
};
|
||||
|
||||
export const DataTable = <T extends {}>({
|
||||
data,
|
||||
columns,
|
||||
selectedRow,
|
||||
onRowSelected,
|
||||
}: DataTableProps<T>): React.JSX.Element => {
|
||||
const handleRowSelect = (id: string) => {
|
||||
onRowSelected(selectedRow === id ? undefined : id);
|
||||
};
|
||||
return (
|
||||
<div className="rounded-md border">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[50px]"></TableHead>
|
||||
{columns.map((column) => (
|
||||
<TableHead key={column.accessorKey as string}>
|
||||
{column.header}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length + 1}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
Нет данных
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
data.map((item, index) => (
|
||||
<TableRow
|
||||
key={(item as any).id || index}
|
||||
data-state={
|
||||
selectedRow === (item as any).id ? 'selected' : undefined
|
||||
}
|
||||
>
|
||||
<TableCell>
|
||||
<Checkbox
|
||||
checked={selectedRow === (item as any).id}
|
||||
onCheckedChange={() => handleRowSelect((item as any).id)}
|
||||
aria-label="Select row"
|
||||
/>
|
||||
</TableCell>
|
||||
{columns.map((column) => (
|
||||
<TableCell key={column.accessorKey as string}>
|
||||
{column.renderCell
|
||||
? column.renderCell(item)
|
||||
: (item as any)[column.accessorKey] ?? 'N/A'}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
44
TheBank/bankui/src/components/layout/DialogForm.tsx
Normal file
44
TheBank/bankui/src/components/layout/DialogForm.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '../ui/dialog';
|
||||
|
||||
type DialogFormProps<T> = {
|
||||
children: React.ReactElement<{ onSubmit: (data: T) => void }>;
|
||||
title: string;
|
||||
description: string;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: (data: T) => void;
|
||||
};
|
||||
|
||||
export const DialogForm = <T,>({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
isOpen,
|
||||
onClose,
|
||||
onSubmit,
|
||||
}: DialogFormProps<T>): React.JSX.Element => {
|
||||
console.log(onSubmit);
|
||||
const wrappedSubmit = (data: T) => {
|
||||
onSubmit(data);
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogDescription>{description}</DialogDescription>
|
||||
</DialogHeader>
|
||||
{React.cloneElement(children, { onSubmit: wrappedSubmit })}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
9
TheBank/bankui/src/components/layout/Footer.tsx
Normal file
9
TheBank/bankui/src/components/layout/Footer.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
export const Footer = (): React.JSX.Element => {
|
||||
return (
|
||||
<footer className="w-full flex border-t border-black shadow-lg p-2">
|
||||
<div className="text-black">Банк "Вы банкрот" 2025</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
183
TheBank/bankui/src/components/layout/Header.tsx
Normal file
183
TheBank/bankui/src/components/layout/Header.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
Menubar,
|
||||
MenubarContent,
|
||||
MenubarItem,
|
||||
MenubarMenu,
|
||||
MenubarSeparator,
|
||||
MenubarTrigger,
|
||||
} from '../ui/menubar';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '../ui/dropdown-menu';
|
||||
import { Avatar, AvatarFallback } from '../ui/avatar';
|
||||
import { Button } from '../ui/button';
|
||||
import { useAuthStore } from '@/store/workerStore';
|
||||
|
||||
type NavOptionValue = {
|
||||
name: string;
|
||||
link: string;
|
||||
id: number;
|
||||
};
|
||||
|
||||
type NavOption = {
|
||||
name: string;
|
||||
options: NavOptionValue[];
|
||||
};
|
||||
|
||||
const navOptions = [
|
||||
{
|
||||
name: 'Валюты',
|
||||
options: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Просмотреть',
|
||||
link: '/currencies',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Кредитные программы',
|
||||
options: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Просмотреть',
|
||||
link: '/credit-programs',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Сроки',
|
||||
options: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Просмотреть',
|
||||
link: '/periods',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Кладовщики',
|
||||
options: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Просмотреть',
|
||||
link: '/storekeepers',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Вклады',
|
||||
options: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Управление валютами вкладов',
|
||||
link: '/deposit-currencies',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Отчеты',
|
||||
options: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Выгрузить отчеты',
|
||||
link: '/reports',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const Header = (): React.JSX.Element => {
|
||||
const user = useAuthStore((store) => store.user);
|
||||
const logout = useAuthStore((store) => store.logout);
|
||||
const { logout: serverLogout } = useAuthStore();
|
||||
const loggedOut = () => {
|
||||
serverLogout();
|
||||
logout();
|
||||
};
|
||||
const fullName = `${user?.name ?? ''} ${user?.surname ?? ''}`;
|
||||
return (
|
||||
<header className="flex w-full p-2 justify-between">
|
||||
<nav className="text-black">
|
||||
<Menubar className="flex gap-10">
|
||||
{navOptions.map((item) => (
|
||||
<MenuOption item={item} key={item.name} />
|
||||
))}
|
||||
</Menubar>
|
||||
</nav>
|
||||
<div>
|
||||
<ProfileIcon name={fullName || 'Евгений Эгов'} logout={loggedOut} />
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
const MenuOption = ({ item }: { item: NavOption }) => {
|
||||
return (
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger className="">{item.name}</MenubarTrigger>
|
||||
<MenubarContent className="">
|
||||
{item.options.map((x, i) => (
|
||||
<React.Fragment key={x.id}>
|
||||
{i == 1 && item.options.length > 1 && <MenubarSeparator />}
|
||||
<MenubarItem className="">
|
||||
<Link className="" to={x.link}>
|
||||
{x.name}
|
||||
</Link>
|
||||
</MenubarItem>
|
||||
</React.Fragment>
|
||||
))}
|
||||
<MenubarSeparator />
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
);
|
||||
};
|
||||
|
||||
type ProfileIconProps = {
|
||||
name: string;
|
||||
logout: () => void;
|
||||
};
|
||||
|
||||
export const ProfileIcon = ({
|
||||
name,
|
||||
logout,
|
||||
}: ProfileIconProps): React.JSX.Element => {
|
||||
return (
|
||||
<div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Avatar className="h-9 w-9">
|
||||
<AvatarFallback>{name[0]}</AvatarFallback>
|
||||
</Avatar>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56">
|
||||
<DropdownMenuItem className="font-bold text-lg">
|
||||
{name}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem asChild>
|
||||
<Link to="/profile" className="block w-full text-left">
|
||||
Профиль
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem asChild>
|
||||
<Button
|
||||
onClick={logout}
|
||||
variant="outline"
|
||||
className="block w-full text-left"
|
||||
>
|
||||
Выйти
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
64
TheBank/bankui/src/components/layout/ReportSidebar.tsx
Normal file
64
TheBank/bankui/src/components/layout/ReportSidebar.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { FileText, FileSpreadsheet } from 'lucide-react';
|
||||
|
||||
type ReportCategory = 'pdf' | 'word-excel' | null;
|
||||
|
||||
interface ReportSidebarProps {
|
||||
selectedCategory: ReportCategory;
|
||||
onCategoryChange: (category: ReportCategory) => void;
|
||||
}
|
||||
|
||||
export const ReportSidebar = ({
|
||||
selectedCategory,
|
||||
onCategoryChange,
|
||||
}: ReportSidebarProps): React.JSX.Element => {
|
||||
return (
|
||||
<div className="w-80 border-r bg-background">
|
||||
<div className="space-y-4 p-4">
|
||||
<div>
|
||||
<h3 className="mb-4 text-lg font-medium">Категории отчетов</h3>
|
||||
<RadioGroup
|
||||
value={selectedCategory || ''}
|
||||
onValueChange={(value) => onCategoryChange(value as ReportCategory)}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="pdf" id="pdf" />
|
||||
<Label
|
||||
htmlFor="pdf"
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<FileText className="h-4 w-4" />
|
||||
PDF отчет по валютам и периодам
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="word-excel" id="word-excel" />
|
||||
<Label
|
||||
htmlFor="word-excel"
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<FileSpreadsheet className="h-4 w-4" />
|
||||
Word/Excel отчет по кредитным программам
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
{selectedCategory && (
|
||||
<div className="pt-4 border-t">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => onCategoryChange(null)}
|
||||
className="w-full"
|
||||
>
|
||||
Сбросить выбор
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
64
TheBank/bankui/src/components/layout/Sidebar.tsx
Normal file
64
TheBank/bankui/src/components/layout/Sidebar.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroupContent,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarProvider,
|
||||
SidebarTrigger,
|
||||
} from '@/components/ui/sidebar';
|
||||
|
||||
import { Plus, Pencil } from 'lucide-react';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
type SidebarProps = {
|
||||
onAddClick: () => void;
|
||||
onEditClick: () => void;
|
||||
};
|
||||
|
||||
const availableTasks = [
|
||||
{
|
||||
name: 'Добавить',
|
||||
link: '',
|
||||
},
|
||||
{
|
||||
name: 'Редактировать',
|
||||
link: '',
|
||||
},
|
||||
];
|
||||
|
||||
export const AppSidebar = ({
|
||||
onAddClick,
|
||||
onEditClick,
|
||||
}: SidebarProps): React.JSX.Element => {
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Sidebar variant="floating" collapsible="icon">
|
||||
<SidebarTrigger />
|
||||
<SidebarContent />
|
||||
<SidebarGroupContent className="">
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton asChild onClick={onAddClick}>
|
||||
<Link to={availableTasks[0].link}>
|
||||
<Plus />
|
||||
<span>{availableTasks[0].name}</span>
|
||||
</Link>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton asChild onClick={onEditClick}>
|
||||
<Link to={availableTasks[1].link}>
|
||||
<Pencil />
|
||||
<span>{availableTasks[1].name}</span>
|
||||
</Link>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</Sidebar>
|
||||
</SidebarProvider>
|
||||
);
|
||||
};
|
||||
76
TheBank/bankui/src/components/pages/AuthStorekeeper.tsx
Normal file
76
TheBank/bankui/src/components/pages/AuthStorekeeper.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import { useStorekeepers } from '@/hooks/useStorekeepers';
|
||||
import React from 'react';
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../ui/tabs';
|
||||
import { RegisterForm } from '../features/RegisterForm';
|
||||
import { LoginForm } from '../features/LoginForm';
|
||||
import { toast } from 'sonner';
|
||||
import type { LoginBindingModel, StorekeeperBindingModel } from '@/types/types';
|
||||
|
||||
type Forms = 'login' | 'register';
|
||||
|
||||
export const AuthStorekeeper = (): React.JSX.Element => {
|
||||
const {
|
||||
createStorekeeper,
|
||||
loginStorekeeper,
|
||||
isLoginError,
|
||||
loginError,
|
||||
isCreateError,
|
||||
} = useStorekeepers();
|
||||
|
||||
const [currentForm, setCurrentForm] = React.useState<Forms>('login');
|
||||
|
||||
const handleRegister = (data: StorekeeperBindingModel) => {
|
||||
createStorekeeper(data, {
|
||||
onSuccess: () => {
|
||||
toast('Регистрация успешна! Войдите в систему.');
|
||||
},
|
||||
onError: (error) => {
|
||||
toast(`Ошибка регистрации: ${error.message}`);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleLogin = (data: LoginBindingModel) => {
|
||||
loginStorekeeper(data);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isLoginError) {
|
||||
toast(`Ошибка входа: ${loginError?.message}`);
|
||||
}
|
||||
if (isCreateError) {
|
||||
toast('Ошибка при регистрации');
|
||||
}
|
||||
}, [isLoginError, loginError, isCreateError]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="flex flex-col justify-center items-center">
|
||||
<div>
|
||||
<Tabs defaultValue="login" className="w-[400px]">
|
||||
<TabsList>
|
||||
<TabsTrigger
|
||||
onClick={() => setCurrentForm('login')}
|
||||
value="login"
|
||||
>
|
||||
Вход
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
onClick={() => setCurrentForm('register')}
|
||||
value="register"
|
||||
>
|
||||
Регистрация
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value={currentForm}>
|
||||
<LoginForm onSubmit={handleLogin} />
|
||||
</TabsContent>
|
||||
<TabsContent value="register">
|
||||
<RegisterForm onSubmit={handleRegister} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
};
|
||||
183
TheBank/bankui/src/components/pages/CreditPrograms.tsx
Normal file
183
TheBank/bankui/src/components/pages/CreditPrograms.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import React from 'react';
|
||||
import { AppSidebar } from '../layout/Sidebar';
|
||||
import { useCreditPrograms } from '@/hooks/useCreditPrograms';
|
||||
import { DialogForm } from '../layout/DialogForm';
|
||||
import { DataTable } from '../layout/DataTable';
|
||||
import {
|
||||
CreditProgramFormAdd,
|
||||
CreditProgramFormEdit,
|
||||
} from '../features/CreditProgramForm';
|
||||
import type { CreditProgramBindingModel } from '@/types/types';
|
||||
import type { ColumnDef } from '../layout/DataTable';
|
||||
import { toast } from 'sonner';
|
||||
import { usePeriods } from '@/hooks/usePeriods';
|
||||
import { useStorekeepers } from '@/hooks/useStorekeepers';
|
||||
|
||||
interface CreditProgramTableData extends CreditProgramBindingModel {
|
||||
formattedPeriod: string;
|
||||
storekeeperFullName: string;
|
||||
}
|
||||
|
||||
const columns: ColumnDef<CreditProgramTableData>[] = [
|
||||
{
|
||||
accessorKey: 'id',
|
||||
header: 'ID',
|
||||
},
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: 'Название',
|
||||
},
|
||||
{
|
||||
accessorKey: 'cost',
|
||||
header: 'Стоимость',
|
||||
},
|
||||
{
|
||||
accessorKey: 'maxCost',
|
||||
header: 'Макс. стоимость',
|
||||
},
|
||||
{
|
||||
accessorKey: 'storekeeperFullName',
|
||||
header: 'Кладовщик',
|
||||
},
|
||||
{
|
||||
accessorKey: 'formattedPeriod',
|
||||
header: 'Период',
|
||||
},
|
||||
];
|
||||
|
||||
export const CreditPrograms = (): React.JSX.Element => {
|
||||
const {
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
creditPrograms,
|
||||
createCreditProgram,
|
||||
updateCreditProgram,
|
||||
} = useCreditPrograms();
|
||||
const { periods } = usePeriods();
|
||||
const { storekeepers } = useStorekeepers();
|
||||
|
||||
const finalData = React.useMemo(() => {
|
||||
if (!creditPrograms || !periods || !storekeepers) return [];
|
||||
|
||||
return creditPrograms.map((program) => {
|
||||
const period = periods?.find((p) => p.id === program.periodId);
|
||||
const storekeeper = storekeepers?.find(
|
||||
(s) => s.id === program.storekeeperId,
|
||||
);
|
||||
|
||||
const formattedPeriod = period
|
||||
? `${new Date(period.startTime).toLocaleDateString()} - ${new Date(
|
||||
period.endTime,
|
||||
).toLocaleDateString()}`
|
||||
: 'Неизвестный период';
|
||||
|
||||
const storekeeperFullName = storekeeper
|
||||
? [storekeeper.surname, storekeeper.name, storekeeper.middleName]
|
||||
.filter(Boolean)
|
||||
.join(' ') || 'Неизвестный кладовщик'
|
||||
: 'Неизвестный кладовщик';
|
||||
|
||||
return {
|
||||
...program,
|
||||
formattedPeriod,
|
||||
storekeeperFullName,
|
||||
};
|
||||
});
|
||||
}, [creditPrograms, periods, storekeepers]);
|
||||
|
||||
const [isAddDialogOpen, setIsAddDialogOpen] = React.useState<boolean>(false);
|
||||
const [isEditDialogOpen, setIsEditDialogOpen] =
|
||||
React.useState<boolean>(false);
|
||||
const [selectedItem, setSelectedItem] = React.useState<
|
||||
CreditProgramBindingModel | undefined
|
||||
>();
|
||||
|
||||
const handleAdd = (data: CreditProgramBindingModel) => {
|
||||
console.log('add', data);
|
||||
createCreditProgram(data);
|
||||
setIsAddDialogOpen(false);
|
||||
};
|
||||
|
||||
const handleEdit = (data: CreditProgramBindingModel) => {
|
||||
if (selectedItem) {
|
||||
updateCreditProgram({
|
||||
...selectedItem,
|
||||
...data,
|
||||
});
|
||||
console.log('edit', data);
|
||||
setIsEditDialogOpen(false);
|
||||
setSelectedItem(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectItem = (id: string | undefined) => {
|
||||
const item = creditPrograms?.find((cp) => cp.id === id);
|
||||
setSelectedItem(item);
|
||||
};
|
||||
|
||||
const openEditForm = () => {
|
||||
if (!selectedItem) {
|
||||
toast.error('Выберите элемент для редактирования');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsEditDialogOpen(true);
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <main className="container mx-auto py-10">Загрузка...</main>;
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<main className="container mx-auto py-10">
|
||||
Ошибка загрузки: {error?.message}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex-1 flex relative">
|
||||
<AppSidebar
|
||||
onAddClick={() => {
|
||||
setIsAddDialogOpen(true);
|
||||
}}
|
||||
onEditClick={() => {
|
||||
openEditForm();
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex-1 p-4">
|
||||
<DialogForm<CreditProgramBindingModel>
|
||||
title="Форма кредитной программы"
|
||||
description="Добавить новую кредитную программу"
|
||||
isOpen={isAddDialogOpen}
|
||||
onClose={() => setIsAddDialogOpen(false)}
|
||||
onSubmit={handleAdd}
|
||||
>
|
||||
<CreditProgramFormAdd />
|
||||
</DialogForm>
|
||||
{selectedItem && (
|
||||
<DialogForm<CreditProgramBindingModel>
|
||||
title="Форма кредитной программы"
|
||||
description="Изменить кредитную программу"
|
||||
isOpen={isEditDialogOpen}
|
||||
onClose={() => setIsEditDialogOpen(false)}
|
||||
onSubmit={handleEdit}
|
||||
>
|
||||
<CreditProgramFormEdit defaultValues={selectedItem} />
|
||||
</DialogForm>
|
||||
)}
|
||||
<div className="">
|
||||
<DataTable
|
||||
data={finalData}
|
||||
columns={columns}
|
||||
onRowSelected={(id) => handleSelectItem(id)}
|
||||
selectedRow={selectedItem?.id}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user