feat : create store and repository and interface

This commit is contained in:
2025-11-23 18:25:59 +03:30
parent 41aaef9889
commit 5774d9e204
21 changed files with 601 additions and 1 deletions
@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Application.Aggregates.Stores.ViewModels;
using Domain.Aggregates.Stores;
using Domain.Aggregates.Stores.Data;
using Mapster;
using Resources.Messages;
namespace Application.Aggregates.Stores;
public class StoresApplication(IStoreRepository storeRepository)
{
public async Task<StoreViewModel> CreateAsync(CreateStoreViewModel storeViewModel)
{
var store = Store.Create(
name: storeViewModel.Name,
address: storeViewModel.Address,
mobile: storeViewModel.Mobile,
score: storeViewModel.Score);
if (storeViewModel.IsActive == true)
{
store.Activate();
}
await storeRepository.AddAsync(store);
await storeRepository.SaveChangesAsync();
return store.Adapt<StoreViewModel>();
}
public async Task<List<StoreViewModel>> GetStors()
{
var store =
await storeRepository.GetAllAsync();
return store.Adapt<List<StoreViewModel>>();
}
public async Task<StoreViewModel> GetAsync(Guid storeId)
{
var store =
await storeRepository.GetAsync(storeId);
return store.Adapt<StoreViewModel>();
}
public async Task<StoreViewModel> UpdateAsync(UpdateStoreViewModel updateStoreViewModel)
{
var update =
await storeRepository.GetAsync(updateStoreViewModel.Id);
if (update == null || updateStoreViewModel.Id == Guid.Empty)
{
var error =
string.Format(Errors.NotFound, Resources.DataDictionary.Store);
throw new Exception(error);
}
update.Update(
name: updateStoreViewModel.Name,
address: updateStoreViewModel.Address,
mobile: updateStoreViewModel.Mobile,
score: updateStoreViewModel.Score);
if (update.IsActive == true)
{
update.Activate();
}
else
{
update.Deactivate();
}
await storeRepository.SaveChangesAsync();
return update.Adapt<StoreViewModel>();
}
public async Task DeleteAsync(Guid storeId)
{
var delete =
await storeRepository.GetAsync(storeId);
if (delete == null || delete.Id == Guid.Empty)
{
var error =
string.Format(Errors.NotFound, Resources.DataDictionary.Store);
throw new Exception(error);
}
storeRepository.Remove(delete);
await storeRepository.SaveChangesAsync();
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Application.Aggregates.Stores.ViewModels;
public class CreateStoreViewModel
{
public CreateStoreViewModel()
{
}
public string Name { get; set; }
public string Address { get; set; }
public string Mobile { get; set; }
public int Score { get; set; }
public bool IsActive { get; set; }
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Application.Aggregates.Stores.ViewModels;
public class StoreViewModel : UpdateStoreViewModel
{
public StoreViewModel()
{
}
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Application.Aggregates.Stores.ViewModels;
public class UpdateStoreViewModel : CreateStoreViewModel
{
public UpdateStoreViewModel()
{
}
public Guid Id { get; set; }
}
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Domain.Aggregates.Stores.Data;
public interface IStoreRepository
{
Task AddAsync(Store store);
Task<List<Store>> GetAllAsync();
Task<Store?> GetAsync(Guid storeId);
void Remove(Store store);
Task SaveChangesAsync();
}
@@ -0,0 +1,69 @@
using Domain.SeedWork;
using Framework.DataType;
using Resources.Messages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Domain.Aggregates.Stores;
public class Store : Entity
{
public Store()
{
////**********
}
private Store(string name, string address, string mobile, int score)
{
Name = name;
Address = address;
Mobile = mobile;
Score = score;
}
public string Name { get; private set; }
public string Address { get; private set; }
public string Mobile { get; private set; }
public int Score { get; private set; }
public static Store Create(string name, string address, string mobile, int score)
{
if (!mobile.IsValidMobile())
{
var error =
string.Format(Errors.Invalid, Resources.DataDictionary.CellPhonenumber);
throw new InvalidDataException(error);
}
var store = new Store(
name: name.Fix() ?? "",
address: address.Fix() ?? "",
mobile: mobile,
score: score);
return store;
}
public void Update(string name, string address, string mobile, int score)
{
if (!mobile.IsValidMobile())
{
var error =
string.Format(Errors.Invalid, Resources.DataDictionary.CellPhonenumber);
throw new InvalidDataException(error);
}
Name = name.Fix() ?? "";
Address = address.Fix() ?? "";
Mobile = mobile;
Score = score;
SetUpdateDateTime();
}
}
+9
View File
@@ -1194,6 +1194,15 @@ namespace Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Score.
/// </summary>
public static string Score {
get {
return ResourceManager.GetString("Score", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Searching.
/// </summary>
@@ -612,4 +612,7 @@
<data name="Invoicenumber" xml:space="preserve">
<value>شماره فاکتور</value>
</data>
<data name="Score" xml:space="preserve">
<value>امتیاز</value>
</data>
</root>
+3
View File
@@ -612,4 +612,7 @@
<data name="Invoicenumber" xml:space="preserve">
<value>Invoicenumber</value>
</data>
<data name="Score" xml:space="preserve">
<value>Score</value>
</data>
</root>
@@ -1,4 +1,5 @@
using Domain.Aggregates.Users;
using Domain.Aggregates.Stores;
using Domain.Aggregates.Users;
using Microsoft.EntityFrameworkCore;
namespace Persistence;
@@ -12,5 +13,6 @@ public class DatabaseContext: DbContext
public DbSet<User> Users { get; set; }
public DbSet<Store> Stores { get; set; }
}
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Domain.Aggregates.Stores;
using Domain.Aggregates.Stores.Data;
using Microsoft.EntityFrameworkCore;
namespace Persistence.Repositories.Aggregates.Stores;
public class StoreRepository(DatabaseContext databaseContext) : IStoreRepository
{
public async Task AddAsync(Store store)
{
await databaseContext.AddAsync(store);
}
public async Task<List<Store>> GetAllAsync()
{
var store =
await databaseContext.Stores
.Where(x => x.IsDeleted == false)
.ToListAsync();
return store;
}
public async Task<Store?> GetAsync(Guid storeId)
{
var store =
await databaseContext.Stores
.Where(x => x.IsDeleted == false)
.Where(x => x.Id == storeId)
.FirstOrDefaultAsync();
return store;
}
public void Remove(Store store)
{
store.Delete();
}
public async Task SaveChangesAsync()
{
await databaseContext.SaveChangesAsync();
}
}
@@ -7,4 +7,5 @@
<div class="text-center d-flex flex-column w-25">
<h2 class="text-start">Pages</h2>
<a class="btn btn-secondary my-2" asp-page="Panel/Users/Index">[ Users ]</a>
<a class="btn btn-secondary my-2" asp-page="Panel/Stores/Index">[ Stores ]</a>
</div>
@@ -0,0 +1,42 @@
@page
@model Server.Pages.Panel.Stores.CreateModel
@{
var pageTitle =
$"{Resources.DataDictionary.CreateOf} {Resources.DataDictionary.Store}";
ViewData[Constants.ViewDataKeyName.PageTitle] = pageTitle;
}
<form method="post">
<section-form>
<fieldset>
<section-form-header>
@(pageTitle)
</section-form-header>
<partial name="PartialViews/_DisplayPageMessages" />
<ub-full-input asp-for="CreateViewModel.Name" />
<ub-full-input asp-for="CreateViewModel.Address" />
<ub-full-input asp-for="CreateViewModel.Mobile" />
<ub-full-input asp-for="CreateViewModel.Score" />
<ub-full-checkbox asp-for="CreateViewModel.IsActive" />
</fieldset>
<section-form-buttons>
<button-create />
<button-reset />
</section-form-buttons>
</section-form>
</form>
@@ -0,0 +1,29 @@
using Application.Aggregates.Stores;
using Application.Aggregates.Stores.ViewModels;
using Application.Aggregates.Users.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Server.Pages.Panel.Stores;
public class CreateModel(StoresApplication storesApplication) : PageModel
{
[BindProperty]
public CreateStoreViewModel CreateViewModel { get; set; } = new();
public void OnGet()
{
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
await storesApplication.CreateAsync(CreateViewModel);
return RedirectToPage("Index");
}
}
@@ -0,0 +1,43 @@
@page
@model Server.Pages.Panel.Stores.DeleteModel
@{
var pageTitle =
$"{Resources.DataDictionary.DeleteOf} {Resources.DataDictionary.Store}";
ViewData[Constants.ViewDataKeyName.PageTitle] = pageTitle;
}
<form method="post">
<section-form>
<input hidden asp-for="DeleteViewModel.Id" dir="ltr" />
<fieldset disabled>
<section-form-header>
@(pageTitle)
</section-form-header>
<partial name="PartialViews/_DisplayPageMessages" />
<ub-full-input asp-for="DeleteViewModel.Name" />
<ub-full-input asp-for="DeleteViewModel.Address" />
<ub-full-input asp-for="DeleteViewModel.Mobile" />
<ub-full-input asp-for="DeleteViewModel.Score" />
<ub-full-checkbox asp-for="DeleteViewModel.IsActive" />
</fieldset>
<section-form-buttons>
<button-delete />
</section-form-buttons>
</section-form>
</form>
@@ -0,0 +1,38 @@
using Application.Aggregates.Stores;
using Application.Aggregates.Stores.ViewModels;
using Application.Aggregates.Users;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Server.Pages.Panel.Stores;
public class DeleteModel(StoresApplication storesApplication) : PageModel
{
[BindProperty]
public StoreViewModel DeleteViewModel { get; set; } = new();
public async Task<IActionResult> OnGetAsync(Guid id)
{
if (id == Guid.Empty)
{
return RedirectToPage("Index");
}
DeleteViewModel =
await storesApplication.GetAsync(id);
if (DeleteViewModel == null)
{
return RedirectToPage("Index");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
await storesApplication.DeleteAsync(DeleteViewModel.Id);
return RedirectToPage("Index");
}
}
@@ -0,0 +1,38 @@
@page
@model Server.Pages.Panel.Stores.IndexModel
@{
}
<div class="my-2 float-end">
<a class="btn btn-primary" asp-page="Create">@(Resources.ButtonCaptions.Create)</a>
</div>
<table class="table table-hover">
<thead>
<tr>
@(Html.Ub_DisplayStringWithTh(Resources.DataDictionary.Name))
@(Html.Ub_DisplayStringWithTh(Resources.DataDictionary.Address))
@(Html.Ub_DisplayStringWithTh(Resources.DataDictionary.Mobile))
@(Html.Ub_DisplayStringWithTh(Resources.DataDictionary.Score))
@(Html.Ub_DisplayStringWithTh(Resources.DataDictionary.IsActive))
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.store)
{
<tr>
@(Html.Ub_DisplayStringWithTd(item.Name))
@(Html.Ub_DisplayStringWithTd(item.Address))
@(Html.Ub_DisplayStringWithTd(item.Mobile))
@(Html.Ub_DisplayInteger(item.Score))
@(Html.Ub_DisplayBooleanWithTd(item.IsActive))
<td>
<div class="btn-group" role="group" aria-label="Basic example">
<a asp-page="Update" asp-route-Id="@(item.Id)" class="btn btn-warning">@(Resources.ButtonCaptions.Edit)</a>
<a asp-page="Delete" asp-route-Id="@(item.Id)" class="btn btn-danger">@(Resources.ButtonCaptions.Delete)</a>
</div>
</td>
</tr>
}
</tbody>
</table>
@@ -0,0 +1,16 @@
using Application.Aggregates.Stores;
using Application.Aggregates.Stores.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Server.Pages.Panel.Stores;
public class IndexModel(StoresApplication storesApplication) : PageModel
{
public List<StoreViewModel> store { get; set; } = new();
public async Task OnGetAsync()
{
store = await storesApplication.GetStors();
}
}
@@ -0,0 +1,43 @@
@page
@model Server.Pages.Panel.Stores.UpdateModel
@{
var pageTitle =
$"{Resources.DataDictionary.UpdateOf} {Resources.DataDictionary.Store}";
ViewData[Constants.ViewDataKeyName.PageTitle] = pageTitle;
}
<form method="post">
<section-form>
<fieldset>
<section-form-header>
@(pageTitle)
</section-form-header>
<partial name="PartialViews/_DisplayPageMessages" />
<input hidden asp-for="UpdateViewModel.Id" />
<ub-full-input asp-for="UpdateViewModel.Name" />
<ub-full-input asp-for="UpdateViewModel.Address" />
<ub-full-input asp-for="UpdateViewModel.Mobile" />
<ub-full-input asp-for="UpdateViewModel.Score" />
<ub-full-checkbox asp-for="UpdateViewModel.IsActive" />
</fieldset>
<section-form-buttons>
<button-save />
<button-reset />
</section-form-buttons>
</section-form>
</form>
@@ -0,0 +1,40 @@
using Application.Aggregates.Stores;
using Application.Aggregates.Stores.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Server.Pages.Panel.Stores;
public class UpdateModel(StoresApplication storesApplication) : PageModel
{
[BindProperty]
public StoreViewModel UpdateViewModel { get; set; }
public async Task<IActionResult> OnGetAsync(Guid id)
{
if(id==Guid.Empty)
{
return RedirectToPage("Index");
}
UpdateViewModel=
await storesApplication.GetAsync(id);
if(UpdateViewModel==null)
{
return RedirectToPage("Index");
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
if(ModelState.IsValid)
{
await storesApplication.UpdateAsync(UpdateViewModel);
}
return RedirectToPage("Index");
}
}
+6
View File
@@ -1,7 +1,10 @@
using Application.Aggregates.Stores;
using Application.Aggregates.Users;
using Domain.Aggregates.Stores.Data;
using Domain.Aggregates.Users.Data;
using Microsoft.EntityFrameworkCore;
using Persistence;
using Persistence.Repositories.Aggregates.Stores;
using Persistence.Repositories.Aggregates.Users;
using Server.Infrastructure.Extensions.ServiceCollections;
@@ -28,6 +31,9 @@ public class Program
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<UsersApplication>();
builder.Services.AddScoped<IStoreRepository, StoreRepository>();
builder.Services.AddScoped<StoresApplication>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())