Browse Source

SP_10062024_CodePush

main
Soumen Pal 7 months ago
parent
commit
c6725c0c01
104 changed files with 22619 additions and 561 deletions
  1. +3
    -5
      angular/angular.json
  2. +0
    -1
      angular/package.json
  3. +3
    -0
      angular/src/app/app-routing.module.ts
  4. +1
    -8
      angular/src/app/app.module.ts
  5. +12
    -0
      angular/src/app/book-issue/book-issue-routing.module.ts
  6. +97
    -0
      angular/src/app/book-issue/book-issue.component.html
  7. +0
    -0
      angular/src/app/book-issue/book-issue.component.scss
  8. +23
    -0
      angular/src/app/book-issue/book-issue.component.spec.ts
  9. +83
    -0
      angular/src/app/book-issue/book-issue.component.ts
  10. +19
    -0
      angular/src/app/book-issue/book-issue.module.ts
  11. +12
    -0
      angular/src/app/book/book-routing.module.ts
  12. +122
    -0
      angular/src/app/book/book.component.html
  13. +0
    -0
      angular/src/app/book/book.component.scss
  14. +23
    -0
      angular/src/app/book/book.component.spec.ts
  15. +88
    -0
      angular/src/app/book/book.component.ts
  16. +21
    -0
      angular/src/app/book/book.module.ts
  17. +13
    -0
      angular/src/app/customer/customer-routing.module.ts
  18. +101
    -0
      angular/src/app/customer/customer.component.html
  19. +0
    -0
      angular/src/app/customer/customer.component.scss
  20. +23
    -0
      angular/src/app/customer/customer.component.spec.ts
  21. +92
    -0
      angular/src/app/customer/customer.component.ts
  22. +20
    -0
      angular/src/app/customer/customer.module.ts
  23. +17
    -0
      angular/src/app/proxy/README.md
  24. +56
    -0
      angular/src/app/proxy/authors/author.service.ts
  25. +2
    -0
      angular/src/app/proxy/authors/index.ts
  26. +23
    -0
      angular/src/app/proxy/authors/models.ts
  27. +55
    -0
      angular/src/app/proxy/book-issued/book-issue.service.ts
  28. +2
    -0
      angular/src/app/proxy/book-issued/index.ts
  29. +13
    -0
      angular/src/app/proxy/book-issued/models.ts
  30. +15
    -0
      angular/src/app/proxy/books/book-type.enum.ts
  31. +64
    -0
      angular/src/app/proxy/books/book.service.ts
  32. +3
    -0
      angular/src/app/proxy/books/index.ts
  33. +16
    -0
      angular/src/app/proxy/books/models.ts
  34. +63
    -0
      angular/src/app/proxy/customers/customer.service.ts
  35. +2
    -0
      angular/src/app/proxy/customers/index.ts
  36. +8
    -0
      angular/src/app/proxy/customers/models.ts
  37. +10619
    -0
      angular/src/app/proxy/generate-proxy.json
  38. +5
    -0
      angular/src/app/proxy/index.ts
  39. +34
    -0
      angular/src/app/route.provider.ts
  40. +2
    -2
      angular/src/environments/environment.prod.ts
  41. +2
    -2
      angular/src/environments/environment.ts
  42. +6
    -9
      angular/src/index.html
  43. +496
    -511
      angular/yarn.lock
  44. +2
    -2
      aspnet-core/README.md
  45. +1
    -1
      aspnet-core/src/Acme.BookStore.Application.Contracts/Acme.BookStore.Application.Contracts.csproj
  46. +44
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Authors/AuthorDto.cs
  47. +19
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Authors/IAuthorAppService.cs
  48. +25
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/BookIssued/BookIssueDto.cs
  49. +22
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/BookIssued/IBookIssueAppService.cs
  50. +18
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Books/BookDto.cs
  51. +24
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Books/CreateUpdateBookDto.cs
  52. +19
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Books/IBookAppService.cs
  53. +20
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Customers/CustomerDto.cs
  54. +24
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Customers/ICustomerAppService.cs
  55. +34
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Permissions/BookStorePermissionDefinitionProvider.cs
  56. +29
    -0
      aspnet-core/src/Acme.BookStore.Application.Contracts/Permissions/BookStorePermissions.cs
  57. +1
    -1
      aspnet-core/src/Acme.BookStore.Application/Acme.BookStore.Application.csproj
  58. +95
    -0
      aspnet-core/src/Acme.BookStore.Application/Authors/AuthorAppService.cs
  59. +73
    -0
      aspnet-core/src/Acme.BookStore.Application/BookIssued/BookIssueAppService.cs
  60. +14
    -2
      aspnet-core/src/Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs
  61. +43
    -0
      aspnet-core/src/Acme.BookStore.Application/Books/BookAppService.cs
  62. +86
    -0
      aspnet-core/src/Acme.BookStore.Application/Customers/CustomerAppService.cs
  63. +1
    -1
      aspnet-core/src/Acme.BookStore.DbMigrator/appsettings.json
  64. +1
    -1
      aspnet-core/src/Acme.BookStore.Domain.Shared/Acme.BookStore.Domain.Shared.csproj
  65. +12
    -0
      aspnet-core/src/Acme.BookStore.Domain.Shared/Authors/AuthorConsts.cs
  66. +4
    -0
      aspnet-core/src/Acme.BookStore.Domain.Shared/BookStoreDomainErrorCodes.cs
  67. +19
    -0
      aspnet-core/src/Acme.BookStore.Domain.Shared/Books/BookType.cs
  68. +13
    -0
      aspnet-core/src/Acme.BookStore.Domain.Shared/Customers/CustomerConsts.cs
  69. +46
    -1
      aspnet-core/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json
  70. +1
    -1
      aspnet-core/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj
  71. +48
    -0
      aspnet-core/src/Acme.BookStore.Domain/Authors/Author.cs
  72. +18
    -0
      aspnet-core/src/Acme.BookStore.Domain/Authors/AuthorAlreadyExistsException.cs
  73. +57
    -0
      aspnet-core/src/Acme.BookStore.Domain/Authors/AuthorManager.cs
  74. +21
    -0
      aspnet-core/src/Acme.BookStore.Domain/Authors/IAuthorRepository.cs
  75. +33
    -0
      aspnet-core/src/Acme.BookStore.Domain/BookIssued/BookIssue.cs
  76. +19
    -0
      aspnet-core/src/Acme.BookStore.Domain/BookIssued/BookIssueErrorException.cs
  77. +36
    -0
      aspnet-core/src/Acme.BookStore.Domain/BookIssued/BookIssueManager.cs
  78. +17
    -0
      aspnet-core/src/Acme.BookStore.Domain/BookIssued/IBookIssueRepository.cs
  79. +100
    -0
      aspnet-core/src/Acme.BookStore.Domain/BookStoreDataSeederContributor.cs
  80. +20
    -0
      aspnet-core/src/Acme.BookStore.Domain/Books/Book.cs
  81. +60
    -0
      aspnet-core/src/Acme.BookStore.Domain/Customers/Customer.cs
  82. +18
    -0
      aspnet-core/src/Acme.BookStore.Domain/Customers/CustomerErrorException.cs
  83. +55
    -0
      aspnet-core/src/Acme.BookStore.Domain/Customers/CustomerManager.cs
  84. +16
    -0
      aspnet-core/src/Acme.BookStore.Domain/Customers/ICustomerRepository.cs
  85. +1
    -1
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj
  86. +56
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Authors/EfCoreAuthorRepository.cs
  87. +85
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/BookIssued/EfCoreBookIssueRepository.cs
  88. +40
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Customers/EfCoreCustomerRepository.cs
  89. +65
    -1
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs
  90. +0
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240604143520_Initial.Designer.cs
  91. +0
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240604143520_Initial.cs
  92. +2011
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605054852_Created_Book_Entity.Designer.cs
  93. +43
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605054852_Created_Book_Entity.cs
  94. +2077
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605111342_Added_Authors.Designer.cs
  95. +50
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605111342_Added_Authors.cs
  96. +2151
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606070329_Added_Customers.Designer.cs
  97. +47
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606070329_Added_Customers.cs
  98. +2212
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606100414_Added_BookIssued.Designer.cs
  99. +50
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606100414_Added_BookIssued.cs
  100. +253
    -0
      aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs

+ 3
- 5
angular/angular.json View File

