SP_10062024_CodePush
This commit is contained in:
parent
55dd84f62a
commit
c6725c0c01
@ -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": [],
|
"scripts": []
|
||||||
"serviceWorker": true,
|
|
||||||
"ngswConfigPath": "ngsw-config.json"
|
|
||||||
},
|
},
|
||||||
"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": []
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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({
|
||||||
|
@ -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(),
|
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'
|
|
||||||
})
|
|
||||||
],
|
],
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
providers: [APP_ROUTE_PROVIDER],
|
providers: [APP_ROUTE_PROVIDER],
|
||||||
|
12
angular/src/app/book-issue/book-issue-routing.module.ts
Normal file
12
angular/src/app/book-issue/book-issue-routing.module.ts
Normal 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
angular/src/app/book-issue/book-issue.component.html
Normal file
97
angular/src/app/book-issue/book-issue.component.html
Normal 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>
|
23
angular/src/app/book-issue/book-issue.component.spec.ts
Normal file
23
angular/src/app/book-issue/book-issue.component.spec.ts
Normal 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
angular/src/app/book-issue/book-issue.component.ts
Normal file
83
angular/src/app/book-issue/book-issue.component.ts
Normal 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
angular/src/app/book-issue/book-issue.module.ts
Normal file
19
angular/src/app/book-issue/book-issue.module.ts
Normal 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
angular/src/app/book/book-routing.module.ts
Normal file
12
angular/src/app/book/book-routing.module.ts
Normal 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
angular/src/app/book/book.component.html
Normal file
122
angular/src/app/book/book.component.html
Normal 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
angular/src/app/book/book.component.scss
Normal file
0
angular/src/app/book/book.component.scss
Normal file
23
angular/src/app/book/book.component.spec.ts
Normal file
23
angular/src/app/book/book.component.spec.ts
Normal 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
angular/src/app/book/book.component.ts
Normal file
88
angular/src/app/book/book.component.ts
Normal 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
angular/src/app/book/book.module.ts
Normal file
21
angular/src/app/book/book.module.ts
Normal 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
angular/src/app/customer/customer-routing.module.ts
Normal file
13
angular/src/app/customer/customer-routing.module.ts
Normal 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
angular/src/app/customer/customer.component.html
Normal file
101
angular/src/app/customer/customer.component.html
Normal 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
angular/src/app/customer/customer.component.scss
Normal file
0
angular/src/app/customer/customer.component.scss
Normal file
23
angular/src/app/customer/customer.component.spec.ts
Normal file
23
angular/src/app/customer/customer.component.spec.ts
Normal 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
angular/src/app/customer/customer.component.ts
Normal file
92
angular/src/app/customer/customer.component.ts
Normal 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
angular/src/app/customer/customer.module.ts
Normal file
20
angular/src/app/customer/customer.module.ts
Normal 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
angular/src/app/proxy/README.md
Normal file
17
angular/src/app/proxy/README.md
Normal 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
angular/src/app/proxy/authors/author.service.ts
Normal file
56
angular/src/app/proxy/authors/author.service.ts
Normal 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
angular/src/app/proxy/authors/index.ts
Normal file
2
angular/src/app/proxy/authors/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './author.service';
|
||||||
|
export * from './models';
|
23
angular/src/app/proxy/authors/models.ts
Normal file
23
angular/src/app/proxy/authors/models.ts
Normal 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
angular/src/app/proxy/book-issued/book-issue.service.ts
Normal file
55
angular/src/app/proxy/book-issued/book-issue.service.ts
Normal 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
angular/src/app/proxy/book-issued/index.ts
Normal file
2
angular/src/app/proxy/book-issued/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './book-issue.service';
|
||||||
|
export * from './models';
|
13
angular/src/app/proxy/book-issued/models.ts
Normal file
13
angular/src/app/proxy/book-issued/models.ts
Normal 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
angular/src/app/proxy/books/book-type.enum.ts
Normal file
15
angular/src/app/proxy/books/book-type.enum.ts
Normal 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
angular/src/app/proxy/books/book.service.ts
Normal file
64
angular/src/app/proxy/books/book.service.ts
Normal 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
angular/src/app/proxy/books/index.ts
Normal file
3
angular/src/app/proxy/books/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './book-type.enum';
|
||||||
|
export * from './book.service';
|
||||||
|
export * from './models';
|
16
angular/src/app/proxy/books/models.ts
Normal file
16
angular/src/app/proxy/books/models.ts
Normal 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
angular/src/app/proxy/customers/customer.service.ts
Normal file
63
angular/src/app/proxy/customers/customer.service.ts
Normal 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
angular/src/app/proxy/customers/index.ts
Normal file
2
angular/src/app/proxy/customers/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './customer.service';
|
||||||
|
export * from './models';
|
8
angular/src/app/proxy/customers/models.ts
Normal file
8
angular/src/app/proxy/customers/models.ts
Normal 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
angular/src/app/proxy/generate-proxy.json
Normal file
10619
angular/src/app/proxy/generate-proxy.json
Normal file
File diff suppressed because it is too large
Load Diff
5
angular/src/app/proxy/index.ts
Normal file
5
angular/src/app/proxy/index.ts
Normal 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 };
|
@ -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',
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -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"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico"/>
|
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||||
<link rel="manifest" href="manifest.webmanifest">
|
</head>
|
||||||
<meta name="theme-color" content="#1976d2">
|
|
||||||
</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>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Import Project="..\..\common.props" />
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Import Project="..\..\common.props" />
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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. */
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"BookStore_Swagger": {
|
"BookStore_Swagger": {
|
||||||
"ClientId": "BookStore_Swagger",
|
"ClientId": "BookStore_Swagger",
|
||||||
"RootUrl": "https://localhost:44362"
|
"RootUrl": "https://localhost:44356"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Import Project="..\..\common.props" />
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Import Project="..\..\common.props" />
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
48
aspnet-core/src/Acme.BookStore.Domain/Authors/Author.cs
Normal file
48
aspnet-core/src/Acme.BookStore.Domain/Authors/Author.cs
Normal 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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
aspnet-core/src/Acme.BookStore.Domain/Books/Book.cs
Normal file
20
aspnet-core/src/Acme.BookStore.Domain/Books/Book.cs
Normal 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
aspnet-core/src/Acme.BookStore.Domain/Customers/Customer.cs
Normal file
60
aspnet-core/src/Acme.BookStore.Domain/Customers/Customer.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Import Project="..\..\common.props" />
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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 =>
|
||||||
|
2011
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605054852_Created_Book_Entity.Designer.cs
generated
Normal file
2011
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605054852_Created_Book_Entity.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605111342_Added_Authors.Designer.cs
generated
Normal file
2077
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240605111342_Added_Authors.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606070329_Added_Customers.Designer.cs
generated
Normal file
2151
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606070329_Added_Customers.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606100414_Added_BookIssued.Designer.cs
generated
Normal file
2212
aspnet-core/src/Acme.BookStore.EntityFrameworkCore/Migrations/20240606100414_Added_BookIssued.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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 have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user