initallCodeAfterError
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
|||||||
# ---> VisualStudio
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
##
|
##
|
||||||
|
@ -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"],
|
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
|
||||||
"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,7 +112,9 @@
|
|||||||
},
|
},
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": [],
|
||||||
|
"serviceWorker": true,
|
||||||
|
"ngswConfigPath": "ngsw-config.json"
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
@ -173,7 +175,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"],
|
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
|
||||||
"styles": ["src/styles.scss"],
|
"styles": ["src/styles.scss"],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
}
|
}
|
||||||
|
30
angular/ngsw-config.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
|
||||||
|
"index": "/index.html",
|
||||||
|
"assetGroups": [
|
||||||
|
{
|
||||||
|
"name": "app",
|
||||||
|
"installMode": "prefetch",
|
||||||
|
"resources": {
|
||||||
|
"files": [
|
||||||
|
"/favicon.ico",
|
||||||
|
"/index.html",
|
||||||
|
"/manifest.webmanifest",
|
||||||
|
"/*.css",
|
||||||
|
"/*.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "assets",
|
||||||
|
"installMode": "lazy",
|
||||||
|
"updateMode": "prefetch",
|
||||||
|
"resources": {
|
||||||
|
"files": [
|
||||||
|
"/assets/**",
|
||||||
|
"/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -30,6 +30,7 @@
|
|||||||
"@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,9 +25,6 @@ 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,6 +17,7 @@ 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,
|
||||||
@ -39,7 +40,13 @@ import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account';
|
|||||||
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],
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
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 { }
|
|
@ -1,97 +0,0 @@
|
|||||||
<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>
|
|
@ -1,23 +0,0 @@
|
|||||||
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();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,83 +0,0 @@
|
|||||||
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());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
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 { }
|
|
@ -1,12 +0,0 @@
|
|||||||
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 { }
|
|
@ -1,122 +0,0 @@
|
|||||||
<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>
|
|
@ -1,23 +0,0 @@
|
|||||||
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();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,88 +0,0 @@
|
|||||||
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());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
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 { }
|
|
@ -1,13 +0,0 @@
|
|||||||
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 { }
|
|
@ -1,101 +0,0 @@
|
|||||||
<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>
|
|
@ -1,23 +0,0 @@
|
|||||||
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();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,92 +0,0 @@
|
|||||||
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());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
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 { }
|
|
@ -1,17 +0,0 @@
|
|||||||
# 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.
|
|
@ -1,56 +0,0 @@
|
|||||||
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) {}
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './author.service';
|
|
||||||
export * from './models';
|
|
@ -1,23 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
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) {}
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './book-issue.service';
|
|
||||||
export * from './models';
|
|
@ -1,13 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
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);
|
|
@ -1,64 +0,0 @@
|
|||||||
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) {}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
export * from './book-type.enum';
|
|
||||||
export * from './book.service';
|
|
||||||
export * from './models';
|
|
@ -1,16 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
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) {}
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './customer.service';
|
|
||||||
export * from './models';
|
|
@ -1,8 +0,0 @@
|
|||||||
import type { EntityDto } from '@abp/ng.core';
|
|
||||||
|
|
||||||
export interface CustomerDto extends EntityDto<number> {
|
|
||||||
firstName?: string;
|
|
||||||
lastName?: string;
|
|
||||||
phone?: string;
|
|
||||||
address?: string;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
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,39 +15,6 @@ 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,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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',
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
BIN
angular/src/assets/icons/icon-128x128.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
angular/src/assets/icons/icon-144x144.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
angular/src/assets/icons/icon-152x152.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
angular/src/assets/icons/icon-192x192.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
angular/src/assets/icons/icon-384x384.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
angular/src/assets/icons/icon-512x512.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
angular/src/assets/icons/icon-72x72.png
Normal file
After Width: | Height: | Size: 792 B |
BIN
angular/src/assets/icons/icon-96x96.png
Normal file
After Width: | Height: | Size: 958 B |
@ -10,7 +10,7 @@ export const environment = {
|
|||||||
logoUrl: '',
|
logoUrl: '',
|
||||||
},
|
},
|
||||||
oAuthConfig: {
|
oAuthConfig: {
|
||||||
issuer: 'https://localhost:44356/',
|
issuer: 'https://localhost:44362/',
|
||||||
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:44356',
|
url: 'https://localhost:44362',
|
||||||
rootNamespace: 'Acme.BookStore',
|
rootNamespace: 'Acme.BookStore',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -10,7 +10,7 @@ export const environment = {
|
|||||||
logoUrl: '',
|
logoUrl: '',
|
||||||
},
|
},
|
||||||
oAuthConfig: {
|
oAuthConfig: {
|
||||||
issuer: 'https://localhost:44356/',
|
issuer: 'https://localhost:44362/',
|
||||||
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:44356',
|
url: 'https://localhost:44362',
|
||||||
rootNamespace: 'Acme.BookStore',
|
rootNamespace: 'Acme.BookStore',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
<!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"/>
|
||||||
</head>
|
<link rel="manifest" href="manifest.webmanifest">
|
||||||
|
<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>
|
||||||
</body>
|
<noscript>Please enable JavaScript to continue using this application.</noscript>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
59
angular/src/manifest.webmanifest
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"name": "BookStore",
|
||||||
|
"short_name": "BookStore",
|
||||||
|
"theme_color": "#1976d2",
|
||||||
|
"background_color": "#fafafa",
|
||||||
|
"display": "standalone",
|
||||||
|
"scope": "./",
|
||||||
|
"start_url": "./",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "assets/icons/icon-72x72.png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "assets/icons/icon-96x96.png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "assets/icons/icon-128x128.png",
|
||||||
|
"sizes": "128x128",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "assets/icons/icon-144x144.png",
|
||||||
|
"sizes": "144x144",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "assets/icons/icon-152x152.png",
|
||||||
|
"sizes": "152x152",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "assets/icons/icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "assets/icons/icon-384x384.png",
|
||||||
|
"sizes": "384x384",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "assets/icons/icon-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1003
angular/yarn.lock
@ -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 9d3dbfba-a400-4e7c-b7a2-779cd1b0c44f
|
dotnet dev-certs https -v -ep openiddict.pfx -p 70790fc6-826d-4901-86d8-1b6ae21c9efb
|
||||||
```
|
```
|
||||||
|
|
||||||
> `9d3dbfba-a400-4e7c-b7a2-779cd1b0c44f` is the password of the certificate, you can change it to any password you want.
|
> `70790fc6-826d-4901-86d8-1b6ae21c9efb` 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" />
|
||||||
|
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
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; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
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,40 +11,6 @@ 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,35 +4,6 @@ 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" />
|
||||||
|
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
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,23 +1,11 @@
|
|||||||
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. */
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
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:44356"
|
"RootUrl": "https://localhost:44362"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Import Project="..\..\common.props" />
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Authors
|
|
||||||
{
|
|
||||||
public static class AuthorConsts
|
|
||||||
{
|
|
||||||
public const int MaxNameLength = 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -2,9 +2,5 @@
|
|||||||
|
|
||||||
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 */
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
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,51 +3,6 @@
|
|||||||
"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" />
|
||||||
|
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
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; }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
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)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
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" />
|
||||||
|
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
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,14 +1,9 @@
|
|||||||
using Acme.BookStore.Authors;
|
using Microsoft.EntityFrameworkCore;
|
||||||
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;
|
||||||
@ -55,12 +50,6 @@ 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
|
||||||
|
|
||||||
@ -85,59 +74,6 @@ 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 =>
|
||||||
|