@ -28,7 +28,7 @@
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"allowedCommonJsDependencies": ["chart.js", "js-sha256"], "allowedCommonJsDependencies": ["chart.js", "js-sha256"],
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
"assets": ["src/favicon.ico", "src/assets"],
"styles": [ "styles": [
{ {
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.css", "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.css",
@ -112,9 +112,7 @@
}, },
"src/styles.scss" "src/styles.scss"
], ],
"scripts": [],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
"scripts": []
}, },
"configurations": { "configurations": {
"production": { "production": {
@ -175,7 +173,7 @@
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js", "karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"], "styles": ["src/styles.scss"],
"scripts": [] "scripts": []
} }


+ 0
- 1
angular/package.json View File

@ -30,7 +30,6 @@
"@angular/platform-browser": "~17.1.0", "@angular/platform-browser": "~17.1.0",
"@angular/platform-browser-dynamic": "~17.1.0", "@angular/platform-browser-dynamic": "~17.1.0",
"@angular/router": "~17.1.0", "@angular/router": "~17.1.0",
"@angular/service-worker": "~17.1.0",
"bootstrap-icons": "~1.8.0", "bootstrap-icons": "~1.8.0",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tslib": "^2.0.0", "tslib": "^2.0.0",


+ 3
- 0
angular/src/app/app-routing.module.ts View File

@ -25,6 +25,9 @@ const routes: Routes = [
loadChildren: () => loadChildren: () =>
import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()), import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()),
}, },
{ path: 'books', loadChildren: () => import('./book/book.module').then(m => m.BookModule) },
{ path: 'customer', loadChildren: () => import('./customer/customer.module').then(m => m.CustomerModule) },
{ path: 'book-issue', loadChildren: () => import('./book-issue/book-issue.module').then(m => m.BookIssueModule) },
]; ];
@NgModule({ @NgModule({


+ 1
- 8
angular/src/app/app.module.ts View File

@ -17,7 +17,6 @@ import { AbpOAuthModule } from '@abp/ng.oauth';
import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x'; import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x';
import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts'; import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts';
import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account'; import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account';
import { ServiceWorkerModule } from '@angular/service-worker';
@NgModule({ @NgModule({
imports: [ imports: [
BrowserModule, BrowserModule,
@ -40,13 +39,7 @@ import { ServiceWorkerModule } from '@angular/service-worker';
InternetConnectionStatusComponent, InternetConnectionStatusComponent,
ThemeLeptonXModule.forRoot(), ThemeLeptonXModule.forRoot(),
SideMenuLayoutModule.forRoot(), SideMenuLayoutModule.forRoot(),
AccountLayoutModule.forRoot(),
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production,
// Register the ServiceWorker as soon as the application is stable
// or after 30 seconds (whichever comes first).
registrationStrategy: 'registerWhenStable:30000'
})
AccountLayoutModule.forRoot()
], ],
declarations: [AppComponent], declarations: [AppComponent],
providers: [APP_ROUTE_PROVIDER], providers: [APP_ROUTE_PROVIDER],


+ 12
- 0
angular/src/app/book-issue/book-issue-routing.module.ts View File

@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { BookIssueComponent } from './book-issue.component';
import { authGuard, permissionGuard } from '@abp/ng.core';
const routes: Routes = [{ path: '', component: BookIssueComponent,canActivate: [authGuard, permissionGuard] }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class BookIssueRoutingModule { }

+ 97
- 0
angular/src/app/book-issue/book-issue.component.html View File

@ -0,0 +1,97 @@
<div class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
{{ 'Book-Issue' | abpLocalization }}
</h5>
</div>
<div class="text-end col col-md-6">
<!-- Add the "new book" button here -->
<div class="text-lg-end pt-2">
<button id="create" class="btn btn-primary" type="button" (click)="createBookIssue()">
<i class="fa fa-plus me-1"></i>
<span>{{ "New Book Issue" | abpLocalization }}</span>
</button>
</div>
</div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="bookIssueList.items" [count]="bookIssueList.totalCount" [list]="list" default>
<ngx-datatable-column
[name]="'::Actions' | abpLocalization"
[maxWidth]="150"
[sortable]="false"
>
<ng-template let-row="row" ngx-datatable-cell-template>
<div ngbDropdown container="body" class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }}
</button>
<div ngbDropdownMenu>
<button ngbDropdownItem (click)="delete(row.bookIssueId)">
{{ 'un Issue' | abpLocalization }}
</button>
</div>
</div>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'Book Name' | abpLocalization" prop="bookName"></ngx-datatable-column>
<ngx-datatable-column [name]="'Customer Name' | abpLocalization" prop="customerName">
</ngx-datatable-column>
<ngx-datatable-column [name]="'Issue Date' | abpLocalization" prop="issueDate">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.issueDate | date }}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
<!-- Add the modal here -->
<abp-modal [(visible)]="isModalOpen">
<ng-template #abpHeader>
<h3> Book Issued </h3>
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="mt-2">
<label for="book-type">Book Name</label><span> * </span>
<select class="form-control" id="book-type" formControlName="bookId">
<option [ngValue]="null">Select a book name</option>
<option [ngValue]="book.id" *ngFor="let book of dropDownbook"> {{ book.name }}</option>
</select>
</div>
<div class="mt-2">
<label for="customer-name">Customer Name</label><span> * </span>
<select class="form-control" id="customer-name" formControlName="customerId">
<option [ngValue]="null">Select a customer name</option>
<option [ngValue]="customer.id" *ngFor="let customer of dropDownCustomer"> {{ customer.firstName }} {{ customer.lastName}}</option>
</select>
</div>
</form>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" abpClose>
{{ '::Close' | abpLocalization }}
</button>
<!--added save button-->
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid">
<i class="fa fa-check mr-1"></i>
{{ '::Save' | abpLocalization }}
</button>
</ng-template>
</abp-modal>

+ 0
- 0
angular/src/app/book-issue/book-issue.component.scss View File


+ 23
- 0
angular/src/app/book-issue/book-issue.component.spec.ts View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BookIssueComponent } from './book-issue.component';
describe('BookIssueComponent', () => {
let component: BookIssueComponent;
let fixture: ComponentFixture<BookIssueComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [BookIssueComponent]
})
.compileComponents();
fixture = TestBed.createComponent(BookIssueComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 83
- 0
angular/src/app/book-issue/book-issue.component.ts View File

@ -0,0 +1,83 @@
import { Component, OnInit } from '@angular/core';
import { ListService, PagedResultDto } from '@abp/ng.core';
import { BookIssueDto, BookIssueListDto, BookIssueService } from '@proxy/book-issued';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { BookDto, BookService } from '@proxy/books';
import { CustomerDto, CustomerService } from '@proxy/customers';
import { ConfirmationService,Confirmation } from '@abp/ng.theme.shared';
@Component({
selector: 'app-book-issue',
templateUrl: './book-issue.component.html',
styleUrl: './book-issue.component.scss',
providers: [ListService]
})
export class BookIssueComponent implements OnInit {
isModalOpen = false;
form:FormGroup;
dropDownbook= {} as Array<BookDto>;
dropDownCustomer= {} as Array<CustomerDto>;
bookIssueList = { items: [], totalCount: 0 } as PagedResultDto<BookIssueListDto>;
constructor(public readonly list: ListService,
private bookIssuedService: BookIssueService,
private bookService: BookService,
private customerService: CustomerService,
private fb: FormBuilder,
private confirmation: ConfirmationService ) {}
ngOnInit(): void {
this.dropdowninitiale();
const bookStreamCreator = (query) => this.bookIssuedService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
this.bookIssueList = response;
});
}
createBookIssue() {
this.buildForm();
this.isModalOpen = true;
}
buildForm() {
this.form = this.fb.group({
bookId: ['', Validators.required],
customerId: ['', Validators.required],
});
}
save() {
if (this.form.invalid) {
return;
}
this.bookIssuedService.create(this.form.value).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
}
dropdowninitiale(){
this.bookService.getBookDropDown().subscribe((response)=>{
this.dropDownbook = response;
});
this.customerService.getcustomerDropDown().subscribe((response)=>{
this.dropDownCustomer = response;
});
}
delete(bookIssueId: number) {
this.confirmation.warn('::AreYouSureToUnIssue', '::AreYouSure').subscribe((status) => {
if (status === Confirmation.Status.confirm) {
this.bookIssuedService.delete(bookIssueId).subscribe(() => this.list.get());
}
});
}
}

+ 19
- 0
angular/src/app/book-issue/book-issue.module.ts View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BookIssueRoutingModule } from './book-issue-routing.module';
import { BookIssueComponent } from './book-issue.component';
import{SharedModule} from '../shared/shared.module';
@NgModule({
declarations: [
BookIssueComponent
],
imports: [
CommonModule,
BookIssueRoutingModule,
SharedModule
]
})
export class BookIssueModule { }

+ 12
- 0
angular/src/app/book/book-routing.module.ts View File

@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { BookComponent } from './book.component';
import { authGuard, permissionGuard } from '@abp/ng.core';
const routes: Routes = [{ path: '', component: BookComponent, canActivate: [authGuard, permissionGuard] }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class BookRoutingModule { }

+ 122
- 0
angular/src/app/book/book.component.html View File

@ -0,0 +1,122 @@
<div class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
{{ '::Menu:Books' | abpLocalization }}
</h5>
</div>
<div class="text-end col col-md-6">
<!-- Add the "new book" button here -->
<div class="text-lg-end pt-2">
<button id="create" class="btn btn-primary" type="button" (click)="createBook()">
<i class="fa fa-plus me-1"></i>
<span>{{ "::NewBook" | abpLocalization }}</span>
</button>
</div>
</div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="book.items" [count]="book.totalCount" [list]="list" default>
<ngx-datatable-column
[name]="'::Actions' | abpLocalization"
[maxWidth]="150"
[sortable]="false"
>
<ng-template let-row="row" ngx-datatable-cell-template>
<div ngbDropdown container="body" class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }}
</button>
<div ngbDropdownMenu>
<button ngbDropdownItem (click)="editBook(row.id)">
{{ '::Edit' | abpLocalization }}
</button>
<button ngbDropdownItem (click)="delete(row.id)">
{{ '::Delete' | abpLocalization }}
</button>
</div>
</div>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Name' | abpLocalization" prop="name"></ngx-datatable-column>
<ngx-datatable-column [name]="'::Type' | abpLocalization" prop="type">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ '::Enum:BookType.' + row.type | abpLocalization }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::PublishDate' | abpLocalization" prop="publishDate">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.publishDate | date }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Price' | abpLocalization" prop="price">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.price | currency }}
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
<!-- Add the modal here -->
<abp-modal [(visible)]="isModalOpen">
<ng-template #abpHeader>
<h3>{{ '::NewBook' | abpLocalization }}</h3>
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="mt-2">
<label for="book-name">Name</label><span> * </span>
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus />
</div>
<div class="mt-2">
<label for="book-price">Price</label><span> * </span>
<input type="number" id="book-price" class="form-control" formControlName="price" />
</div>
<div class="mt-2">
<label for="book-type">Type</label><span> * </span>
<select class="form-control" id="book-type" formControlName="type">
<option [ngValue]="null">Select a book type</option>
<option [ngValue]="type.value" *ngFor="let type of bookTypes"> {{ '::Enum:BookType.' + type.value | abpLocalization }}</option>
</select>
</div>
<div class="mt-2">
<label>Publish date</label><span> * </span>
<input
#datepicker="ngbDatepicker"
class="form-control"
name="datepicker"
formControlName="publishDate"
ngbDatepicker
(click)="datepicker.toggle()"
/>
</div>
</form>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" abpClose>
{{ '::Close' | abpLocalization }}
</button>
<!--added save button-->
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid">
<i class="fa fa-check mr-1"></i>
{{ '::Save' | abpLocalization }}
</button>
</ng-template>
</abp-modal>

+ 0
- 0
angular/src/app/book/book.component.scss View File


+ 23
- 0
angular/src/app/book/book.component.spec.ts View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BookComponent } from './book.component';
describe('BookComponent', () => {
let component: BookComponent;
let fixture: ComponentFixture<BookComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [BookComponent]
})
.compileComponents();
fixture = TestBed.createComponent(BookComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 88
- 0
angular/src/app/book/book.component.ts View File

@ -0,0 +1,88 @@
import { ListService, PagedResultDto } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { BookService, BookDto, bookTypeOptions } from '@proxy/books';
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
@Component({
selector: 'app-book',
templateUrl: './book.component.html',
styleUrls: ['./book.component.scss'],
providers: [ListService,
{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter } // add this line
],
})
export class BookComponent implements OnInit {
book = { items: [], totalCount: 0 } as PagedResultDto<BookDto>;
selectedBook = {} as BookDto; // declare selectedBook
isModalOpen = false; // add this line
form: FormGroup; // add this line
bookTypes = bookTypeOptions;
constructor(public readonly list: ListService, private bookService: BookService, private fb: FormBuilder,
private confirmation: ConfirmationService
) {}
ngOnInit() {
debugger;
const bookStreamCreator = (query) => this.bookService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
this.book = response;
});
}
// add new method
createBook() {
this.buildForm(); // add this line
this.selectedBook = {} as BookDto; // reset the selected book
this.isModalOpen = true;
}
buildForm() {
this.form = this.fb.group({
name: ['', Validators.required],
type: [null, Validators.required],
publishDate: [null, Validators.required],
price: [null, Validators.required],
});
}
save() {
if (this.form.invalid) {
return;
}
const request = this.selectedBook.id
? this.bookService.update(this.selectedBook.id, this.form.value)
: this.bookService.create(this.form.value);
request.subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
}
// Add editBook method
editBook(id: string) {
this.bookService.get(id).subscribe((book) => {
this.selectedBook = book;
this.buildForm();
this.form.controls["name"].setValue(this.selectedBook.name);
this.form.controls["type"].setValue(this.selectedBook.type);
this.form.controls["publishDate"].setValue(this.selectedBook.publishDate);
this.form.controls["price"].setValue(this.selectedBook.price);
this.isModalOpen = true;
});
}
delete(id: string) {
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => {
if (status === Confirmation.Status.confirm) {
this.bookService.delete(id).subscribe(() => this.list.get());
}
});
}
}

+ 21
- 0
angular/src/app/book/book.module.ts View File

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BookRoutingModule } from './book-routing.module';
import { BookComponent } from './book.component';
import{SharedModule} from '../shared/shared.module';
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; // add this line
@NgModule({
declarations: [
BookComponent
],
imports: [
CommonModule,
BookRoutingModule,
SharedModule,
NgbDatepickerModule
]
})
export class BookModule { }

+ 13
- 0
angular/src/app/customer/customer-routing.module.ts View File

@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomerComponent } from './customer.component';
import { authGuard, permissionGuard } from '@abp/ng.core';
const routes: Routes = [{ path: '', component: CustomerComponent,canActivate: [authGuard, permissionGuard] }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class CustomerRoutingModule { }

+ 101
- 0
angular/src/app/customer/customer.component.html View File

@ -0,0 +1,101 @@
<div class="card">
<div class="card-header">
<div class="row">
<div class="col col-md-6">
<h5 class="card-title">
{{ 'customer' | abpLocalization }}
</h5>
</div>
<div class="text-end col col-md-6">
<!-- Add the "new book" button here -->
<div class="text-lg-end pt-2">
<button id="create" class="btn btn-primary" type="button" (click)="createCustomer()">
<i class="fa fa-plus me-1"></i>
<span>{{ "New Customer" | abpLocalization }}</span>
</button>
</div>
</div>
</div>
</div>
<div class="card-body">
<ngx-datatable [rows]="customer.items" [count]="customer.totalCount" [list]="list" default>
<ngx-datatable-column
[name]="'::Actions' | abpLocalization"
[maxWidth]="150"
[sortable]="false"
>
<ng-template let-row="row" ngx-datatable-cell-template>
<div ngbDropdown container="body" class="d-inline-block">
<button
class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
ngbDropdownToggle
>
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }}
</button>
<div ngbDropdownMenu>
<button ngbDropdownItem (click)="editCustomer(row.id)">
{{ '::Edit' | abpLocalization }}
</button>
<button ngbDropdownItem (click)="delete(row.id)">
{{ '::Delete' | abpLocalization }}
</button>
</div>
</div>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column [name]="'first Name' | abpLocalization" prop="firstName"></ngx-datatable-column>
<ngx-datatable-column [name]="'Last Name' | abpLocalization" prop="lastName">
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Address' | abpLocalization" prop="address">
</ngx-datatable-column>
<ngx-datatable-column [name]="'::Phone' | abpLocalization" prop="phone">
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
<!-- Add the modal here -->
<abp-modal [(visible)]="isModalOpen">
<ng-template #abpHeader>
<h3>{{ (selectedcustomer.id ? '::Edit' : '::New Customer' ) | abpLocalization }}</h3>
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form" (ngSubmit)="save()">
<div class="mt-2">
<label for="customer-first-name">First Name</label><span> * </span>
<input type="text" id="customer-first-name" class="form-control" formControlName="firstName" autofocus />
</div>
<div class="mt-2">
<label for="customer-last-name">Last Name</label><span> * </span>
<input type="text" id="customer-last-name" class="form-control" formControlName="lastName" />
</div>
<div class="mt-2">
<label for="customer-phone-name">Phone</label><span> * </span>
<input type="text" id="customer-phone-name" class="form-control" formControlName="phone" />
</div>
<div class="mt-2">
<label for="customer-address-name">Address</label><span> * </span>
<input type="text" id="customer-address-name" class="form-control" formControlName="address" />
</div>
</form>
</ng-template>
<ng-template #abpFooter>
<button type="button" class="btn btn-secondary" abpClose>
{{ '::Close' | abpLocalization }}
</button>
<!--added save button-->
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid">
<i class="fa fa-check mr-1"></i>
{{ '::Save' | abpLocalization }}
</button>
</ng-template>
</abp-modal>

+ 0
- 0
angular/src/app/customer/customer.component.scss View File


+ 23
- 0
angular/src/app/customer/customer.component.spec.ts View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CustomerComponent } from './customer.component';
describe('CustomerComponent', () => {
let component: CustomerComponent;
let fixture: ComponentFixture<CustomerComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [CustomerComponent]
})
.compileComponents();
fixture = TestBed.createComponent(CustomerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

+ 92
- 0
angular/src/app/customer/customer.component.ts View File

@ -0,0 +1,92 @@
import { Component, OnInit } from '@angular/core';
import { ListService, PagedResultDto } from '@abp/ng.core';
import { CustomerDto, CustomerService } from '@proxy/customers';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
@Component({
selector: 'app-customer',
templateUrl: './customer.component.html',
styleUrl: './customer.component.scss',
providers: [ListService]
})
export class CustomerComponent implements OnInit {
customer = { items: [], totalCount: 0 } as PagedResultDto<CustomerDto>;
isModalOpen = false;
form: FormGroup;
selectedcustomer = {} as CustomerDto;
constructor(public readonly list: ListService,
private customerService: CustomerService,
private fb: FormBuilder,
private confirmation: ConfirmationService ) {}
ngOnInit() {
debugger;
const bookStreamCreator = (query) => this.customerService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
this.customer = response;
});
}
// add new method
createCustomer() {
this.selectedcustomer = {} as CustomerDto;
this.buildForm();
this.isModalOpen = true;
}
editCustomer(id: number) {
this.customerService.get(id).subscribe((customer) => {
debugger;
this.selectedcustomer = customer;
this.buildForm();
this.isModalOpen = true;
});
}
buildForm() {
this.form = this.fb.group({
firstName: [this.selectedcustomer.firstName || '', Validators.required],
lastName: [this.selectedcustomer.lastName, Validators.required],
phone: [this.selectedcustomer.phone, Validators.required],
address: [this.selectedcustomer.address, Validators.required],
});
}
// add save method
save() {
if (this.form.invalid) {
return;
}
debugger;
const request = this.selectedcustomer.id
? this.customerService.update(this.selectedcustomer.id, this.form.value)
: this.customerService.create(this.form.value);
if(this.selectedcustomer.id){
this.customerService.update(this.selectedcustomer.id,this.form.value).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
}
else{
this.customerService.create(this.form.value).subscribe(() => {
this.isModalOpen = false;
this.form.reset();
this.list.get();
});
}
}
delete(id: number) {
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => {
if (status === Confirmation.Status.confirm) {
this.customerService.delete(id).subscribe(() => this.list.get());
}
});
}
}

+ 20
- 0
angular/src/app/customer/customer.module.ts View File

@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CustomerRoutingModule } from './customer-routing.module';
import { CustomerComponent } from './customer.component';
import{SharedModule} from '../shared/shared.module';
@NgModule({
declarations: [
CustomerComponent
],
imports: [
CommonModule,
CustomerRoutingModule,
SharedModule
]
})
export class CustomerModule { }

+ 17
- 0
angular/src/app/proxy/README.md View File

@ -0,0 +1,17 @@
# Proxy Generation Output
This directory includes the output of the latest proxy generation.
The files and folders in it will be overwritten when proxy generation is run again.
Therefore, please do not place your own content in this folder.
In addition, `generate-proxy.json` works like a lock file.
It includes information used by the proxy generator, so please do not delete or modify it.
Finally, the name of the files and folders should not be changed for two reasons:
- Proxy generator will keep creating them at those paths and you will have multiple copies of the same content.
- ABP Suite generates files which include imports from this folder.
> **Important Notice:** If you are building a module and are planning to publish to npm,
> some of the generated proxies are likely to be exported from public-api.ts file. In such a case,
> please make sure you export files directly and not from barrel exports. In other words,
> do not include index.ts exports in your public-api.ts exports.

+ 56
- 0
angular/src/app/proxy/authors/author.service.ts View File

@ -0,0 +1,56 @@
import type { AuthorDto, CreateAuthorDto, GetAuthorListDto, UpdateAuthorDto } from './models';
import { RestService, Rest } from '@abp/ng.core';
import type { PagedResultDto } from '@abp/ng.core';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class AuthorService {
apiName = 'Default';
create = (input: CreateAuthorDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, AuthorDto>({
method: 'POST',
url: '/api/app/author',
body: input,
},
{ apiName: this.apiName,...config });
delete = (id: string, config?: Partial<Rest.Config>) =>
this.restService.request<any, void>({
method: 'DELETE',
url: `/api/app/author/${id}`,
},
{ apiName: this.apiName,...config });
get = (id: string, config?: Partial<Rest.Config>) =>
this.restService.request<any, AuthorDto>({
method: 'GET',
url: `/api/app/author/${id}`,
},
{ apiName: this.apiName,...config });
getList = (input: GetAuthorListDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, PagedResultDto<AuthorDto>>({
method: 'GET',
url: '/api/app/author',
params: { filter: input.filter, sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount },
},
{ apiName: this.apiName,...config });
update = (id: string, input: UpdateAuthorDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, void>({
method: 'PUT',
url: `/api/app/author/${id}`,
body: input,
},
{ apiName: this.apiName,...config });
constructor(private restService: RestService) {}
}

+ 2
- 0
angular/src/app/proxy/authors/index.ts View File

@ -0,0 +1,2 @@
export * from './author.service';
export * from './models';

+ 23
- 0
angular/src/app/proxy/authors/models.ts View File

@ -0,0 +1,23 @@
import type { EntityDto, PagedAndSortedResultRequestDto } from '@abp/ng.core';
export interface AuthorDto extends EntityDto<string> {
name?: string;
birthDate?: string;
shortBio?: string;
}
export interface CreateAuthorDto {
name: string;
birthDate: string;
shortBio?: string;
}
export interface GetAuthorListDto extends PagedAndSortedResultRequestDto {
filter?: string;
}
export interface UpdateAuthorDto {
name: string;
birthDate: string;
shortBio?: string;
}

+ 55
- 0
angular/src/app/proxy/book-issued/book-issue.service.ts View File

@ -0,0 +1,55 @@
import type { BookIssueDto, BookIssueListDto } from './models';
import { RestService, Rest } from '@abp/ng.core';
import type { PagedResultDto } from '@abp/ng.core';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class BookIssueService {
apiName = 'Default';
create = (input: BookIssueDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, BookIssueDto>({
method: 'POST',
url: '/api/app/book-issue',
body: input,
},
{ apiName: this.apiName,...config });
delete = (id: number, config?: Partial<Rest.Config>) =>
this.restService.request<any, void>({
method: 'DELETE',
url: `/api/app/book-issue/${id}`,
},
{ apiName: this.apiName,...config });
get = (id: number, config?: Partial<Rest.Config>) =>
this.restService.request<any, BookIssueDto>({
method: 'GET',
url: `/api/app/book-issue/${id}`,
},
{ apiName: this.apiName,...config });
getList = (config?: Partial<Rest.Config>) =>
this.restService.request<any, PagedResultDto<BookIssueListDto>>({
method: 'GET',
url: '/api/app/book-issue',
},
{ apiName: this.apiName,...config });
update = (id: number, input: BookIssueDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, void>({
method: 'PUT',
url: `/api/app/book-issue/${id}`,
body: input,
},
{ apiName: this.apiName,...config });
constructor(private restService: RestService) {}
}

+ 2
- 0
angular/src/app/proxy/book-issued/index.ts View File

@ -0,0 +1,2 @@
export * from './book-issue.service';
export * from './models';

+ 13
- 0
angular/src/app/proxy/book-issued/models.ts View File

@ -0,0 +1,13 @@
import type { EntityDto } from '@abp/ng.core';
export interface BookIssueDto extends EntityDto<number> {
bookId?: string;
customerId: number;
}
export interface BookIssueListDto {
bookIssueId: number;
bookName?: string;
customerName?: string;
issueDate?: string;
}

+ 15
- 0
angular/src/app/proxy/books/book-type.enum.ts View File

@ -0,0 +1,15 @@
import { mapEnumToOptions } from '@abp/ng.core';
export enum BookType {
Undefined = 0,
Adventure = 1,
Biography = 2,
Dystopia = 3,
Fantastic = 4,
Horror = 5,
Science = 6,
ScienceFiction = 7,
Poetry = 8,
}
export const bookTypeOptions = mapEnumToOptions(BookType);

+ 64
- 0
angular/src/app/proxy/books/book.service.ts View File

@ -0,0 +1,64 @@
import type { BookDto, CreateUpdateBookDto } from './models';
import { RestService, Rest } from '@abp/ng.core';
import type { PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class BookService {
apiName = 'Default';
create = (input: CreateUpdateBookDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, BookDto>({
method: 'POST',
url: '/api/app/book',
body: input,
},
{ apiName: this.apiName,...config });
delete = (id: string, config?: Partial<Rest.Config>) =>
this.restService.request<any, void>({
method: 'DELETE',
url: `/api/app/book/${id}`,
},
{ apiName: this.apiName,...config });
get = (id: string, config?: Partial<Rest.Config>) =>
this.restService.request<any, BookDto>({
method: 'GET',
url: `/api/app/book/${id}`,
},
{ apiName: this.apiName,...config });
getBookDropDown = (config?: Partial<Rest.Config>) =>
this.restService.request<any, BookDto[]>({
method: 'GET',
url: '/api/app/book/book-drop-down',
},
{ apiName: this.apiName,...config });
getList = (input: PagedAndSortedResultRequestDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, PagedResultDto<BookDto>>({
method: 'GET',
url: '/api/app/book',
params: { sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount },
},
{ apiName: this.apiName,...config });
update = (id: string, input: CreateUpdateBookDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, BookDto>({
method: 'PUT',
url: `/api/app/book/${id}`,
body: input,
},
{ apiName: this.apiName,...config });
constructor(private restService: RestService) {}
}

+ 3
- 0
angular/src/app/proxy/books/index.ts View File

@ -0,0 +1,3 @@
export * from './book-type.enum';
export * from './book.service';
export * from './models';

+ 16
- 0
angular/src/app/proxy/books/models.ts View File

@ -0,0 +1,16 @@
import type { AuditedEntityDto } from '@abp/ng.core';
import type { BookType } from './book-type.enum';
export interface BookDto extends AuditedEntityDto<string> {
name?: string;
type: BookType;
publishDate?: string;
price: number;
}
export interface CreateUpdateBookDto {
name: string;
type: BookType;
publishDate: string;
price: number;
}

+ 63
- 0
angular/src/app/proxy/customers/customer.service.ts View File

@ -0,0 +1,63 @@
import type { CustomerDto } from './models';
import { RestService, Rest } from '@abp/ng.core';
import type { PagedResultDto } from '@abp/ng.core';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class CustomerService {
apiName = 'Default';
create = (input: CustomerDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, CustomerDto>({
method: 'POST',
url: '/api/app/customer',
body: input,
},
{ apiName: this.apiName,...config });
delete = (id: number, config?: Partial<Rest.Config>) =>
this.restService.request<any, void>({
method: 'DELETE',
url: `/api/app/customer/${id}`,
},
{ apiName: this.apiName,...config });
get = (id: number, config?: Partial<Rest.Config>) =>
this.restService.request<any, CustomerDto>({
method: 'GET',
url: `/api/app/customer/${id}`,
},
{ apiName: this.apiName,...config });
getList = (config?: Partial<Rest.Config>) =>
this.restService.request<any, PagedResultDto<CustomerDto>>({
method: 'GET',
url: '/api/app/customer',
},
{ apiName: this.apiName,...config });
getcustomerDropDown = (config?: Partial<Rest.Config>) =>
this.restService.request<any, CustomerDto[]>({
method: 'GET',
url: '/api/app/customer/customer-drop-down',
},
{ apiName: this.apiName,...config });
update = (id: number, input: CustomerDto, config?: Partial<Rest.Config>) =>
this.restService.request<any, void>({
method: 'PUT',
url: `/api/app/customer/${id}`,
body: input,
},
{ apiName: this.apiName,...config });
constructor(private restService: RestService) {}
}

+ 2
- 0
angular/src/app/proxy/customers/index.ts View File

@ -0,0 +1,2 @@
export * from './customer.service';
export * from './models';

+ 8
- 0
angular/src/app/proxy/customers/models.ts View File

@ -0,0 +1,8 @@
import type { EntityDto } from '@abp/ng.core';
export interface CustomerDto extends EntityDto<number> {
firstName?: string;
lastName?: string;
phone?: string;
address?: string;
}

+ 10619
- 0
angular/src/app/proxy/generate-proxy.json
File diff suppressed because it is too large
View File


+ 5
- 0
angular/src/app/proxy/index.ts View File

@ -0,0 +1,5 @@
import * as Authors from './authors';
import * as BookIssued from './book-issued';
import * as Books from './books';
import * as Customers from './customers';
export { Authors, BookIssued, Books, Customers };

+ 34
- 0
angular/src/app/route.provider.ts View File

@ -15,6 +15,40 @@ function configureRoutes(routesService: RoutesService) {
order: 1, order: 1,
layout: eLayoutType.application, layout: eLayoutType.application,
}, },
{
path: '/book-store',
name: '::Menu:BookStore',
iconClass: 'fas fa-book',
order: 2,
layout: eLayoutType.application,
requiredPolicy: 'BookStore.Books',
},
{
path: '/books',
name: '::Menu:Books',
parentName: '::Menu:BookStore',
layout: eLayoutType.application,
requiredPolicy: 'BookStore.Books',
},
{
path: '/customer',
name: 'Customer',
iconClass: 'fas fa-user',
order: 2,
layout: eLayoutType.application,
requiredPolicy: 'BookStore.Customers',
},
{
path: '/book-issue',
name: 'book-issue',
iconClass: 'fas fa-book',
order: 2,
layout: eLayoutType.application,
requiredPolicy: 'BookStore.BookIssued',
},
]); ]);
}; };
} }

+ 2
- 2
angular/src/environments/environment.prod.ts View File

@ -10,7 +10,7 @@ export const environment = {
logoUrl: '', logoUrl: '',
}, },
oAuthConfig: { oAuthConfig: {
issuer: 'https://localhost:44362/',
issuer: 'https://localhost:44356/',
redirectUri: baseUrl, redirectUri: baseUrl,
clientId: 'BookStore_App', clientId: 'BookStore_App',
responseType: 'code', responseType: 'code',
@ -19,7 +19,7 @@ export const environment = {
}, },
apis: { apis: {
default: { default: {
url: 'https://localhost:44362',
url: 'https://localhost:44356',
rootNamespace: 'Acme.BookStore', rootNamespace: 'Acme.BookStore',
}, },
}, },


+ 2
- 2
angular/src/environments/environment.ts View File

@ -10,7 +10,7 @@ export const environment = {
logoUrl: '', logoUrl: '',
}, },
oAuthConfig: { oAuthConfig: {
issuer: 'https://localhost:44362/',
issuer: 'https://localhost:44356/',
redirectUri: baseUrl, redirectUri: baseUrl,
clientId: 'BookStore_App', clientId: 'BookStore_App',
responseType: 'code', responseType: 'code',
@ -19,7 +19,7 @@ export const environment = {
}, },
apis: { apis: {
default: { default: {
url: 'https://localhost:44362',
url: 'https://localhost:44356',
rootNamespace: 'Acme.BookStore', rootNamespace: 'Acme.BookStore',
}, },
}, },


+ 6
- 9
angular/src/index.html View File

@ -1,19 +1,16 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"/>
<meta charset="utf-8" />
<title>BookStore</title> <title>BookStore</title>
<base href="/"/>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" type="image/x-icon" href="favicon.ico"/>
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#1976d2">
</head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body class="bg-light"> <body class="bg-light">
<app-root> <app-root>
<div class="donut centered"></div> <div class="donut centered"></div>
</app-root> </app-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
</body>
</html> </html>

+ 496
- 511
angular/yarn.lock
File diff suppressed because it is too large
View File


+ 2
- 2
aspnet-core/README.md View File

@ -24,10 +24,10 @@ In the production environment, you need to use a production signing certificate.
This certificate is already generated by ABP CLI, so most of the time you don't need to generate it yourself. However, if you need to generate a certificate, you can use the following command: This certificate is already generated by ABP CLI, so most of the time you don't need to generate it yourself. However, if you need to generate a certificate, you can use the following command:
```bash ```bash
dotnet dev-certs https -v -ep openiddict.pfx -p 70790fc6-826d-4901-86d8-1b6ae21c9efb
dotnet dev-certs https -v -ep openiddict.pfx -p 9d3dbfba-a400-4e7c-b7a2-779cd1b0c44f
``` ```
> `70790fc6-826d-4901-86d8-1b6ae21c9efb` is the password of the certificate, you can change it to any password you want.
> `9d3dbfba-a400-4e7c-b7a2-779cd1b0c44f` is the password of the certificate, you can change it to any password you want.
It is recommended to use **two** RSA certificates, distinct from the certificate(s) used for HTTPS: one for encryption, one for signing. It is recommended to use **two** RSA certificates, distinct from the certificate(s) used for HTTPS: one for encryption, one for signing.


+ 1
- 1
aspnet-core/src/Acme.BookStore.Application.Contracts/Acme.BookStore.Application.Contracts.csproj View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" /> <Import Project="..\..\common.props" />


+ 44
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Authors/AuthorDto.cs View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Authors
{
public class AuthorDto : EntityDto<Guid>
{
public string Name { get; set; }
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
}
public class GetAuthorListDto : PagedAndSortedResultRequestDto
{
public string? Filter { get; set; }
}
public class CreateAuthorDto
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; } = string.Empty;
[Required]
public DateTime BirthDate { get; set; }
public string? ShortBio { get; set; }
}
public class UpdateAuthorDto
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; } = string.Empty;
[Required]
public DateTime BirthDate { get; set; }
public string? ShortBio { get; set; }
}
}

+ 19
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Authors/IAuthorAppService.cs View File

@ -0,0 +1,19 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Authors;
public interface IAuthorAppService : IApplicationService
{
Task<AuthorDto> GetAsync(Guid id);
Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input);
Task<AuthorDto> CreateAsync(CreateAuthorDto input);
Task UpdateAsync(Guid id, UpdateAuthorDto input);
Task DeleteAsync(Guid id);
}

+ 25
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/BookIssued/BookIssueDto.cs View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.BookIssued
{
public class BookIssueDto : EntityDto<int>
{
[Required]
public Guid bookId { get; set; }
[Required]
public int customerId { get; set; }
}
public class BookIssueListDto
{
public int bookIssueId { get; set; }
public string bookName { get; set; }
public string customerName { get; set; }
public DateTime issueDate { get; set; }
}
}

+ 22
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/BookIssued/IBookIssueAppService.cs View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.BookIssued
{
public interface IBookIssueAppService : IApplicationService
{
Task<BookIssueDto> GetAsync(int id);
Task<PagedResultDto<BookIssueListDto>> GetListAsync();
Task<BookIssueDto> CreateAsync(BookIssueDto input);
Task UpdateAsync(int id, BookIssueDto input);
Task DeleteAsync(int id);
}
}

+ 18
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Books/BookDto.cs View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Books
{
public class BookDto : AuditedEntityDto<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}

+ 24
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Books/CreateUpdateBookDto.cs View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Acme.BookStore.Books
{
public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; } = string.Empty;
[Required]
public BookType Type { get; set; } = BookType.Undefined;
[Required]
[DataType(DataType.Date)]
public DateTime PublishDate { get; set; } = DateTime.Now;
[Required]
public float Price { get; set; }
}
}

+ 19
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Books/IBookAppService.cs View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Books
{
public interface IBookAppService :
ICrudAppService< //Defines CRUD methods
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdateBookDto> //Used to create/update a book
{
Task<List<BookDto>> GetBookDropDown();
}
}

+ 20
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Customers/CustomerDto.cs View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Customers
{
public class CustomerDto : EntityDto<int>
{
[Required]
public string firstName { get; set; }
[Required]
public string lastName { get; set; }
[Required]
public string phone { get; set; }
[Required]
public string address { get; set; }
}
}

+ 24
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Customers/ICustomerAppService.cs View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Customers
{
public interface ICustomerAppService : IApplicationService
{
Task<CustomerDto> GetAsync(int id);
Task<PagedResultDto<CustomerDto>> GetListAsync();
Task<CustomerDto> CreateAsync(CustomerDto input);
Task UpdateAsync(int id, CustomerDto input);
Task DeleteAsync(int id);
Task<List<CustomerDto>> GetcustomerDropDown();
}
}

+ 34
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Permissions/BookStorePermissionDefinitionProvider.cs View File

@ -11,6 +11,40 @@ public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvide
var myGroup = context.AddGroup(BookStorePermissions.GroupName); var myGroup = context.AddGroup(BookStorePermissions.GroupName);
//Define your own permissions here. Example: //Define your own permissions here. Example:
//myGroup.AddPermission(BookStorePermissions.MyPermission1, L("Permission:MyPermission1")); //myGroup.AddPermission(BookStorePermissions.MyPermission1, L("Permission:MyPermission1"));
var booksPermission = myGroup.AddPermission(BookStorePermissions.Books.Default, L("Permission:Books"));
booksPermission.AddChild(BookStorePermissions.Books.Create, L("Permission:Books.Create"));
booksPermission.AddChild(BookStorePermissions.Books.Edit, L("Permission:Books.Edit"));
booksPermission.AddChild(BookStorePermissions.Books.Delete, L("Permission:Books.Delete"));
var authorsPermission = myGroup.AddPermission(
BookStorePermissions.Authors.Default, L("Permission:Authors"));
authorsPermission.AddChild(
BookStorePermissions.Authors.Create, L("Permission:Authors.Create"));
authorsPermission.AddChild(
BookStorePermissions.Authors.Edit, L("Permission:Authors.Edit"));
authorsPermission.AddChild(
BookStorePermissions.Authors.Delete, L("Permission:Authors.Delete"));
var customersPermission = myGroup.AddPermission(
BookStorePermissions.Customers.Default, L("Permission:Customers"));
customersPermission.AddChild(
BookStorePermissions.Customers.Create, L("Permission:Customers.Create"));
customersPermission.AddChild(
BookStorePermissions.Customers.Edit, L("Permission:Customers.Edit"));
customersPermission.AddChild(
BookStorePermissions.Customers.Delete, L("Permission:Customers.Delete"));
var bookissuedPermission = myGroup.AddPermission(
BookStorePermissions.BookIssued.Default, L("Permission:BookIssued"));
bookissuedPermission.AddChild(
BookStorePermissions.BookIssued.Create, L("Permission:BookIssued.Create"));
bookissuedPermission.AddChild(
BookStorePermissions.BookIssued.Edit, L("Permission:BookIssued.Edit"));
bookissuedPermission.AddChild(
BookStorePermissions.BookIssued.Delete, L("Permission:BookIssued.Delete"));
} }
private static LocalizableString L(string name) private static LocalizableString L(string name)


+ 29
- 0
aspnet-core/src/Acme.BookStore.Application.Contracts/Permissions/BookStorePermissions.cs View File

@ -4,6 +4,35 @@ public static class BookStorePermissions
{ {
public const string GroupName = "BookStore"; public const string GroupName = "BookStore";
public static class Books
{
public const string Default = GroupName + ".Books";
public const string Create = Default + ".Create";
public const string Edit = Default + ".Edit";
public const string Delete = Default + ".Delete";
}
public static class Authors
{
public const string Default = GroupName + ".Authors";
public const string Create = Default + ".Create";
public const string Edit = Default + ".Edit";
public const string Delete = Default + ".Delete";
}
public static class Customers
{
public const string Default = GroupName + ".Customers";
public const string Create = Default + ".Create";
public const string Edit = Default + ".Edit";
public const string Delete = Default + ".Delete";
}
public static class BookIssued
{
public const string Default = GroupName + ".BookIssued";
public const string Create = Default + ".Create";
public const string Edit = Default + ".Edit";
public const string Delete = Default + ".Delete";
}
//Add your own permission names. Example: //Add your own permission names. Example:
//public const string MyPermission1 = GroupName + ".MyPermission1"; //public const string MyPermission1 = GroupName + ".MyPermission1";
} }

+ 1
- 1
aspnet-core/src/Acme.BookStore.Application/Acme.BookStore.Application.csproj View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" /> <Import Project="..\..\common.props" />


+ 95
- 0
aspnet-core/src/Acme.BookStore.Application/Authors/AuthorAppService.cs View File

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Acme.BookStore.Permissions;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore.Authors
{
[Authorize(BookStorePermissions.Authors.Default)]
public class AuthorAppService : BookStoreAppService, IAuthorAppService
{
private readonly IAuthorRepository _authorRepository;
private readonly AuthorManager _authorManager;
public AuthorAppService(
IAuthorRepository authorRepository,
AuthorManager authorManager)
{
_authorRepository = authorRepository;
_authorManager = authorManager;
}
public async Task<AuthorDto> GetAsync(Guid id)
{
var author = await _authorRepository.GetAsync(id);
return ObjectMapper.Map<Author, AuthorDto>(author);
}
public async Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input)
{
if (input.Sorting.IsNullOrWhiteSpace())
{
input.Sorting = nameof(Author.Name);
}
var authors = await _authorRepository.GetListAsync(
input.SkipCount,
input.MaxResultCount,
input.Sorting,
input.Filter
);
var totalCount = input.Filter == null
? await _authorRepository.CountAsync()
: await _authorRepository.CountAsync(
author => author.Name.Contains(input.Filter));
return new PagedResultDto<AuthorDto>(
totalCount,
ObjectMapper.Map<List<Author>, List<AuthorDto>>(authors)
);
}
[Authorize(BookStorePermissions.Authors.Create)]
public async Task<AuthorDto> CreateAsync(CreateAuthorDto input)
{
var author = await _authorManager.CreateAsync(
input.Name,
input.BirthDate,
input.ShortBio
);
await _authorRepository.InsertAsync(author);
return ObjectMapper.Map<Author, AuthorDto>(author);
}
[Authorize(BookStorePermissions.Authors.Edit)]
public async Task UpdateAsync(Guid id, UpdateAuthorDto input)
{
var author = await _authorRepository.GetAsync(id);
if (author.Name != input.Name)
{
await _authorManager.ChangeNameAsync(author, input.Name);
}
author.BirthDate = input.BirthDate;
author.ShortBio = input.ShortBio;
await _authorRepository.UpdateAsync(author);
}
[Authorize(BookStorePermissions.Authors.Delete)]
public async Task DeleteAsync(Guid id)
{
await _authorRepository.DeleteAsync(id);
}
}
}

+ 73
- 0
aspnet-core/src/Acme.BookStore.Application/BookIssued/BookIssueAppService.cs View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Acme.BookStore.BookIssued;
using Volo.Abp.Application.Dtos;
using Acme.BookStore.Permissions;
using Microsoft.AspNetCore.Authorization;
namespace Acme.BookStore.BookIssued
{
public class BookIssueAppService : BookStoreAppService, IBookIssueAppService
{
private readonly IBookIssueRepository _bookIssueRepository;
private readonly BookIssueManager _bookIssueManager;
public BookIssueAppService(
IBookIssueRepository bookIssueRepository,
BookIssueManager bookIssueManager)
{
_bookIssueRepository = bookIssueRepository;
_bookIssueManager = bookIssueManager;
}
public async Task<BookIssueDto> GetAsync(int id)
{
var cus = await _bookIssueRepository.GetAsync(id);
return ObjectMapper.Map<BookIssue, BookIssueDto>(cus);
}
public async Task<PagedResultDto<BookIssueListDto>> GetListAsync()
{
var cus = await _bookIssueRepository.BookIssueList();
return new PagedResultDto<BookIssueListDto>(
cus.Count(),
ObjectMapper.Map<List<BookIssueList>, List<BookIssueListDto>>(cus)
);
}
[Authorize(BookStorePermissions.BookIssued.Create)]
public async Task<BookIssueDto> CreateAsync(BookIssueDto input)
{
var cus = ObjectMapper.Map<BookIssueDto, BookIssue>(input);
var cust = await _bookIssueManager.CreateAsync(cus);
var res = await _bookIssueRepository.InsertAsync(cust);
return ObjectMapper.Map<BookIssue, BookIssueDto>(cust);
}
[Authorize(BookStorePermissions.BookIssued.Edit)]
public async Task UpdateAsync(int id, BookIssueDto input)
{
var cus = await _bookIssueRepository.GetAsync(id);
await _bookIssueRepository.UpdateAsync(cus);
}
[Authorize(BookStorePermissions.BookIssued.Delete)]
public async Task DeleteAsync(int id)
{
await _bookIssueRepository.DeleteAsync(id);
}
}
}

+ 14
- 2
aspnet-core/src/Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs View File

@ -1,11 +1,23 @@
using AutoMapper; using AutoMapper;
using Acme.BookStore.Books;
using Acme.BookStore.Authors;
using Acme.BookStore.Customers;
using Acme.BookStore.BookIssued;
using System.Collections.Generic;
namespace Acme.BookStore; namespace Acme.BookStore;
public class BookStoreApplicationAutoMapperProfile : Profile public class BookStoreApplicationAutoMapperProfile : Profile
{ {
public BookStoreApplicationAutoMapperProfile() public BookStoreApplicationAutoMapperProfile()
{ {
CreateMap<Book, BookDto>();
//CreateMap<List<Book>, List<BookDto>>().ReverseMap();
CreateMap<CreateUpdateBookDto, Book>();
CreateMap<Author, AuthorDto>();
CreateMap<Customer, CustomerDto>().ReverseMap();
// CreateMap<List<Customer>, List<CustomerDto>>().ReverseMap();
CreateMap<BookIssue, BookIssueDto>().ReverseMap();
CreateMap<BookIssueList, BookIssueListDto>().ReverseMap();
/* You can configure your AutoMapper mapping configuration here. /* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations * Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */ * into multiple profile classes for a better organization. */


+ 43
- 0
aspnet-core/src/Acme.BookStore.Application/Books/BookAppService.cs View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Acme.BookStore.Permissions;
namespace Acme.BookStore.Books
{
public class BookAppService :
CrudAppService<
Book, //The Book entity
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdateBookDto>, //Used to create/update a book
IBookAppService //implement the IBookAppService
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookAppService(IRepository<Book, Guid> repository)
: base(repository)
{
_bookRepository = repository;
GetPolicyName = BookStorePermissions.Books.Default;
GetListPolicyName = BookStorePermissions.Books.Default;
CreatePolicyName = BookStorePermissions.Books.Create;
UpdatePolicyName = BookStorePermissions.Books.Edit;
DeletePolicyName = BookStorePermissions.Books.Delete;
}
public async Task<List<BookDto>> GetBookDropDown()
{
var cus = await _bookRepository.GetListAsync();
cus = cus == null ? new List<Book>() : cus;
return ObjectMapper.Map<List<Book>, List<BookDto>>(cus);
}
}
}

+ 86
- 0
aspnet-core/src/Acme.BookStore.Application/Customers/CustomerAppService.cs View File

@ -0,0 +1,86 @@
using Acme.BookStore.Customers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.ObjectMapping;
using Acme.BookStore.Permissions;
using Microsoft.AspNetCore.Authorization;
namespace Acme.BookStore.Customers
{
public class CustomerAppService: BookStoreAppService, ICustomerAppService
{
private readonly ICustomerRepository _customerRepository;
private readonly CustomerManager _customerManager;
public CustomerAppService(
ICustomerRepository customerRepository,
CustomerManager customerManager)
{
_customerRepository = customerRepository;
_customerManager = customerManager;
}
public async Task<CustomerDto> GetAsync(int id)
{
var cus = await _customerRepository.GetAsync(id);
return ObjectMapper.Map<Customer, CustomerDto>(cus);
}
public async Task<List<CustomerDto>> GetcustomerDropDown()
{
var cus = await _customerRepository.GetListAsync();
cus = cus == null ? new List<Customer>() : cus;
return ObjectMapper.Map<List<Customer>, List<CustomerDto>>(cus);
}
public async Task<PagedResultDto<CustomerDto>> GetListAsync()
{
var cus = await _customerRepository.GetListAsync();
return new PagedResultDto<CustomerDto>(
cus.Count(),
ObjectMapper.Map<List<Customer>, List<CustomerDto>>(cus)
);
}
[Authorize(BookStorePermissions.Customers.Create)]
public async Task<CustomerDto> CreateAsync(CustomerDto input)
{
var cus = ObjectMapper.Map<CustomerDto,Customer>(input);
var cust = await _customerManager.CreateAsync(cus);
await _customerRepository.InsertAsync(cust);
return ObjectMapper.Map<Customer, CustomerDto>(cust);
}
[Authorize(BookStorePermissions.Customers.Edit)]
public async Task UpdateAsync(int id, CustomerDto input)
{
var cus = await _customerRepository.GetAsync(id);
if (cus.phone == input.phone)
{
await _customerManager.ChangeNameAsync(cus, input.firstName,input.lastName);
}
await _customerRepository.UpdateAsync(cus);
}
[Authorize(BookStorePermissions.Customers.Delete)]
public async Task DeleteAsync(int id)
{
await _customerRepository.DeleteAsync(id);
}
}
}

+ 1
- 1
aspnet-core/src/Acme.BookStore.DbMigrator/appsettings.json View File

@ -10,7 +10,7 @@
}, },
"BookStore_Swagger": { "BookStore_Swagger": {
"ClientId": "BookStore_Swagger", "ClientId": "BookStore_Swagger",
"RootUrl": "https://localhost:44362"
"RootUrl": "https://localhost:44356"
} }
} }
} }


+ 1
- 1
aspnet-core/src/Acme.BookStore.Domain.Shared/Acme.BookStore.Domain.Shared.csproj View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" /> <Import Project="..\..\common.props" />


+ 12
- 0
aspnet-core/src/Acme.BookStore.Domain.Shared/Authors/AuthorConsts.cs View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Acme.BookStore.Authors
{
public static class AuthorConsts
{
public const int MaxNameLength = 64;
}
}

+ 4
- 0
aspnet-core/src/Acme.BookStore.Domain.Shared/BookStoreDomainErrorCodes.cs View File

@ -2,5 +2,9 @@
public static class BookStoreDomainErrorCodes public static class BookStoreDomainErrorCodes
{ {
public const string AuthorAlreadyExists = "BookStore:00001";
public const string CustomerPhoneAlreadyExists = "BookStore:00002";
public const string BookIssuedAlready = "BookStore:00003";
/* You can add your business exception error codes here, as constants */ /* You can add your business exception error codes here, as constants */
} }

+ 19
- 0
aspnet-core/src/Acme.BookStore.Domain.Shared/Books/BookType.cs View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Acme.BookStore.Books
{
public enum BookType
{
Undefined,
Adventure,
Biography,
Dystopia,
Fantastic,
Horror,
Science,
ScienceFiction,
Poetry
}
}

+ 13
- 0
aspnet-core/src/Acme.BookStore.Domain.Shared/Customers/CustomerConsts.cs View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Acme.BookStore.Customers
{
public class CustomerConsts
{
public const int MaxNameLength = 100;
public const int MaxPhoneLength = 14;
}
}

+ 46
- 1
aspnet-core/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json View File

@ -3,6 +3,51 @@
"texts": { "texts": {
"Menu:Home": "Home", "Menu:Home": "Home",
"Welcome": "Welcome", "Welcome": "Welcome",
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io."
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Menu:BookStore": "Book Store",
"Menu:Books": "Books",
"Actions": "Actions",
"Close": "Close",
"Delete": "Delete",
"Edit": "Edit",
"PublishDate": "Publish date",
"NewBook": "New book",
"Name": "Name",
"Type": "Type",
"Price": "Price",
"CreationTime": "Creation time",
"AreYouSure": "Are you sure?",
"AreYouSureToDelete": "Are you sure you want to delete this item?",
"Enum:BookType.0": "Undefined",
"Enum:BookType.1": "Adventure",
"Enum:BookType.2": "Biography",
"Enum:BookType.3": "Dystopia",
"Enum:BookType.4": "Fantastic",
"Enum:BookType.5": "Horror",
"Enum:BookType.6": "Science",
"Enum:BookType.7": "Science fiction",
"Enum:BookType.8": "Poetry",
"Permission:BookStore": "Book Store",
"Permission:Books": "Book Management",
"Permission:Books.Create": "Creating new books",
"Permission:Books.Edit": "Editing the books",
"Permission:Books.Delete": "Deleting the books",
"BookStore:00001": "There is already an author with the same name: {name}",
"BookStore:00002": "There is already an customer with the same phone: {phone}",
"BookStore:00003": "{book} Book already issued to customer: {customer}",
"Permission:Authors": "Author Management",
"Permission:Authors.Create": "Creating new authors",
"Permission:Authors.Edit": "Editing the authors",
"Permission:Authors.Delete": "Deleting the authors",
"Permission:Customers": "Customer Management",
"Permission:Customers.Create": "Creating new Customer",
"Permission:Customers.Edit": "Editing the Customer",
"Permission:Customers.Delete": "Deleting the Customer",
"Permission:BookIssued": "Book Issued Management",
"Permission:BookIssued.Create": "Creating new Issued Book",
"Permission:BookIssued.Edit": "Editing the Issued Book",
"Permission:BookIssued.Delete": "Deleting the Issued Book"
} }
} }

+ 1
- 1
aspnet-core/src/Acme.BookStore.Domain/Acme.BookStore.Domain.csproj View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" /> <Import Project="..\..\common.props" />


+ 48
- 0
aspnet-core/src/Acme.BookStore.Domain/Authors/Author.cs View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore.Authors
{
public class Author : FullAuditedAggregateRoot<Guid>
{
public string Name { get; private set; }
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
private Author()
{
/* This constructor is for deserialization / ORM purpose */
}
internal Author(
Guid id,
string name,
DateTime birthDate,
string? shortBio = null)
: base(id)
{
SetName(name);
BirthDate = birthDate;
ShortBio = shortBio;
}
internal Author ChangeName(string name)
{
SetName(name);
return this;
}
private void SetName(string name)
{
Name = Check.NotNullOrWhiteSpace(
name,
nameof(name),
maxLength: AuthorConsts.MaxNameLength
);
}
}
}

+ 18
- 0
aspnet-core/src/Acme.BookStore.Domain/Authors/AuthorAlreadyExistsException.cs View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
namespace Acme.BookStore.Authors
{
public class AuthorAlreadyExistsException : BusinessException
{
public AuthorAlreadyExistsException(string name)
: base(BookStoreDomainErrorCodes.AuthorAlreadyExists)
{
WithData("name", name);
}
}
}

+ 57
- 0
aspnet-core/src/Acme.BookStore.Domain/Authors/AuthorManager.cs View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Services;
namespace Acme.BookStore.Authors
{
public class AuthorManager : DomainService
{
private readonly IAuthorRepository _authorRepository;
public AuthorManager(IAuthorRepository authorRepository)
{
_authorRepository = authorRepository;
}
public async Task<Author> CreateAsync(
string name,
DateTime birthDate,
string? shortBio = null)
{
Check.NotNullOrWhiteSpace(name, nameof(name));
var existingAuthor = await _authorRepository.FindByNameAsync(name);
if (existingAuthor != null)
{
throw new AuthorAlreadyExistsException(name);
}
return new Author(
GuidGenerator.Create(),
name,
birthDate,
shortBio
);
}
public async Task ChangeNameAsync(
Author author,
string newName)
{
Check.NotNull(author, nameof(author));
Check.NotNullOrWhiteSpace(newName, nameof(newName));
var existingAuthor = await _authorRepository.FindByNameAsync(newName);
if (existingAuthor != null && existingAuthor.Id != author.Id)
{
throw new AuthorAlreadyExistsException(newName);
}
author.ChangeName(newName);
}
}
}

+ 21
- 0
aspnet-core/src/Acme.BookStore.Domain/Authors/IAuthorRepository.cs View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore.Authors
{
public interface IAuthorRepository : IRepository<Author, Guid>
{
Task<Author> FindByNameAsync(string name);
Task<List<Author>> GetListAsync(
int skipCount,
int maxResultCount,
string sorting,
string filter = null
);
}
}

+ 33
- 0
aspnet-core/src/Acme.BookStore.Domain/BookIssued/BookIssue.cs View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore.BookIssued
{
public class BookIssue : FullAuditedAggregateRoot<int>
{
public Guid bookId { get; set; }
public int customerId { get; set; }
private BookIssue()
{
/* This constructor is for deserialization / ORM purpose */
}
internal BookIssue(int id, Guid bookId, int customerId) : base(id)
{
this.bookId = bookId;
this.customerId = customerId;
}
}
public class BookIssueList
{
public int bookIssueId { get; set; }
public string bookName { get; set; }
public string customerName { get; set; }
public DateTime issueDate { get; set; }
}
}

+ 19
- 0
aspnet-core/src/Acme.BookStore.Domain/BookIssued/BookIssueErrorException.cs View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
namespace Acme.BookStore.BookIssued
{
public class BookIssueErrorException : BusinessException
{
public BookIssueErrorException(string customerName, string bookName)
: base(BookStoreDomainErrorCodes.BookIssuedAlready)
{
WithData("customer", customerName);
WithData("book", bookName);
}
}
}

+ 36
- 0
aspnet-core/src/Acme.BookStore.Domain/BookIssued/BookIssueManager.cs View File

@ -0,0 +1,36 @@
using Acme.BookStore.Customers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Services;
namespace Acme.BookStore.BookIssued
{
public class BookIssueManager : DomainService
{
private readonly IBookIssueRepository _bookIssueRepository;
public BookIssueManager(IBookIssueRepository bookIssueRepository)
{
_bookIssueRepository = bookIssueRepository;
}
public async Task<BookIssue> CreateAsync(
BookIssue bookissue)
{
var existingBookIssue = await _bookIssueRepository.FindBookIssueCustomer(bookissue.customerId,bookissue.bookId);
if (existingBookIssue != null)
{
throw new BookIssueErrorException(existingBookIssue.customerName, existingBookIssue.bookName);
}
return new BookIssue(
await _bookIssueRepository.NewBookIssueId(),
bookissue.bookId,
bookissue.customerId
);
}
}
}

+ 17
- 0
aspnet-core/src/Acme.BookStore.Domain/BookIssued/IBookIssueRepository.cs View File

@ -0,0 +1,17 @@
using Acme.BookStore.Customers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore.BookIssued
{
public interface IBookIssueRepository : IRepository<BookIssue, int>
{
Task<BookIssueList> FindBookIssueCustomer(int customerId, Guid bookId);
Task<int> NewBookIssueId();
Task<List<BookIssueList>> BookIssueList();
}
}

+ 100
- 0
aspnet-core/src/Acme.BookStore.Domain/BookStoreDataSeederContributor.cs View File

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Acme.BookStore.Books;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Acme.BookStore.Authors;
using Acme.BookStore.Customers;
namespace Acme.BookStore
{
public class BookStoreDataSeederContributor
: IDataSeedContributor, ITransientDependency
{
private readonly IRepository<Book, Guid> _bookRepository;
private readonly IAuthorRepository _authorRepository;
private readonly ICustomerRepository _customerRepository;
private readonly AuthorManager _authorManager;
private readonly CustomerManager _customerManager;
public BookStoreDataSeederContributor(IRepository<Book, Guid> bookRepository,
IAuthorRepository authorRepository,
AuthorManager authorManager,
ICustomerRepository customerRepository,
CustomerManager customerManager
)
{
_bookRepository = bookRepository;
_authorRepository = authorRepository;
_authorManager = authorManager;
_customerRepository = customerRepository;
_customerManager = customerManager;
}
public async Task SeedAsync(DataSeedContext context)
{
if (await _bookRepository.GetCountAsync() <= 0)
{
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
if (await _authorRepository.GetCountAsync() <= 0)
{
await _authorRepository.InsertAsync(
await _authorManager.CreateAsync(
"George Orwell",
new DateTime(1903, 06, 25),
"Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)."
)
);
await _authorRepository.InsertAsync(
await _authorManager.CreateAsync(
"Douglas Adams",
new DateTime(1952, 03, 11),
"Douglas Adams was an English author, screenwriter, essayist, humorist, satirist and dramatist. Adams was an advocate for environmentalism and conservation, a lover of fast cars, technological innovation and the Apple Macintosh, and a self-proclaimed 'radical atheist'."
)
);
}
if (await _customerRepository.GetCountAsync() <= 0)
{
Customer customer = new Customer(1, "soumen", "pal", "9091184026", "haripal");
await _customerRepository.InsertAsync(
await _customerManager.CreateAsync(customer)
);
}
}
}
}

+ 20
- 0
aspnet-core/src/Acme.BookStore.Domain/Books/Book.cs View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore.Books
{
public class Book : AuditedAggregateRoot<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}

+ 60
- 0
aspnet-core/src/Acme.BookStore.Domain/Customers/Customer.cs View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore.Customers
{
public class Customer : FullAuditedAggregateRoot<int>
{
public string firstName { get; set; }
public string lastName { get; set; }
public string phone { get; set; }
public string address { get; set; }
private Customer()
{
/* This constructor is for deserialization / ORM purpose */
}
internal Customer(int id, string firstName, string lastName, string phone, string address) : base(id)
{
this.firstName = firstName;
this.lastName = lastName;
this.phone = phone;
this.address = address;
}
internal Customer ChangeFirstName(string firstname)
{
SetFirstName(firstname);
return this;
}
private void SetFirstName(string firstName)
{
firstName = Check.NotNullOrWhiteSpace(
firstName,
nameof(firstName),
maxLength: CustomerConsts.MaxNameLength
);
this.firstName = firstName;
}
internal Customer ChangeLastName(string lastname)
{
SetLastName(lastname);
return this;
}
private void SetLastName(string lastname)
{
lastname = Check.NotNullOrWhiteSpace(
lastname,
nameof(lastname),
maxLength: CustomerConsts.MaxNameLength
);
this.lastName = lastname;
}
}
}

+ 18
- 0
aspnet-core/src/Acme.BookStore.Domain/Customers/CustomerErrorException.cs View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
namespace Acme.BookStore.Customers
{
public class CustomerErrorException : BusinessException
{
public CustomerErrorException(string phone)
: base(BookStoreDomainErrorCodes.CustomerPhoneAlreadyExists)
{
WithData("phone", phone);
}
}
}

+ 55
- 0
aspnet-core/src/Acme.BookStore.Domain/Customers/CustomerManager.cs View File

@ -0,0 +1,55 @@
using Acme.BookStore.Authors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Guids;
using Volo.Abp;
using Volo.Abp.Domain.Services;
namespace Acme.BookStore.Customers
{
public class CustomerManager : DomainService
{
private readonly ICustomerRepository _customerRepository;
public CustomerManager(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
public async Task<Customer> CreateAsync(
Customer customer)
{
Check.NotNullOrWhiteSpace(customer.firstName, nameof(customer.firstName));
Check.NotNullOrWhiteSpace(customer.lastName, nameof(customer.lastName));
var existingAuthor = await _customerRepository.FindByPhoneAsync(customer.phone);
if (existingAuthor != null)
{
throw new CustomerErrorException(customer.phone);
}
return new Customer(
await _customerRepository.NewCustomerId(),
customer.firstName,
customer.lastName,
customer.phone,
customer.address
);
}
public async Task ChangeNameAsync(
Customer customer,
string firstName,string lastName)
{
Check.NotNull(customer, nameof(customer));
Check.NotNullOrWhiteSpace(customer.firstName, nameof(customer.firstName));
Check.NotNullOrWhiteSpace(customer.lastName, nameof(customer.lastName));
customer.ChangeFirstName(firstName);
customer.ChangeLastName(lastName);
}
}
}

+ 16
- 0
aspnet-core/src/Acme.BookStore.Domain/Customers/ICustomerRepository.cs View File

@ -0,0 +1,16 @@
using Acme.BookStore.Authors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore.Customers
{
public interface ICustomerRepository : IRepository<Customer, int>
{
Task<Customer> FindByPhoneAsync(string phone);
Task<int> NewCustomerId();
}
}

+ 1
- 1
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Acme.BookStore.EntityFrameworkCore.csproj View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" /> <Import Project="..\..\common.props" />


+ 56
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Authors/EfCoreAuthorRepository.cs View File

@ -0,0 +1,56 @@
using Acme.BookStore.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Acme.BookStore.Authors
{
public class EfCoreAuthorRepository
: EfCoreRepository<BookStoreDbContext, Author, Guid>,
IAuthorRepository
{
public EfCoreAuthorRepository(
IDbContextProvider<BookStoreDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<Author> FindByNameAsync(string name)
{
var dbSet = await GetDbSetAsync();
return await dbSet.FirstOrDefaultAsync(author => author.Name == name);
}
public async Task<List<Author>> GetListAsync(
int skipCount,
int maxResultCount,
string sorting,
string filter = null)
{
var dbSet = await GetDbSetAsync();
return await dbSet.WhereIf(
!filter.IsNullOrEmpty(),
author=>author.Name.Contains(filter)).OrderBy(author=> author.Name).Skip(skipCount).Take(maxResultCount).ToListAsync();
//return await dbSet
// .WhereIf(
// !filter.IsNullOrWhiteSpace(),
// author => author.Name.Contains(filter)
// )
// .OrderBy(sorting)
// .Skip(skipCount)
// .Take(maxResultCount)
// .ToListAsync();
}
}
}

+ 85
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/BookIssued/EfCoreBookIssueRepository.cs View File

@ -0,0 +1,85 @@
using Acme.BookStore.Customers;
using Acme.BookStore.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Polly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
namespace Acme.BookStore.BookIssued
{
public class EfCoreBookIssueRepository : EfCoreRepository<BookStoreDbContext, BookIssue, int>,
IBookIssueRepository
{
private readonly IDataFilter _dataFilter;
public EfCoreBookIssueRepository(
IDbContextProvider<BookStoreDbContext> dbContextProvider, IDataFilter dataFilter
)
: base(dbContextProvider)
{
_dataFilter = dataFilter;
}
public async Task<BookIssueList> FindBookIssueCustomer(int customerId, Guid bookId)
{
//var dbSet = await GetDbSetAsync();
var dbContext = await GetDbContextAsync();
List<BookIssueList> item = (
from bi in dbContext.bookIssues
join cu in dbContext.Customers on bi.customerId equals cu.Id
join bk in dbContext.Books on bi.bookId equals bk.Id
where (bi.customerId == customerId && bi.bookId == bookId && bi.IsDeleted == false)
select new BookIssueList
{
bookIssueId = bi.Id,
bookName = bk.Name,
customerName = cu.firstName + " " + cu.lastName,
issueDate = bi.CreationTime
}).ToList();
return item == null? null : item.FirstOrDefault();
}
public async Task<int> NewBookIssueId()
{
using (_dataFilter.Disable<ISoftDelete>())
{
var dbSet = await GetDbSetAsync();
var values = await dbSet.MaxAsync(u => (int?)u.Id);
return values == null ? 0 + 1 : (int)values + 1;
}
}
public async Task<List<BookIssueList>> BookIssueList()
{
var dbContext = await GetDbContextAsync();
List<BookIssueList> item = (
from bi in dbContext.bookIssues
join cu in dbContext.Customers on bi.customerId equals cu.Id
join bk in dbContext.Books on bi.bookId equals bk.Id
select new BookIssueList
{
bookIssueId = bi.Id,
bookName = bk.Name,
customerName = cu.firstName + " " + cu.lastName,
issueDate = bi.CreationTime
}).ToList();
return item;
}
}
}

+ 40
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Customers/EfCoreCustomerRepository.cs View File

@ -0,0 +1,40 @@
using Acme.BookStore.Authors;
using Acme.BookStore.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Acme.BookStore.Customers
{
public class EfCoreCustomerRepository : EfCoreRepository<BookStoreDbContext, Customer, int>,
ICustomerRepository
{
public EfCoreCustomerRepository(
IDbContextProvider<BookStoreDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<Customer> FindByPhoneAsync(string phone)
{
var dbSet = await GetDbSetAsync();
return await dbSet.FirstOrDefaultAsync(cust => cust.phone == phone);
}
public async Task<int> NewCustomerId()
{
var dbSet = await GetDbSetAsync();
var values = await dbSet.MaxAsync(u => (int?)u.Id);
return values == null ? 0 +1: (int)values + 1;
}
}
}

+ 65
- 1
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs View File

@ -1,9 +1,14 @@
using Microsoft.EntityFrameworkCore;
using Acme.BookStore.Authors;
using Acme.BookStore.BookIssued;
using Acme.BookStore.Books;
using Acme.BookStore.Customers;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore; using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.FeatureManagement.EntityFrameworkCore; using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity; using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.Identity.EntityFrameworkCore;
@ -50,6 +55,12 @@ public class BookStoreDbContext :
// Tenant Management // Tenant Management
public DbSet<Tenant> Tenants { get; set; } public DbSet<Tenant> Tenants { get; set; }
public DbSet<TenantConnectionString> TenantConnectionStrings { get; set; } public DbSet<TenantConnectionString> TenantConnectionStrings { get; set; }
public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<BookIssue> bookIssues { get; set; }
#endregion #endregion
@ -74,6 +85,59 @@ public class BookStoreDbContext :
builder.ConfigureFeatureManagement(); builder.ConfigureFeatureManagement();
builder.ConfigureTenantManagement(); builder.ConfigureTenantManagement();
builder.Entity<Book>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "Books",
BookStoreConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
});
builder.Entity<Author>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "Authors",
BookStoreConsts.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.Name)
.IsRequired()
.HasMaxLength(AuthorConsts.MaxNameLength);
b.HasIndex(x => x.Name);
});
builder.Entity<Customer>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "Customers",
BookStoreConsts.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.firstName)
.IsRequired()
.HasMaxLength(CustomerConsts.MaxNameLength);
b.Property(x => x.lastName)
.IsRequired()
.HasMaxLength(CustomerConsts.MaxNameLength);
b.Property(x => x.phone)
.IsRequired()
.HasMaxLength(CustomerConsts.MaxPhoneLength);
});
builder.Entity<BookIssue>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "BookIssued",
"BKN");
b.ConfigureByConvention();
});
/* Configure your own tables/entities inside here */ /* Configure your own tables/entities inside here */
//builder.Entity<YourEntity>(b => //builder.Entity<YourEntity>(b =>


aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240610143520_Initial.Designer.cs → aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240604143520_Initial.Designer.cs View File


aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240610143520_Initial.cs → aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240604143520_Initial.cs View File


+ 2011
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605054852_Created_Book_Entity.Designer.cs
File diff suppressed because it is too large
View File


+ 43
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605054852_Created_Book_Entity.cs View File

@ -0,0 +1,43 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Acme.BookStore.Migrations
{
/// <inheritdoc />
public partial class Created_Book_Entity : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppBooks",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Type = table.Column<int>(type: "int", nullable: false),
PublishDate = table.Column<DateTime>(type: "datetime2", nullable: false),
Price = table.Column<float>(type: "real", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppBooks", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppBooks");
}
}
}

+ 2077
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605111342_Added_Authors.Designer.cs
File diff suppressed because it is too large
View File


+ 50
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605111342_Added_Authors.cs View File

@ -0,0 +1,50 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Acme.BookStore.Migrations
{
/// <inheritdoc />
public partial class Added_Authors : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppAuthors",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
BirthDate = table.Column<DateTime>(type: "datetime2", nullable: false),
ShortBio = table.Column<string>(type: "nvarchar(max)", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppAuthors", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_AppAuthors_Name",
table: "AppAuthors",
column: "Name");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppAuthors");
}
}
}

+ 2151
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606070329_Added_Customers.Designer.cs
File diff suppressed because it is too large
View File


+ 47
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606070329_Added_Customers.cs View File

@ -0,0 +1,47 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Acme.BookStore.Migrations
{
/// <inheritdoc />
public partial class Added_Customers : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AppCustomers",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
firstName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
lastName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
phone = table.Column<string>(type: "nvarchar(14)", maxLength: 14, nullable: false),
address = table.Column<string>(type: "nvarchar(max)", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppCustomers", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppCustomers");
}
}
}

+ 2212
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606100414_Added_BookIssued.Designer.cs
File diff suppressed because it is too large
View File


+ 50
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606100414_Added_BookIssued.cs View File

@ -0,0 +1,50 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Acme.BookStore.Migrations
{
/// <inheritdoc />
public partial class Added_BookIssued : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.EnsureSchema(
name: "BKN");
migrationBuilder.CreateTable(
name: "AppBookIssued",
schema: "BKN",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
bookId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
customerId = table.Column<int>(type: "int", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AppBookIssued", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AppBookIssued",
schema: "BKN");
}
}
}

+ 253
- 0
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/BookStoreDbContextModelSnapshot.cs View File

@ -24,6 +24,259 @@ namespace Acme.BookStore.Migrations
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("Acme.BookStore.Authors.Author", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("BirthDate")
.HasColumnType("datetime2");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("nvarchar(64)");
b.Property<string>("ShortBio")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("Name");
b.ToTable("AppAuthors", (string)null);
});
modelBuilder.Entity("Acme.BookStore.BookIssued.BookIssue", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<Guid>("bookId")
.HasColumnType("uniqueidentifier");
b.Property<int>("customerId")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("AppBookIssued", "BKN");
});
modelBuilder.Entity("Acme.BookStore.Books.Book", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<float>("Price")
.HasColumnType("real");
b.Property<DateTime>("PublishDate")
.HasColumnType("datetime2");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("AppBooks", (string)null);
});
modelBuilder.Entity("Acme.BookStore.Customers.Customer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("address")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("firstName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("lastName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("phone")
.IsRequired()
.HasMaxLength(14)
.HasColumnType("nvarchar(14)");
b.HasKey("Id");
b.ToTable("AppCustomers", (string)null);
});
modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")


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

Loading…
Cancel
Save