@ -0,0 +1,12 @@ | |||||
import { NgModule } from '@angular/core'; | |||||
import { RouterModule, Routes } from '@angular/router'; | |||||
import { BookIssueComponent } from './book-issue.component'; | |||||
import { authGuard, permissionGuard } from '@abp/ng.core'; | |||||
const routes: Routes = [{ path: '', component: BookIssueComponent,canActivate: [authGuard, permissionGuard] }]; | |||||
@NgModule({ | |||||
imports: [RouterModule.forChild(routes)], | |||||
exports: [RouterModule] | |||||
}) | |||||
export class BookIssueRoutingModule { } |
@ -0,0 +1,97 @@ | |||||
<div class="card"> | |||||
<div class="card-header"> | |||||
<div class="row"> | |||||
<div class="col col-md-6"> | |||||
<h5 class="card-title"> | |||||
{{ 'Book-Issue' | abpLocalization }} | |||||
</h5> | |||||
</div> | |||||
<div class="text-end col col-md-6"> | |||||
<!-- Add the "new book" button here --> | |||||
<div class="text-lg-end pt-2"> | |||||
<button id="create" class="btn btn-primary" type="button" (click)="createBookIssue()"> | |||||
<i class="fa fa-plus me-1"></i> | |||||
<span>{{ "New Book Issue" | abpLocalization }}</span> | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="card-body"> | |||||
<ngx-datatable [rows]="bookIssueList.items" [count]="bookIssueList.totalCount" [list]="list" default> | |||||
<ngx-datatable-column | |||||
[name]="'::Actions' | abpLocalization" | |||||
[maxWidth]="150" | |||||
[sortable]="false" | |||||
> | |||||
<ng-template let-row="row" ngx-datatable-cell-template> | |||||
<div ngbDropdown container="body" class="d-inline-block"> | |||||
<button | |||||
class="btn btn-primary btn-sm dropdown-toggle" | |||||
data-toggle="dropdown" | |||||
aria-haspopup="true" | |||||
ngbDropdownToggle | |||||
> | |||||
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }} | |||||
</button> | |||||
<div ngbDropdownMenu> | |||||
<button ngbDropdownItem (click)="delete(row.bookIssueId)"> | |||||
{{ 'un Issue' | abpLocalization }} | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</ng-template> | |||||
</ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'Book Name' | abpLocalization" prop="bookName"></ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'Customer Name' | abpLocalization" prop="customerName"> | |||||
</ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'Issue Date' | abpLocalization" prop="issueDate"> | |||||
<ng-template let-row="row" ngx-datatable-cell-template> | |||||
{{ row.issueDate | date }} | |||||
</ng-template> | |||||
</ngx-datatable-column> | |||||
</ngx-datatable> | |||||
</div> | |||||
</div> | |||||
<!-- Add the modal here --> | |||||
<abp-modal [(visible)]="isModalOpen"> | |||||
<ng-template #abpHeader> | |||||
<h3> Book Issued </h3> | |||||
</ng-template> | |||||
<ng-template #abpBody> | |||||
<form [formGroup]="form" (ngSubmit)="save()"> | |||||
<div class="mt-2"> | |||||
<label for="book-type">Book Name</label><span> * </span> | |||||
<select class="form-control" id="book-type" formControlName="bookId"> | |||||
<option [ngValue]="null">Select a book name</option> | |||||
<option [ngValue]="book.id" *ngFor="let book of dropDownbook"> {{ book.name }}</option> | |||||
</select> | |||||
</div> | |||||
<div class="mt-2"> | |||||
<label for="customer-name">Customer Name</label><span> * </span> | |||||
<select class="form-control" id="customer-name" formControlName="customerId"> | |||||
<option [ngValue]="null">Select a customer name</option> | |||||
<option [ngValue]="customer.id" *ngFor="let customer of dropDownCustomer"> {{ customer.firstName }} {{ customer.lastName}}</option> | |||||
</select> | |||||
</div> | |||||
</form> | |||||
</ng-template> | |||||
<ng-template #abpFooter> | |||||
<button type="button" class="btn btn-secondary" abpClose> | |||||
{{ '::Close' | abpLocalization }} | |||||
</button> | |||||
<!--added save button--> | |||||
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid"> | |||||
<i class="fa fa-check mr-1"></i> | |||||
{{ '::Save' | abpLocalization }} | |||||
</button> | |||||
</ng-template> | |||||
</abp-modal> |
@ -0,0 +1,23 @@ | |||||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
import { BookIssueComponent } from './book-issue.component'; | |||||
describe('BookIssueComponent', () => { | |||||
let component: BookIssueComponent; | |||||
let fixture: ComponentFixture<BookIssueComponent>; | |||||
beforeEach(async () => { | |||||
await TestBed.configureTestingModule({ | |||||
declarations: [BookIssueComponent] | |||||
}) | |||||
.compileComponents(); | |||||
fixture = TestBed.createComponent(BookIssueComponent); | |||||
component = fixture.componentInstance; | |||||
fixture.detectChanges(); | |||||
}); | |||||
it('should create', () => { | |||||
expect(component).toBeTruthy(); | |||||
}); | |||||
}); |
@ -0,0 +1,83 @@ | |||||
import { Component, OnInit } from '@angular/core'; | |||||
import { ListService, PagedResultDto } from '@abp/ng.core'; | |||||
import { BookIssueDto, BookIssueListDto, BookIssueService } from '@proxy/book-issued'; | |||||
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; | |||||
import { BookDto, BookService } from '@proxy/books'; | |||||
import { CustomerDto, CustomerService } from '@proxy/customers'; | |||||
import { ConfirmationService,Confirmation } from '@abp/ng.theme.shared'; | |||||
@Component({ | |||||
selector: 'app-book-issue', | |||||
templateUrl: './book-issue.component.html', | |||||
styleUrl: './book-issue.component.scss', | |||||
providers: [ListService] | |||||
}) | |||||
export class BookIssueComponent implements OnInit { | |||||
isModalOpen = false; | |||||
form:FormGroup; | |||||
dropDownbook= {} as Array<BookDto>; | |||||
dropDownCustomer= {} as Array<CustomerDto>; | |||||
bookIssueList = { items: [], totalCount: 0 } as PagedResultDto<BookIssueListDto>; | |||||
constructor(public readonly list: ListService, | |||||
private bookIssuedService: BookIssueService, | |||||
private bookService: BookService, | |||||
private customerService: CustomerService, | |||||
private fb: FormBuilder, | |||||
private confirmation: ConfirmationService ) {} | |||||
ngOnInit(): void { | |||||
this.dropdowninitiale(); | |||||
const bookStreamCreator = (query) => this.bookIssuedService.getList(query); | |||||
this.list.hookToQuery(bookStreamCreator).subscribe((response) => { | |||||
this.bookIssueList = response; | |||||
}); | |||||
} | |||||
createBookIssue() { | |||||
this.buildForm(); | |||||
this.isModalOpen = true; | |||||
} | |||||
buildForm() { | |||||
this.form = this.fb.group({ | |||||
bookId: ['', Validators.required], | |||||
customerId: ['', Validators.required], | |||||
}); | |||||
} | |||||
save() { | |||||
if (this.form.invalid) { | |||||
return; | |||||
} | |||||
this.bookIssuedService.create(this.form.value).subscribe(() => { | |||||
this.isModalOpen = false; | |||||
this.form.reset(); | |||||
this.list.get(); | |||||
}); | |||||
} | |||||
dropdowninitiale(){ | |||||
this.bookService.getBookDropDown().subscribe((response)=>{ | |||||
this.dropDownbook = response; | |||||
}); | |||||
this.customerService.getcustomerDropDown().subscribe((response)=>{ | |||||
this.dropDownCustomer = response; | |||||
}); | |||||
} | |||||
delete(bookIssueId: number) { | |||||
this.confirmation.warn('::AreYouSureToUnIssue', '::AreYouSure').subscribe((status) => { | |||||
if (status === Confirmation.Status.confirm) { | |||||
this.bookIssuedService.delete(bookIssueId).subscribe(() => this.list.get()); | |||||
} | |||||
}); | |||||
} | |||||
} |
@ -0,0 +1,19 @@ | |||||
import { NgModule } from '@angular/core'; | |||||
import { CommonModule } from '@angular/common'; | |||||
import { BookIssueRoutingModule } from './book-issue-routing.module'; | |||||
import { BookIssueComponent } from './book-issue.component'; | |||||
import{SharedModule} from '../shared/shared.module'; | |||||
@NgModule({ | |||||
declarations: [ | |||||
BookIssueComponent | |||||
], | |||||
imports: [ | |||||
CommonModule, | |||||
BookIssueRoutingModule, | |||||
SharedModule | |||||
] | |||||
}) | |||||
export class BookIssueModule { } |
@ -0,0 +1,12 @@ | |||||
import { NgModule } from '@angular/core'; | |||||
import { RouterModule, Routes } from '@angular/router'; | |||||
import { BookComponent } from './book.component'; | |||||
import { authGuard, permissionGuard } from '@abp/ng.core'; | |||||
const routes: Routes = [{ path: '', component: BookComponent, canActivate: [authGuard, permissionGuard] }]; | |||||
@NgModule({ | |||||
imports: [RouterModule.forChild(routes)], | |||||
exports: [RouterModule] | |||||
}) | |||||
export class BookRoutingModule { } |
@ -0,0 +1,122 @@ | |||||
<div class="card"> | |||||
<div class="card-header"> | |||||
<div class="row"> | |||||
<div class="col col-md-6"> | |||||
<h5 class="card-title"> | |||||
{{ '::Menu:Books' | abpLocalization }} | |||||
</h5> | |||||
</div> | |||||
<div class="text-end col col-md-6"> | |||||
<!-- Add the "new book" button here --> | |||||
<div class="text-lg-end pt-2"> | |||||
<button id="create" class="btn btn-primary" type="button" (click)="createBook()"> | |||||
<i class="fa fa-plus me-1"></i> | |||||
<span>{{ "::NewBook" | abpLocalization }}</span> | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="card-body"> | |||||
<ngx-datatable [rows]="book.items" [count]="book.totalCount" [list]="list" default> | |||||
<ngx-datatable-column | |||||
[name]="'::Actions' | abpLocalization" | |||||
[maxWidth]="150" | |||||
[sortable]="false" | |||||
> | |||||
<ng-template let-row="row" ngx-datatable-cell-template> | |||||
<div ngbDropdown container="body" class="d-inline-block"> | |||||
<button | |||||
class="btn btn-primary btn-sm dropdown-toggle" | |||||
data-toggle="dropdown" | |||||
aria-haspopup="true" | |||||
ngbDropdownToggle | |||||
> | |||||
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }} | |||||
</button> | |||||
<div ngbDropdownMenu> | |||||
<button ngbDropdownItem (click)="editBook(row.id)"> | |||||
{{ '::Edit' | abpLocalization }} | |||||
</button> | |||||
<button ngbDropdownItem (click)="delete(row.id)"> | |||||
{{ '::Delete' | abpLocalization }} | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</ng-template> | |||||
</ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'::Name' | abpLocalization" prop="name"></ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'::Type' | abpLocalization" prop="type"> | |||||
<ng-template let-row="row" ngx-datatable-cell-template> | |||||
{{ '::Enum:BookType.' + row.type | abpLocalization }} | |||||
</ng-template> | |||||
</ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'::PublishDate' | abpLocalization" prop="publishDate"> | |||||
<ng-template let-row="row" ngx-datatable-cell-template> | |||||
{{ row.publishDate | date }} | |||||
</ng-template> | |||||
</ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'::Price' | abpLocalization" prop="price"> | |||||
<ng-template let-row="row" ngx-datatable-cell-template> | |||||
{{ row.price | currency }} | |||||
</ng-template> | |||||
</ngx-datatable-column> | |||||
</ngx-datatable> | |||||
</div> | |||||
</div> | |||||
<!-- Add the modal here --> | |||||
<abp-modal [(visible)]="isModalOpen"> | |||||
<ng-template #abpHeader> | |||||
<h3>{{ '::NewBook' | abpLocalization }}</h3> | |||||
</ng-template> | |||||
<ng-template #abpBody> | |||||
<form [formGroup]="form" (ngSubmit)="save()"> | |||||
<div class="mt-2"> | |||||
<label for="book-name">Name</label><span> * </span> | |||||
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus /> | |||||
</div> | |||||
<div class="mt-2"> | |||||
<label for="book-price">Price</label><span> * </span> | |||||
<input type="number" id="book-price" class="form-control" formControlName="price" /> | |||||
</div> | |||||
<div class="mt-2"> | |||||
<label for="book-type">Type</label><span> * </span> | |||||
<select class="form-control" id="book-type" formControlName="type"> | |||||
<option [ngValue]="null">Select a book type</option> | |||||
<option [ngValue]="type.value" *ngFor="let type of bookTypes"> {{ '::Enum:BookType.' + type.value | abpLocalization }}</option> | |||||
</select> | |||||
</div> | |||||
<div class="mt-2"> | |||||
<label>Publish date</label><span> * </span> | |||||
<input | |||||
#datepicker="ngbDatepicker" | |||||
class="form-control" | |||||
name="datepicker" | |||||
formControlName="publishDate" | |||||
ngbDatepicker | |||||
(click)="datepicker.toggle()" | |||||
/> | |||||
</div> | |||||
</form> | |||||
</ng-template> | |||||
<ng-template #abpFooter> | |||||
<button type="button" class="btn btn-secondary" abpClose> | |||||
{{ '::Close' | abpLocalization }} | |||||
</button> | |||||
<!--added save button--> | |||||
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid"> | |||||
<i class="fa fa-check mr-1"></i> | |||||
{{ '::Save' | abpLocalization }} | |||||
</button> | |||||
</ng-template> | |||||
</abp-modal> |
@ -0,0 +1,23 @@ | |||||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
import { BookComponent } from './book.component'; | |||||
describe('BookComponent', () => { | |||||
let component: BookComponent; | |||||
let fixture: ComponentFixture<BookComponent>; | |||||
beforeEach(async () => { | |||||
await TestBed.configureTestingModule({ | |||||
declarations: [BookComponent] | |||||
}) | |||||
.compileComponents(); | |||||
fixture = TestBed.createComponent(BookComponent); | |||||
component = fixture.componentInstance; | |||||
fixture.detectChanges(); | |||||
}); | |||||
it('should create', () => { | |||||
expect(component).toBeTruthy(); | |||||
}); | |||||
}); |
@ -0,0 +1,88 @@ | |||||
import { ListService, PagedResultDto } from '@abp/ng.core'; | |||||
import { Component, OnInit } from '@angular/core'; | |||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; | |||||
import { BookService, BookDto, bookTypeOptions } from '@proxy/books'; | |||||
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; | |||||
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared'; | |||||
@Component({ | |||||
selector: 'app-book', | |||||
templateUrl: './book.component.html', | |||||
styleUrls: ['./book.component.scss'], | |||||
providers: [ListService, | |||||
{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter } // add this line | |||||
], | |||||
}) | |||||
export class BookComponent implements OnInit { | |||||
book = { items: [], totalCount: 0 } as PagedResultDto<BookDto>; | |||||
selectedBook = {} as BookDto; // declare selectedBook | |||||
isModalOpen = false; // add this line | |||||
form: FormGroup; // add this line | |||||
bookTypes = bookTypeOptions; | |||||
constructor(public readonly list: ListService, private bookService: BookService, private fb: FormBuilder, | |||||
private confirmation: ConfirmationService | |||||
) {} | |||||
ngOnInit() { | |||||
debugger; | |||||
const bookStreamCreator = (query) => this.bookService.getList(query); | |||||
this.list.hookToQuery(bookStreamCreator).subscribe((response) => { | |||||
this.book = response; | |||||
}); | |||||
} | |||||
// add new method | |||||
createBook() { | |||||
this.buildForm(); // add this line | |||||
this.selectedBook = {} as BookDto; // reset the selected book | |||||
this.isModalOpen = true; | |||||
} | |||||
buildForm() { | |||||
this.form = this.fb.group({ | |||||
name: ['', Validators.required], | |||||
type: [null, Validators.required], | |||||
publishDate: [null, Validators.required], | |||||
price: [null, Validators.required], | |||||
}); | |||||
} | |||||
save() { | |||||
if (this.form.invalid) { | |||||
return; | |||||
} | |||||
const request = this.selectedBook.id | |||||
? this.bookService.update(this.selectedBook.id, this.form.value) | |||||
: this.bookService.create(this.form.value); | |||||
request.subscribe(() => { | |||||
this.isModalOpen = false; | |||||
this.form.reset(); | |||||
this.list.get(); | |||||
}); | |||||
} | |||||
// Add editBook method | |||||
editBook(id: string) { | |||||
this.bookService.get(id).subscribe((book) => { | |||||
this.selectedBook = book; | |||||
this.buildForm(); | |||||
this.form.controls["name"].setValue(this.selectedBook.name); | |||||
this.form.controls["type"].setValue(this.selectedBook.type); | |||||
this.form.controls["publishDate"].setValue(this.selectedBook.publishDate); | |||||
this.form.controls["price"].setValue(this.selectedBook.price); | |||||
this.isModalOpen = true; | |||||
}); | |||||
} | |||||
delete(id: string) { | |||||
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => { | |||||
if (status === Confirmation.Status.confirm) { | |||||
this.bookService.delete(id).subscribe(() => this.list.get()); | |||||
} | |||||
}); | |||||
} | |||||
} |
@ -0,0 +1,21 @@ | |||||
import { NgModule } from '@angular/core'; | |||||
import { CommonModule } from '@angular/common'; | |||||
import { BookRoutingModule } from './book-routing.module'; | |||||
import { BookComponent } from './book.component'; | |||||
import{SharedModule} from '../shared/shared.module'; | |||||
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; // add this line | |||||
@NgModule({ | |||||
declarations: [ | |||||
BookComponent | |||||
], | |||||
imports: [ | |||||
CommonModule, | |||||
BookRoutingModule, | |||||
SharedModule, | |||||
NgbDatepickerModule | |||||
] | |||||
}) | |||||
export class BookModule { } |
@ -0,0 +1,13 @@ | |||||
import { NgModule } from '@angular/core'; | |||||
import { RouterModule, Routes } from '@angular/router'; | |||||
import { CustomerComponent } from './customer.component'; | |||||
import { authGuard, permissionGuard } from '@abp/ng.core'; | |||||
const routes: Routes = [{ path: '', component: CustomerComponent,canActivate: [authGuard, permissionGuard] }]; | |||||
@NgModule({ | |||||
imports: [RouterModule.forChild(routes)], | |||||
exports: [RouterModule] | |||||
}) | |||||
export class CustomerRoutingModule { } |
@ -0,0 +1,101 @@ | |||||
<div class="card"> | |||||
<div class="card-header"> | |||||
<div class="row"> | |||||
<div class="col col-md-6"> | |||||
<h5 class="card-title"> | |||||
{{ 'customer' | abpLocalization }} | |||||
</h5> | |||||
</div> | |||||
<div class="text-end col col-md-6"> | |||||
<!-- Add the "new book" button here --> | |||||
<div class="text-lg-end pt-2"> | |||||
<button id="create" class="btn btn-primary" type="button" (click)="createCustomer()"> | |||||
<i class="fa fa-plus me-1"></i> | |||||
<span>{{ "New Customer" | abpLocalization }}</span> | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="card-body"> | |||||
<ngx-datatable [rows]="customer.items" [count]="customer.totalCount" [list]="list" default> | |||||
<ngx-datatable-column | |||||
[name]="'::Actions' | abpLocalization" | |||||
[maxWidth]="150" | |||||
[sortable]="false" | |||||
> | |||||
<ng-template let-row="row" ngx-datatable-cell-template> | |||||
<div ngbDropdown container="body" class="d-inline-block"> | |||||
<button | |||||
class="btn btn-primary btn-sm dropdown-toggle" | |||||
data-toggle="dropdown" | |||||
aria-haspopup="true" | |||||
ngbDropdownToggle | |||||
> | |||||
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }} | |||||
</button> | |||||
<div ngbDropdownMenu> | |||||
<button ngbDropdownItem (click)="editCustomer(row.id)"> | |||||
{{ '::Edit' | abpLocalization }} | |||||
</button> | |||||
<button ngbDropdownItem (click)="delete(row.id)"> | |||||
{{ '::Delete' | abpLocalization }} | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</ng-template> | |||||
</ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'first Name' | abpLocalization" prop="firstName"></ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'Last Name' | abpLocalization" prop="lastName"> | |||||
</ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'::Address' | abpLocalization" prop="address"> | |||||
</ngx-datatable-column> | |||||
<ngx-datatable-column [name]="'::Phone' | abpLocalization" prop="phone"> | |||||
</ngx-datatable-column> | |||||
</ngx-datatable> | |||||
</div> | |||||
</div> | |||||
<!-- Add the modal here --> | |||||
<abp-modal [(visible)]="isModalOpen"> | |||||
<ng-template #abpHeader> | |||||
<h3>{{ (selectedcustomer.id ? '::Edit' : '::New Customer' ) | abpLocalization }}</h3> | |||||
</ng-template> | |||||
<ng-template #abpBody> | |||||
<form [formGroup]="form" (ngSubmit)="save()"> | |||||
<div class="mt-2"> | |||||
<label for="customer-first-name">First Name</label><span> * </span> | |||||
<input type="text" id="customer-first-name" class="form-control" formControlName="firstName" autofocus /> | |||||
</div> | |||||
<div class="mt-2"> | |||||
<label for="customer-last-name">Last Name</label><span> * </span> | |||||
<input type="text" id="customer-last-name" class="form-control" formControlName="lastName" /> | |||||
</div> | |||||
<div class="mt-2"> | |||||
<label for="customer-phone-name">Phone</label><span> * </span> | |||||
<input type="text" id="customer-phone-name" class="form-control" formControlName="phone" /> | |||||
</div> | |||||
<div class="mt-2"> | |||||
<label for="customer-address-name">Address</label><span> * </span> | |||||
<input type="text" id="customer-address-name" class="form-control" formControlName="address" /> | |||||
</div> | |||||
</form> | |||||
</ng-template> | |||||
<ng-template #abpFooter> | |||||
<button type="button" class="btn btn-secondary" abpClose> | |||||
{{ '::Close' | abpLocalization }} | |||||
</button> | |||||
<!--added save button--> | |||||
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid"> | |||||
<i class="fa fa-check mr-1"></i> | |||||
{{ '::Save' | abpLocalization }} | |||||
</button> | |||||
</ng-template> | |||||
</abp-modal> |
@ -0,0 +1,23 @@ | |||||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
import { CustomerComponent } from './customer.component'; | |||||
describe('CustomerComponent', () => { | |||||
let component: CustomerComponent; | |||||
let fixture: ComponentFixture<CustomerComponent>; | |||||
beforeEach(async () => { | |||||
await TestBed.configureTestingModule({ | |||||
declarations: [CustomerComponent] | |||||
}) | |||||
.compileComponents(); | |||||
fixture = TestBed.createComponent(CustomerComponent); | |||||
component = fixture.componentInstance; | |||||
fixture.detectChanges(); | |||||
}); | |||||
it('should create', () => { | |||||
expect(component).toBeTruthy(); | |||||
}); | |||||
}); |
@ -0,0 +1,92 @@ | |||||
import { Component, OnInit } from '@angular/core'; | |||||
import { ListService, PagedResultDto } from '@abp/ng.core'; | |||||
import { CustomerDto, CustomerService } from '@proxy/customers'; | |||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; | |||||
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared'; | |||||
@Component({ | |||||
selector: 'app-customer', | |||||
templateUrl: './customer.component.html', | |||||
styleUrl: './customer.component.scss', | |||||
providers: [ListService] | |||||
}) | |||||
export class CustomerComponent implements OnInit { | |||||
customer = { items: [], totalCount: 0 } as PagedResultDto<CustomerDto>; | |||||
isModalOpen = false; | |||||
form: FormGroup; | |||||
selectedcustomer = {} as CustomerDto; | |||||
constructor(public readonly list: ListService, | |||||
private customerService: CustomerService, | |||||
private fb: FormBuilder, | |||||
private confirmation: ConfirmationService ) {} | |||||
ngOnInit() { | |||||
debugger; | |||||
const bookStreamCreator = (query) => this.customerService.getList(query); | |||||
this.list.hookToQuery(bookStreamCreator).subscribe((response) => { | |||||
this.customer = response; | |||||
}); | |||||
} | |||||
// add new method | |||||
createCustomer() { | |||||
this.selectedcustomer = {} as CustomerDto; | |||||
this.buildForm(); | |||||
this.isModalOpen = true; | |||||
} | |||||
editCustomer(id: number) { | |||||
this.customerService.get(id).subscribe((customer) => { | |||||
debugger; | |||||
this.selectedcustomer = customer; | |||||
this.buildForm(); | |||||
this.isModalOpen = true; | |||||
}); | |||||
} | |||||
buildForm() { | |||||
this.form = this.fb.group({ | |||||
firstName: [this.selectedcustomer.firstName || '', Validators.required], | |||||
lastName: [this.selectedcustomer.lastName, Validators.required], | |||||
phone: [this.selectedcustomer.phone, Validators.required], | |||||
address: [this.selectedcustomer.address, Validators.required], | |||||
}); | |||||
} | |||||
// add save method | |||||
save() { | |||||
if (this.form.invalid) { | |||||
return; | |||||
} | |||||
debugger; | |||||
const request = this.selectedcustomer.id | |||||
? this.customerService.update(this.selectedcustomer.id, this.form.value) | |||||
: this.customerService.create(this.form.value); | |||||
if(this.selectedcustomer.id){ | |||||
this.customerService.update(this.selectedcustomer.id,this.form.value).subscribe(() => { | |||||
this.isModalOpen = false; | |||||
this.form.reset(); | |||||
this.list.get(); | |||||
}); | |||||
} | |||||
else{ | |||||
this.customerService.create(this.form.value).subscribe(() => { | |||||
this.isModalOpen = false; | |||||
this.form.reset(); | |||||
this.list.get(); | |||||
}); | |||||
} | |||||
} | |||||
delete(id: number) { | |||||
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => { | |||||
if (status === Confirmation.Status.confirm) { | |||||
this.customerService.delete(id).subscribe(() => this.list.get()); | |||||
} | |||||
}); | |||||
} | |||||
} |
@ -0,0 +1,20 @@ | |||||
import { NgModule } from '@angular/core'; | |||||
import { CommonModule } from '@angular/common'; | |||||
import { CustomerRoutingModule } from './customer-routing.module'; | |||||
import { CustomerComponent } from './customer.component'; | |||||
import{SharedModule} from '../shared/shared.module'; | |||||
@NgModule({ | |||||
declarations: [ | |||||
CustomerComponent | |||||
], | |||||
imports: [ | |||||
CommonModule, | |||||
CustomerRoutingModule, | |||||
SharedModule | |||||
] | |||||
}) | |||||
export class CustomerModule { } |
@ -0,0 +1,17 @@ | |||||
# Proxy Generation Output | |||||
This directory includes the output of the latest proxy generation. | |||||
The files and folders in it will be overwritten when proxy generation is run again. | |||||
Therefore, please do not place your own content in this folder. | |||||
In addition, `generate-proxy.json` works like a lock file. | |||||
It includes information used by the proxy generator, so please do not delete or modify it. | |||||
Finally, the name of the files and folders should not be changed for two reasons: | |||||
- Proxy generator will keep creating them at those paths and you will have multiple copies of the same content. | |||||
- ABP Suite generates files which include imports from this folder. | |||||
> **Important Notice:** If you are building a module and are planning to publish to npm, | |||||
> some of the generated proxies are likely to be exported from public-api.ts file. In such a case, | |||||
> please make sure you export files directly and not from barrel exports. In other words, | |||||
> do not include index.ts exports in your public-api.ts exports. |
@ -0,0 +1,56 @@ | |||||
import type { AuthorDto, CreateAuthorDto, GetAuthorListDto, UpdateAuthorDto } from './models'; | |||||
import { RestService, Rest } from '@abp/ng.core'; | |||||
import type { PagedResultDto } from '@abp/ng.core'; | |||||
import { Injectable } from '@angular/core'; | |||||
@Injectable({ | |||||
providedIn: 'root', | |||||
}) | |||||
export class AuthorService { | |||||
apiName = 'Default'; | |||||
create = (input: CreateAuthorDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, AuthorDto>({ | |||||
method: 'POST', | |||||
url: '/api/app/author', | |||||
body: input, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
delete = (id: string, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, void>({ | |||||
method: 'DELETE', | |||||
url: `/api/app/author/${id}`, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
get = (id: string, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, AuthorDto>({ | |||||
method: 'GET', | |||||
url: `/api/app/author/${id}`, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
getList = (input: GetAuthorListDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, PagedResultDto<AuthorDto>>({ | |||||
method: 'GET', | |||||
url: '/api/app/author', | |||||
params: { filter: input.filter, sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount }, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
update = (id: string, input: UpdateAuthorDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, void>({ | |||||
method: 'PUT', | |||||
url: `/api/app/author/${id}`, | |||||
body: input, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
constructor(private restService: RestService) {} | |||||
} |
@ -0,0 +1,2 @@ | |||||
export * from './author.service'; | |||||
export * from './models'; |
@ -0,0 +1,23 @@ | |||||
import type { EntityDto, PagedAndSortedResultRequestDto } from '@abp/ng.core'; | |||||
export interface AuthorDto extends EntityDto<string> { | |||||
name?: string; | |||||
birthDate?: string; | |||||
shortBio?: string; | |||||
} | |||||
export interface CreateAuthorDto { | |||||
name: string; | |||||
birthDate: string; | |||||
shortBio?: string; | |||||
} | |||||
export interface GetAuthorListDto extends PagedAndSortedResultRequestDto { | |||||
filter?: string; | |||||
} | |||||
export interface UpdateAuthorDto { | |||||
name: string; | |||||
birthDate: string; | |||||
shortBio?: string; | |||||
} |
@ -0,0 +1,55 @@ | |||||
import type { BookIssueDto, BookIssueListDto } from './models'; | |||||
import { RestService, Rest } from '@abp/ng.core'; | |||||
import type { PagedResultDto } from '@abp/ng.core'; | |||||
import { Injectable } from '@angular/core'; | |||||
@Injectable({ | |||||
providedIn: 'root', | |||||
}) | |||||
export class BookIssueService { | |||||
apiName = 'Default'; | |||||
create = (input: BookIssueDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, BookIssueDto>({ | |||||
method: 'POST', | |||||
url: '/api/app/book-issue', | |||||
body: input, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
delete = (id: number, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, void>({ | |||||
method: 'DELETE', | |||||
url: `/api/app/book-issue/${id}`, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
get = (id: number, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, BookIssueDto>({ | |||||
method: 'GET', | |||||
url: `/api/app/book-issue/${id}`, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
getList = (config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, PagedResultDto<BookIssueListDto>>({ | |||||
method: 'GET', | |||||
url: '/api/app/book-issue', | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
update = (id: number, input: BookIssueDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, void>({ | |||||
method: 'PUT', | |||||
url: `/api/app/book-issue/${id}`, | |||||
body: input, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
constructor(private restService: RestService) {} | |||||
} |
@ -0,0 +1,2 @@ | |||||
export * from './book-issue.service'; | |||||
export * from './models'; |
@ -0,0 +1,13 @@ | |||||
import type { EntityDto } from '@abp/ng.core'; | |||||
export interface BookIssueDto extends EntityDto<number> { | |||||
bookId?: string; | |||||
customerId: number; | |||||
} | |||||
export interface BookIssueListDto { | |||||
bookIssueId: number; | |||||
bookName?: string; | |||||
customerName?: string; | |||||
issueDate?: string; | |||||
} |
@ -0,0 +1,15 @@ | |||||
import { mapEnumToOptions } from '@abp/ng.core'; | |||||
export enum BookType { | |||||
Undefined = 0, | |||||
Adventure = 1, | |||||
Biography = 2, | |||||
Dystopia = 3, | |||||
Fantastic = 4, | |||||
Horror = 5, | |||||
Science = 6, | |||||
ScienceFiction = 7, | |||||
Poetry = 8, | |||||
} | |||||
export const bookTypeOptions = mapEnumToOptions(BookType); |
@ -0,0 +1,64 @@ | |||||
import type { BookDto, CreateUpdateBookDto } from './models'; | |||||
import { RestService, Rest } from '@abp/ng.core'; | |||||
import type { PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core'; | |||||
import { Injectable } from '@angular/core'; | |||||
@Injectable({ | |||||
providedIn: 'root', | |||||
}) | |||||
export class BookService { | |||||
apiName = 'Default'; | |||||
create = (input: CreateUpdateBookDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, BookDto>({ | |||||
method: 'POST', | |||||
url: '/api/app/book', | |||||
body: input, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
delete = (id: string, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, void>({ | |||||
method: 'DELETE', | |||||
url: `/api/app/book/${id}`, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
get = (id: string, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, BookDto>({ | |||||
method: 'GET', | |||||
url: `/api/app/book/${id}`, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
getBookDropDown = (config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, BookDto[]>({ | |||||
method: 'GET', | |||||
url: '/api/app/book/book-drop-down', | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
getList = (input: PagedAndSortedResultRequestDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, PagedResultDto<BookDto>>({ | |||||
method: 'GET', | |||||
url: '/api/app/book', | |||||
params: { sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount }, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
update = (id: string, input: CreateUpdateBookDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, BookDto>({ | |||||
method: 'PUT', | |||||
url: `/api/app/book/${id}`, | |||||
body: input, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
constructor(private restService: RestService) {} | |||||
} |
@ -0,0 +1,3 @@ | |||||
export * from './book-type.enum'; | |||||
export * from './book.service'; | |||||
export * from './models'; |
@ -0,0 +1,16 @@ | |||||
import type { AuditedEntityDto } from '@abp/ng.core'; | |||||
import type { BookType } from './book-type.enum'; | |||||
export interface BookDto extends AuditedEntityDto<string> { | |||||
name?: string; | |||||
type: BookType; | |||||
publishDate?: string; | |||||
price: number; | |||||
} | |||||
export interface CreateUpdateBookDto { | |||||
name: string; | |||||
type: BookType; | |||||
publishDate: string; | |||||
price: number; | |||||
} |
@ -0,0 +1,63 @@ | |||||
import type { CustomerDto } from './models'; | |||||
import { RestService, Rest } from '@abp/ng.core'; | |||||
import type { PagedResultDto } from '@abp/ng.core'; | |||||
import { Injectable } from '@angular/core'; | |||||
@Injectable({ | |||||
providedIn: 'root', | |||||
}) | |||||
export class CustomerService { | |||||
apiName = 'Default'; | |||||
create = (input: CustomerDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, CustomerDto>({ | |||||
method: 'POST', | |||||
url: '/api/app/customer', | |||||
body: input, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
delete = (id: number, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, void>({ | |||||
method: 'DELETE', | |||||
url: `/api/app/customer/${id}`, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
get = (id: number, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, CustomerDto>({ | |||||
method: 'GET', | |||||
url: `/api/app/customer/${id}`, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
getList = (config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, PagedResultDto<CustomerDto>>({ | |||||
method: 'GET', | |||||
url: '/api/app/customer', | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
getcustomerDropDown = (config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, CustomerDto[]>({ | |||||
method: 'GET', | |||||
url: '/api/app/customer/customer-drop-down', | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
update = (id: number, input: CustomerDto, config?: Partial<Rest.Config>) => | |||||
this.restService.request<any, void>({ | |||||
method: 'PUT', | |||||
url: `/api/app/customer/${id}`, | |||||
body: input, | |||||
}, | |||||
{ apiName: this.apiName,...config }); | |||||
constructor(private restService: RestService) {} | |||||
} |
@ -0,0 +1,2 @@ | |||||
export * from './customer.service'; | |||||
export * from './models'; |
@ -0,0 +1,8 @@ | |||||
import type { EntityDto } from '@abp/ng.core'; | |||||
export interface CustomerDto extends EntityDto<number> { | |||||
firstName?: string; | |||||
lastName?: string; | |||||
phone?: string; | |||||
address?: string; | |||||
} |
@ -0,0 +1,5 @@ | |||||
import * as Authors from './authors'; | |||||
import * as BookIssued from './book-issued'; | |||||
import * as Books from './books'; | |||||
import * as Customers from './customers'; | |||||
export { Authors, BookIssued, Books, Customers }; |
@ -1,19 +1,16 @@ | |||||
<!DOCTYPE html> | <!DOCTYPE html> | ||||
<html lang="en"> | <html lang="en"> | ||||
<head> | <head> | ||||
<meta charset="utf-8"/> | |||||
<meta charset="utf-8" /> | |||||
<title>BookStore</title> | <title>BookStore</title> | ||||
<base href="/"/> | |||||
<base href="/" /> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1"/> | |||||
<link rel="icon" type="image/x-icon" href="favicon.ico"/> | |||||
<link rel="manifest" href="manifest.webmanifest"> | |||||
<meta name="theme-color" content="#1976d2"> | |||||
</head> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |||||
<link rel="icon" type="image/x-icon" href="favicon.ico" /> | |||||
</head> | |||||
<body class="bg-light"> | <body class="bg-light"> | ||||
<app-root> | <app-root> | ||||
<div class="donut centered"></div> | <div class="donut centered"></div> | ||||
</app-root> | </app-root> | ||||
<noscript>Please enable JavaScript to continue using this application.</noscript> | |||||
</body> | |||||
</body> | |||||
</html> | </html> |
@ -0,0 +1,44 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.ComponentModel.DataAnnotations; | |||||
using System.Text; | |||||
using Volo.Abp.Application.Dtos; | |||||
namespace Acme.BookStore.Authors | |||||
{ | |||||
public class AuthorDto : EntityDto<Guid> | |||||
{ | |||||
public string Name { get; set; } | |||||
public DateTime BirthDate { get; set; } | |||||
public string ShortBio { get; set; } | |||||
} | |||||
public class GetAuthorListDto : PagedAndSortedResultRequestDto | |||||
{ | |||||
public string? Filter { get; set; } | |||||
} | |||||
public class CreateAuthorDto | |||||
{ | |||||
[Required] | |||||
[StringLength(AuthorConsts.MaxNameLength)] | |||||
public string Name { get; set; } = string.Empty; | |||||
[Required] | |||||
public DateTime BirthDate { get; set; } | |||||
public string? ShortBio { get; set; } | |||||
} | |||||
public class UpdateAuthorDto | |||||
{ | |||||
[Required] | |||||
[StringLength(AuthorConsts.MaxNameLength)] | |||||
public string Name { get; set; } = string.Empty; | |||||
[Required] | |||||
public DateTime BirthDate { get; set; } | |||||
public string? ShortBio { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,19 @@ | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Application.Dtos; | |||||
using Volo.Abp.Application.Services; | |||||
namespace Acme.BookStore.Authors; | |||||
public interface IAuthorAppService : IApplicationService | |||||
{ | |||||
Task<AuthorDto> GetAsync(Guid id); | |||||
Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input); | |||||
Task<AuthorDto> CreateAsync(CreateAuthorDto input); | |||||
Task UpdateAsync(Guid id, UpdateAuthorDto input); | |||||
Task DeleteAsync(Guid id); | |||||
} |
@ -0,0 +1,25 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.ComponentModel.DataAnnotations; | |||||
using System.Text; | |||||
using Volo.Abp.Application.Dtos; | |||||
namespace Acme.BookStore.BookIssued | |||||
{ | |||||
public class BookIssueDto : EntityDto<int> | |||||
{ | |||||
[Required] | |||||
public Guid bookId { get; set; } | |||||
[Required] | |||||
public int customerId { get; set; } | |||||
} | |||||
public class BookIssueListDto | |||||
{ | |||||
public int bookIssueId { get; set; } | |||||
public string bookName { get; set; } | |||||
public string customerName { get; set; } | |||||
public DateTime issueDate { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,22 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Application.Dtos; | |||||
using Volo.Abp.Application.Services; | |||||
namespace Acme.BookStore.BookIssued | |||||
{ | |||||
public interface IBookIssueAppService : IApplicationService | |||||
{ | |||||
Task<BookIssueDto> GetAsync(int id); | |||||
Task<PagedResultDto<BookIssueListDto>> GetListAsync(); | |||||
Task<BookIssueDto> CreateAsync(BookIssueDto input); | |||||
Task UpdateAsync(int id, BookIssueDto input); | |||||
Task DeleteAsync(int id); | |||||
} | |||||
} |
@ -0,0 +1,18 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Volo.Abp.Application.Dtos; | |||||
namespace Acme.BookStore.Books | |||||
{ | |||||
public class BookDto : AuditedEntityDto<Guid> | |||||
{ | |||||
public string Name { get; set; } | |||||
public BookType Type { get; set; } | |||||
public DateTime PublishDate { get; set; } | |||||
public float Price { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,24 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.ComponentModel.DataAnnotations; | |||||
using System.Text; | |||||
namespace Acme.BookStore.Books | |||||
{ | |||||
public class CreateUpdateBookDto | |||||
{ | |||||
[Required] | |||||
[StringLength(128)] | |||||
public string Name { get; set; } = string.Empty; | |||||
[Required] | |||||
public BookType Type { get; set; } = BookType.Undefined; | |||||
[Required] | |||||
[DataType(DataType.Date)] | |||||
public DateTime PublishDate { get; set; } = DateTime.Now; | |||||
[Required] | |||||
public float Price { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,19 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Application.Dtos; | |||||
using Volo.Abp.Application.Services; | |||||
namespace Acme.BookStore.Books | |||||
{ | |||||
public interface IBookAppService : | |||||
ICrudAppService< //Defines CRUD methods | |||||
BookDto, //Used to show books | |||||
Guid, //Primary key of the book entity | |||||
PagedAndSortedResultRequestDto, //Used for paging/sorting | |||||
CreateUpdateBookDto> //Used to create/update a book | |||||
{ | |||||
Task<List<BookDto>> GetBookDropDown(); | |||||
} | |||||
} |
@ -0,0 +1,20 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.ComponentModel.DataAnnotations; | |||||
using System.Text; | |||||
using Volo.Abp.Application.Dtos; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public class CustomerDto : EntityDto<int> | |||||
{ | |||||
[Required] | |||||
public string firstName { get; set; } | |||||
[Required] | |||||
public string lastName { get; set; } | |||||
[Required] | |||||
public string phone { get; set; } | |||||
[Required] | |||||
public string address { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,24 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Application.Dtos; | |||||
using Volo.Abp.Application.Services; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public interface ICustomerAppService : IApplicationService | |||||
{ | |||||
Task<CustomerDto> GetAsync(int id); | |||||
Task<PagedResultDto<CustomerDto>> GetListAsync(); | |||||
Task<CustomerDto> CreateAsync(CustomerDto input); | |||||
Task UpdateAsync(int id, CustomerDto input); | |||||
Task DeleteAsync(int id); | |||||
Task<List<CustomerDto>> GetcustomerDropDown(); | |||||
} | |||||
} |
@ -0,0 +1,95 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Acme.BookStore.Permissions; | |||||
using Microsoft.AspNetCore.Authorization; | |||||
using Volo.Abp.Application.Dtos; | |||||
using Volo.Abp.Domain.Repositories; | |||||
namespace Acme.BookStore.Authors | |||||
{ | |||||
[Authorize(BookStorePermissions.Authors.Default)] | |||||
public class AuthorAppService : BookStoreAppService, IAuthorAppService | |||||
{ | |||||
private readonly IAuthorRepository _authorRepository; | |||||
private readonly AuthorManager _authorManager; | |||||
public AuthorAppService( | |||||
IAuthorRepository authorRepository, | |||||
AuthorManager authorManager) | |||||
{ | |||||
_authorRepository = authorRepository; | |||||
_authorManager = authorManager; | |||||
} | |||||
public async Task<AuthorDto> GetAsync(Guid id) | |||||
{ | |||||
var author = await _authorRepository.GetAsync(id); | |||||
return ObjectMapper.Map<Author, AuthorDto>(author); | |||||
} | |||||
public async Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input) | |||||
{ | |||||
if (input.Sorting.IsNullOrWhiteSpace()) | |||||
{ | |||||
input.Sorting = nameof(Author.Name); | |||||
} | |||||
var authors = await _authorRepository.GetListAsync( | |||||
input.SkipCount, | |||||
input.MaxResultCount, | |||||
input.Sorting, | |||||
input.Filter | |||||
); | |||||
var totalCount = input.Filter == null | |||||
? await _authorRepository.CountAsync() | |||||
: await _authorRepository.CountAsync( | |||||
author => author.Name.Contains(input.Filter)); | |||||
return new PagedResultDto<AuthorDto>( | |||||
totalCount, | |||||
ObjectMapper.Map<List<Author>, List<AuthorDto>>(authors) | |||||
); | |||||
} | |||||
[Authorize(BookStorePermissions.Authors.Create)] | |||||
public async Task<AuthorDto> CreateAsync(CreateAuthorDto input) | |||||
{ | |||||
var author = await _authorManager.CreateAsync( | |||||
input.Name, | |||||
input.BirthDate, | |||||
input.ShortBio | |||||
); | |||||
await _authorRepository.InsertAsync(author); | |||||
return ObjectMapper.Map<Author, AuthorDto>(author); | |||||
} | |||||
[Authorize(BookStorePermissions.Authors.Edit)] | |||||
public async Task UpdateAsync(Guid id, UpdateAuthorDto input) | |||||
{ | |||||
var author = await _authorRepository.GetAsync(id); | |||||
if (author.Name != input.Name) | |||||
{ | |||||
await _authorManager.ChangeNameAsync(author, input.Name); | |||||
} | |||||
author.BirthDate = input.BirthDate; | |||||
author.ShortBio = input.ShortBio; | |||||
await _authorRepository.UpdateAsync(author); | |||||
} | |||||
[Authorize(BookStorePermissions.Authors.Delete)] | |||||
public async Task DeleteAsync(Guid id) | |||||
{ | |||||
await _authorRepository.DeleteAsync(id); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,73 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Acme.BookStore.BookIssued; | |||||
using Volo.Abp.Application.Dtos; | |||||
using Acme.BookStore.Permissions; | |||||
using Microsoft.AspNetCore.Authorization; | |||||
namespace Acme.BookStore.BookIssued | |||||
{ | |||||
public class BookIssueAppService : BookStoreAppService, IBookIssueAppService | |||||
{ | |||||
private readonly IBookIssueRepository _bookIssueRepository; | |||||
private readonly BookIssueManager _bookIssueManager; | |||||
public BookIssueAppService( | |||||
IBookIssueRepository bookIssueRepository, | |||||
BookIssueManager bookIssueManager) | |||||
{ | |||||
_bookIssueRepository = bookIssueRepository; | |||||
_bookIssueManager = bookIssueManager; | |||||
} | |||||
public async Task<BookIssueDto> GetAsync(int id) | |||||
{ | |||||
var cus = await _bookIssueRepository.GetAsync(id); | |||||
return ObjectMapper.Map<BookIssue, BookIssueDto>(cus); | |||||
} | |||||
public async Task<PagedResultDto<BookIssueListDto>> GetListAsync() | |||||
{ | |||||
var cus = await _bookIssueRepository.BookIssueList(); | |||||
return new PagedResultDto<BookIssueListDto>( | |||||
cus.Count(), | |||||
ObjectMapper.Map<List<BookIssueList>, List<BookIssueListDto>>(cus) | |||||
); | |||||
} | |||||
[Authorize(BookStorePermissions.BookIssued.Create)] | |||||
public async Task<BookIssueDto> CreateAsync(BookIssueDto input) | |||||
{ | |||||
var cus = ObjectMapper.Map<BookIssueDto, BookIssue>(input); | |||||
var cust = await _bookIssueManager.CreateAsync(cus); | |||||
var res = await _bookIssueRepository.InsertAsync(cust); | |||||
return ObjectMapper.Map<BookIssue, BookIssueDto>(cust); | |||||
} | |||||
[Authorize(BookStorePermissions.BookIssued.Edit)] | |||||
public async Task UpdateAsync(int id, BookIssueDto input) | |||||
{ | |||||
var cus = await _bookIssueRepository.GetAsync(id); | |||||
await _bookIssueRepository.UpdateAsync(cus); | |||||
} | |||||
[Authorize(BookStorePermissions.BookIssued.Delete)] | |||||
public async Task DeleteAsync(int id) | |||||
{ | |||||
await _bookIssueRepository.DeleteAsync(id); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,43 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Application.Dtos; | |||||
using Volo.Abp.Application.Services; | |||||
using Volo.Abp.Domain.Repositories; | |||||
using Acme.BookStore.Permissions; | |||||
namespace Acme.BookStore.Books | |||||
{ | |||||
public class BookAppService : | |||||
CrudAppService< | |||||
Book, //The Book entity | |||||
BookDto, //Used to show books | |||||
Guid, //Primary key of the book entity | |||||
PagedAndSortedResultRequestDto, //Used for paging/sorting | |||||
CreateUpdateBookDto>, //Used to create/update a book | |||||
IBookAppService //implement the IBookAppService | |||||
{ | |||||
private readonly IRepository<Book, Guid> _bookRepository; | |||||
public BookAppService(IRepository<Book, Guid> repository) | |||||
: base(repository) | |||||
{ | |||||
_bookRepository = repository; | |||||
GetPolicyName = BookStorePermissions.Books.Default; | |||||
GetListPolicyName = BookStorePermissions.Books.Default; | |||||
CreatePolicyName = BookStorePermissions.Books.Create; | |||||
UpdatePolicyName = BookStorePermissions.Books.Edit; | |||||
DeletePolicyName = BookStorePermissions.Books.Delete; | |||||
} | |||||
public async Task<List<BookDto>> GetBookDropDown() | |||||
{ | |||||
var cus = await _bookRepository.GetListAsync(); | |||||
cus = cus == null ? new List<Book>() : cus; | |||||
return ObjectMapper.Map<List<Book>, List<BookDto>>(cus); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,86 @@ | |||||
using Acme.BookStore.Customers; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Application.Dtos; | |||||
using Volo.Abp.Application.Services; | |||||
using Volo.Abp.ObjectMapping; | |||||
using Acme.BookStore.Permissions; | |||||
using Microsoft.AspNetCore.Authorization; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public class CustomerAppService: BookStoreAppService, ICustomerAppService | |||||
{ | |||||
private readonly ICustomerRepository _customerRepository; | |||||
private readonly CustomerManager _customerManager; | |||||
public CustomerAppService( | |||||
ICustomerRepository customerRepository, | |||||
CustomerManager customerManager) | |||||
{ | |||||
_customerRepository = customerRepository; | |||||
_customerManager = customerManager; | |||||
} | |||||
public async Task<CustomerDto> GetAsync(int id) | |||||
{ | |||||
var cus = await _customerRepository.GetAsync(id); | |||||
return ObjectMapper.Map<Customer, CustomerDto>(cus); | |||||
} | |||||
public async Task<List<CustomerDto>> GetcustomerDropDown() | |||||
{ | |||||
var cus = await _customerRepository.GetListAsync(); | |||||
cus = cus == null ? new List<Customer>() : cus; | |||||
return ObjectMapper.Map<List<Customer>, List<CustomerDto>>(cus); | |||||
} | |||||
public async Task<PagedResultDto<CustomerDto>> GetListAsync() | |||||
{ | |||||
var cus = await _customerRepository.GetListAsync(); | |||||
return new PagedResultDto<CustomerDto>( | |||||
cus.Count(), | |||||
ObjectMapper.Map<List<Customer>, List<CustomerDto>>(cus) | |||||
); | |||||
} | |||||
[Authorize(BookStorePermissions.Customers.Create)] | |||||
public async Task<CustomerDto> CreateAsync(CustomerDto input) | |||||
{ | |||||
var cus = ObjectMapper.Map<CustomerDto,Customer>(input); | |||||
var cust = await _customerManager.CreateAsync(cus); | |||||
await _customerRepository.InsertAsync(cust); | |||||
return ObjectMapper.Map<Customer, CustomerDto>(cust); | |||||
} | |||||
[Authorize(BookStorePermissions.Customers.Edit)] | |||||
public async Task UpdateAsync(int id, CustomerDto input) | |||||
{ | |||||
var cus = await _customerRepository.GetAsync(id); | |||||
if (cus.phone == input.phone) | |||||
{ | |||||
await _customerManager.ChangeNameAsync(cus, input.firstName,input.lastName); | |||||
} | |||||
await _customerRepository.UpdateAsync(cus); | |||||
} | |||||
[Authorize(BookStorePermissions.Customers.Delete)] | |||||
public async Task DeleteAsync(int id) | |||||
{ | |||||
await _customerRepository.DeleteAsync(id); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,12 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Acme.BookStore.Authors | |||||
{ | |||||
public static class AuthorConsts | |||||
{ | |||||
public const int MaxNameLength = 64; | |||||
} | |||||
} |
@ -0,0 +1,19 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Acme.BookStore.Books | |||||
{ | |||||
public enum BookType | |||||
{ | |||||
Undefined, | |||||
Adventure, | |||||
Biography, | |||||
Dystopia, | |||||
Fantastic, | |||||
Horror, | |||||
Science, | |||||
ScienceFiction, | |||||
Poetry | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public class CustomerConsts | |||||
{ | |||||
public const int MaxNameLength = 100; | |||||
public const int MaxPhoneLength = 14; | |||||
} | |||||
} |
@ -0,0 +1,48 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp; | |||||
using Volo.Abp.Domain.Entities.Auditing; | |||||
namespace Acme.BookStore.Authors | |||||
{ | |||||
public class Author : FullAuditedAggregateRoot<Guid> | |||||
{ | |||||
public string Name { get; private set; } | |||||
public DateTime BirthDate { get; set; } | |||||
public string ShortBio { get; set; } | |||||
private Author() | |||||
{ | |||||
/* This constructor is for deserialization / ORM purpose */ | |||||
} | |||||
internal Author( | |||||
Guid id, | |||||
string name, | |||||
DateTime birthDate, | |||||
string? shortBio = null) | |||||
: base(id) | |||||
{ | |||||
SetName(name); | |||||
BirthDate = birthDate; | |||||
ShortBio = shortBio; | |||||
} | |||||
internal Author ChangeName(string name) | |||||
{ | |||||
SetName(name); | |||||
return this; | |||||
} | |||||
private void SetName(string name) | |||||
{ | |||||
Name = Check.NotNullOrWhiteSpace( | |||||
name, | |||||
nameof(name), | |||||
maxLength: AuthorConsts.MaxNameLength | |||||
); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,18 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp; | |||||
namespace Acme.BookStore.Authors | |||||
{ | |||||
public class AuthorAlreadyExistsException : BusinessException | |||||
{ | |||||
public AuthorAlreadyExistsException(string name) | |||||
: base(BookStoreDomainErrorCodes.AuthorAlreadyExists) | |||||
{ | |||||
WithData("name", name); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,57 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp; | |||||
using Volo.Abp.Domain.Services; | |||||
namespace Acme.BookStore.Authors | |||||
{ | |||||
public class AuthorManager : DomainService | |||||
{ | |||||
private readonly IAuthorRepository _authorRepository; | |||||
public AuthorManager(IAuthorRepository authorRepository) | |||||
{ | |||||
_authorRepository = authorRepository; | |||||
} | |||||
public async Task<Author> CreateAsync( | |||||
string name, | |||||
DateTime birthDate, | |||||
string? shortBio = null) | |||||
{ | |||||
Check.NotNullOrWhiteSpace(name, nameof(name)); | |||||
var existingAuthor = await _authorRepository.FindByNameAsync(name); | |||||
if (existingAuthor != null) | |||||
{ | |||||
throw new AuthorAlreadyExistsException(name); | |||||
} | |||||
return new Author( | |||||
GuidGenerator.Create(), | |||||
name, | |||||
birthDate, | |||||
shortBio | |||||
); | |||||
} | |||||
public async Task ChangeNameAsync( | |||||
Author author, | |||||
string newName) | |||||
{ | |||||
Check.NotNull(author, nameof(author)); | |||||
Check.NotNullOrWhiteSpace(newName, nameof(newName)); | |||||
var existingAuthor = await _authorRepository.FindByNameAsync(newName); | |||||
if (existingAuthor != null && existingAuthor.Id != author.Id) | |||||
{ | |||||
throw new AuthorAlreadyExistsException(newName); | |||||
} | |||||
author.ChangeName(newName); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,21 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Domain.Repositories; | |||||
namespace Acme.BookStore.Authors | |||||
{ | |||||
public interface IAuthorRepository : IRepository<Author, Guid> | |||||
{ | |||||
Task<Author> FindByNameAsync(string name); | |||||
Task<List<Author>> GetListAsync( | |||||
int skipCount, | |||||
int maxResultCount, | |||||
string sorting, | |||||
string filter = null | |||||
); | |||||
} | |||||
} |
@ -0,0 +1,33 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Domain.Entities.Auditing; | |||||
namespace Acme.BookStore.BookIssued | |||||
{ | |||||
public class BookIssue : FullAuditedAggregateRoot<int> | |||||
{ | |||||
public Guid bookId { get; set; } | |||||
public int customerId { get; set; } | |||||
private BookIssue() | |||||
{ | |||||
/* This constructor is for deserialization / ORM purpose */ | |||||
} | |||||
internal BookIssue(int id, Guid bookId, int customerId) : base(id) | |||||
{ | |||||
this.bookId = bookId; | |||||
this.customerId = customerId; | |||||
} | |||||
} | |||||
public class BookIssueList | |||||
{ | |||||
public int bookIssueId { get; set; } | |||||
public string bookName { get; set; } | |||||
public string customerName { get; set; } | |||||
public DateTime issueDate { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,19 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp; | |||||
namespace Acme.BookStore.BookIssued | |||||
{ | |||||
public class BookIssueErrorException : BusinessException | |||||
{ | |||||
public BookIssueErrorException(string customerName, string bookName) | |||||
: base(BookStoreDomainErrorCodes.BookIssuedAlready) | |||||
{ | |||||
WithData("customer", customerName); | |||||
WithData("book", bookName); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,36 @@ | |||||
using Acme.BookStore.Customers; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp; | |||||
using Volo.Abp.Domain.Services; | |||||
namespace Acme.BookStore.BookIssued | |||||
{ | |||||
public class BookIssueManager : DomainService | |||||
{ | |||||
private readonly IBookIssueRepository _bookIssueRepository; | |||||
public BookIssueManager(IBookIssueRepository bookIssueRepository) | |||||
{ | |||||
_bookIssueRepository = bookIssueRepository; | |||||
} | |||||
public async Task<BookIssue> CreateAsync( | |||||
BookIssue bookissue) | |||||
{ | |||||
var existingBookIssue = await _bookIssueRepository.FindBookIssueCustomer(bookissue.customerId,bookissue.bookId); | |||||
if (existingBookIssue != null) | |||||
{ | |||||
throw new BookIssueErrorException(existingBookIssue.customerName, existingBookIssue.bookName); | |||||
} | |||||
return new BookIssue( | |||||
await _bookIssueRepository.NewBookIssueId(), | |||||
bookissue.bookId, | |||||
bookissue.customerId | |||||
); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,17 @@ | |||||
using Acme.BookStore.Customers; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Domain.Repositories; | |||||
namespace Acme.BookStore.BookIssued | |||||
{ | |||||
public interface IBookIssueRepository : IRepository<BookIssue, int> | |||||
{ | |||||
Task<BookIssueList> FindBookIssueCustomer(int customerId, Guid bookId); | |||||
Task<int> NewBookIssueId(); | |||||
Task<List<BookIssueList>> BookIssueList(); | |||||
} | |||||
} |
@ -0,0 +1,100 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Acme.BookStore.Books; | |||||
using Volo.Abp.Data; | |||||
using Volo.Abp.DependencyInjection; | |||||
using Volo.Abp.Domain.Repositories; | |||||
using Acme.BookStore.Authors; | |||||
using Acme.BookStore.Customers; | |||||
namespace Acme.BookStore | |||||
{ | |||||
public class BookStoreDataSeederContributor | |||||
: IDataSeedContributor, ITransientDependency | |||||
{ | |||||
private readonly IRepository<Book, Guid> _bookRepository; | |||||
private readonly IAuthorRepository _authorRepository; | |||||
private readonly ICustomerRepository _customerRepository; | |||||
private readonly AuthorManager _authorManager; | |||||
private readonly CustomerManager _customerManager; | |||||
public BookStoreDataSeederContributor(IRepository<Book, Guid> bookRepository, | |||||
IAuthorRepository authorRepository, | |||||
AuthorManager authorManager, | |||||
ICustomerRepository customerRepository, | |||||
CustomerManager customerManager | |||||
) | |||||
{ | |||||
_bookRepository = bookRepository; | |||||
_authorRepository = authorRepository; | |||||
_authorManager = authorManager; | |||||
_customerRepository = customerRepository; | |||||
_customerManager = customerManager; | |||||
} | |||||
public async Task SeedAsync(DataSeedContext context) | |||||
{ | |||||
if (await _bookRepository.GetCountAsync() <= 0) | |||||
{ | |||||
await _bookRepository.InsertAsync( | |||||
new Book | |||||
{ | |||||
Name = "1984", | |||||
Type = BookType.Dystopia, | |||||
PublishDate = new DateTime(1949, 6, 8), | |||||
Price = 19.84f | |||||
}, | |||||
autoSave: true | |||||
); | |||||
await _bookRepository.InsertAsync( | |||||
new Book | |||||
{ | |||||
Name = "The Hitchhiker's Guide to the Galaxy", | |||||
Type = BookType.ScienceFiction, | |||||
PublishDate = new DateTime(1995, 9, 27), | |||||
Price = 42.0f | |||||
}, | |||||
autoSave: true | |||||
); | |||||
} | |||||
if (await _authorRepository.GetCountAsync() <= 0) | |||||
{ | |||||
await _authorRepository.InsertAsync( | |||||
await _authorManager.CreateAsync( | |||||
"George Orwell", | |||||
new DateTime(1903, 06, 25), | |||||
"Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)." | |||||
) | |||||
); | |||||
await _authorRepository.InsertAsync( | |||||
await _authorManager.CreateAsync( | |||||
"Douglas Adams", | |||||
new DateTime(1952, 03, 11), | |||||
"Douglas Adams was an English author, screenwriter, essayist, humorist, satirist and dramatist. Adams was an advocate for environmentalism and conservation, a lover of fast cars, technological innovation and the Apple Macintosh, and a self-proclaimed 'radical atheist'." | |||||
) | |||||
); | |||||
} | |||||
if (await _customerRepository.GetCountAsync() <= 0) | |||||
{ | |||||
Customer customer = new Customer(1, "soumen", "pal", "9091184026", "haripal"); | |||||
await _customerRepository.InsertAsync( | |||||
await _customerManager.CreateAsync(customer) | |||||
); | |||||
} | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,20 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Domain.Entities.Auditing; | |||||
namespace Acme.BookStore.Books | |||||
{ | |||||
public class Book : AuditedAggregateRoot<Guid> | |||||
{ | |||||
public string Name { get; set; } | |||||
public BookType Type { get; set; } | |||||
public DateTime PublishDate { get; set; } | |||||
public float Price { get; set; } | |||||
} | |||||
} |
@ -0,0 +1,60 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp; | |||||
using Volo.Abp.Domain.Entities.Auditing; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public class Customer : FullAuditedAggregateRoot<int> | |||||
{ | |||||
public string firstName { get; set; } | |||||
public string lastName { get; set; } | |||||
public string phone { get; set; } | |||||
public string address { get; set; } | |||||
private Customer() | |||||
{ | |||||
/* This constructor is for deserialization / ORM purpose */ | |||||
} | |||||
internal Customer(int id, string firstName, string lastName, string phone, string address) : base(id) | |||||
{ | |||||
this.firstName = firstName; | |||||
this.lastName = lastName; | |||||
this.phone = phone; | |||||
this.address = address; | |||||
} | |||||
internal Customer ChangeFirstName(string firstname) | |||||
{ | |||||
SetFirstName(firstname); | |||||
return this; | |||||
} | |||||
private void SetFirstName(string firstName) | |||||
{ | |||||
firstName = Check.NotNullOrWhiteSpace( | |||||
firstName, | |||||
nameof(firstName), | |||||
maxLength: CustomerConsts.MaxNameLength | |||||
); | |||||
this.firstName = firstName; | |||||
} | |||||
internal Customer ChangeLastName(string lastname) | |||||
{ | |||||
SetLastName(lastname); | |||||
return this; | |||||
} | |||||
private void SetLastName(string lastname) | |||||
{ | |||||
lastname = Check.NotNullOrWhiteSpace( | |||||
lastname, | |||||
nameof(lastname), | |||||
maxLength: CustomerConsts.MaxNameLength | |||||
); | |||||
this.lastName = lastname; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,18 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public class CustomerErrorException : BusinessException | |||||
{ | |||||
public CustomerErrorException(string phone) | |||||
: base(BookStoreDomainErrorCodes.CustomerPhoneAlreadyExists) | |||||
{ | |||||
WithData("phone", phone); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,55 @@ | |||||
using Acme.BookStore.Authors; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Guids; | |||||
using Volo.Abp; | |||||
using Volo.Abp.Domain.Services; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public class CustomerManager : DomainService | |||||
{ | |||||
private readonly ICustomerRepository _customerRepository; | |||||
public CustomerManager(ICustomerRepository customerRepository) | |||||
{ | |||||
_customerRepository = customerRepository; | |||||
} | |||||
public async Task<Customer> CreateAsync( | |||||
Customer customer) | |||||
{ | |||||
Check.NotNullOrWhiteSpace(customer.firstName, nameof(customer.firstName)); | |||||
Check.NotNullOrWhiteSpace(customer.lastName, nameof(customer.lastName)); | |||||
var existingAuthor = await _customerRepository.FindByPhoneAsync(customer.phone); | |||||
if (existingAuthor != null) | |||||
{ | |||||
throw new CustomerErrorException(customer.phone); | |||||
} | |||||
return new Customer( | |||||
await _customerRepository.NewCustomerId(), | |||||
customer.firstName, | |||||
customer.lastName, | |||||
customer.phone, | |||||
customer.address | |||||
); | |||||
} | |||||
public async Task ChangeNameAsync( | |||||
Customer customer, | |||||
string firstName,string lastName) | |||||
{ | |||||
Check.NotNull(customer, nameof(customer)); | |||||
Check.NotNullOrWhiteSpace(customer.firstName, nameof(customer.firstName)); | |||||
Check.NotNullOrWhiteSpace(customer.lastName, nameof(customer.lastName)); | |||||
customer.ChangeFirstName(firstName); | |||||
customer.ChangeLastName(lastName); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,16 @@ | |||||
using Acme.BookStore.Authors; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Domain.Repositories; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public interface ICustomerRepository : IRepository<Customer, int> | |||||
{ | |||||
Task<Customer> FindByPhoneAsync(string phone); | |||||
Task<int> NewCustomerId(); | |||||
} | |||||
} |
@ -0,0 +1,56 @@ | |||||
using Acme.BookStore.EntityFrameworkCore; | |||||
using Microsoft.EntityFrameworkCore; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; | |||||
using Volo.Abp.EntityFrameworkCore; | |||||
namespace Acme.BookStore.Authors | |||||
{ | |||||
public class EfCoreAuthorRepository | |||||
: EfCoreRepository<BookStoreDbContext, Author, Guid>, | |||||
IAuthorRepository | |||||
{ | |||||
public EfCoreAuthorRepository( | |||||
IDbContextProvider<BookStoreDbContext> dbContextProvider) | |||||
: base(dbContextProvider) | |||||
{ | |||||
} | |||||
public async Task<Author> FindByNameAsync(string name) | |||||
{ | |||||
var dbSet = await GetDbSetAsync(); | |||||
return await dbSet.FirstOrDefaultAsync(author => author.Name == name); | |||||
} | |||||
public async Task<List<Author>> GetListAsync( | |||||
int skipCount, | |||||
int maxResultCount, | |||||
string sorting, | |||||
string filter = null) | |||||
{ | |||||
var dbSet = await GetDbSetAsync(); | |||||
return await dbSet.WhereIf( | |||||
!filter.IsNullOrEmpty(), | |||||
author=>author.Name.Contains(filter)).OrderBy(author=> author.Name).Skip(skipCount).Take(maxResultCount).ToListAsync(); | |||||
//return await dbSet | |||||
// .WhereIf( | |||||
// !filter.IsNullOrWhiteSpace(), | |||||
// author => author.Name.Contains(filter) | |||||
// ) | |||||
// .OrderBy(sorting) | |||||
// .Skip(skipCount) | |||||
// .Take(maxResultCount) | |||||
// .ToListAsync(); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,85 @@ | |||||
using Acme.BookStore.Customers; | |||||
using Acme.BookStore.EntityFrameworkCore; | |||||
using Microsoft.EntityFrameworkCore; | |||||
using Polly; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp; | |||||
using Volo.Abp.Data; | |||||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; | |||||
using Volo.Abp.EntityFrameworkCore; | |||||
using static Microsoft.EntityFrameworkCore.DbLoggerCategory; | |||||
namespace Acme.BookStore.BookIssued | |||||
{ | |||||
public class EfCoreBookIssueRepository : EfCoreRepository<BookStoreDbContext, BookIssue, int>, | |||||
IBookIssueRepository | |||||
{ | |||||
private readonly IDataFilter _dataFilter; | |||||
public EfCoreBookIssueRepository( | |||||
IDbContextProvider<BookStoreDbContext> dbContextProvider, IDataFilter dataFilter | |||||
) | |||||
: base(dbContextProvider) | |||||
{ | |||||
_dataFilter = dataFilter; | |||||
} | |||||
public async Task<BookIssueList> FindBookIssueCustomer(int customerId, Guid bookId) | |||||
{ | |||||
//var dbSet = await GetDbSetAsync(); | |||||
var dbContext = await GetDbContextAsync(); | |||||
List<BookIssueList> item = ( | |||||
from bi in dbContext.bookIssues | |||||
join cu in dbContext.Customers on bi.customerId equals cu.Id | |||||
join bk in dbContext.Books on bi.bookId equals bk.Id | |||||
where (bi.customerId == customerId && bi.bookId == bookId && bi.IsDeleted == false) | |||||
select new BookIssueList | |||||
{ | |||||
bookIssueId = bi.Id, | |||||
bookName = bk.Name, | |||||
customerName = cu.firstName + " " + cu.lastName, | |||||
issueDate = bi.CreationTime | |||||
}).ToList(); | |||||
return item == null? null : item.FirstOrDefault(); | |||||
} | |||||
public async Task<int> NewBookIssueId() | |||||
{ | |||||
using (_dataFilter.Disable<ISoftDelete>()) | |||||
{ | |||||
var dbSet = await GetDbSetAsync(); | |||||
var values = await dbSet.MaxAsync(u => (int?)u.Id); | |||||
return values == null ? 0 + 1 : (int)values + 1; | |||||
} | |||||
} | |||||
public async Task<List<BookIssueList>> BookIssueList() | |||||
{ | |||||
var dbContext = await GetDbContextAsync(); | |||||
List<BookIssueList> item = ( | |||||
from bi in dbContext.bookIssues | |||||
join cu in dbContext.Customers on bi.customerId equals cu.Id | |||||
join bk in dbContext.Books on bi.bookId equals bk.Id | |||||
select new BookIssueList | |||||
{ | |||||
bookIssueId = bi.Id, | |||||
bookName = bk.Name, | |||||
customerName = cu.firstName + " " + cu.lastName, | |||||
issueDate = bi.CreationTime | |||||
}).ToList(); | |||||
return item; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,40 @@ | |||||
using Acme.BookStore.Authors; | |||||
using Acme.BookStore.EntityFrameworkCore; | |||||
using Microsoft.EntityFrameworkCore; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; | |||||
using Volo.Abp.EntityFrameworkCore; | |||||
namespace Acme.BookStore.Customers | |||||
{ | |||||
public class EfCoreCustomerRepository : EfCoreRepository<BookStoreDbContext, Customer, int>, | |||||
ICustomerRepository | |||||
{ | |||||
public EfCoreCustomerRepository( | |||||
IDbContextProvider<BookStoreDbContext> dbContextProvider) | |||||
: base(dbContextProvider) | |||||
{ | |||||
} | |||||
public async Task<Customer> FindByPhoneAsync(string phone) | |||||
{ | |||||
var dbSet = await GetDbSetAsync(); | |||||
return await dbSet.FirstOrDefaultAsync(cust => cust.phone == phone); | |||||
} | |||||
public async Task<int> NewCustomerId() | |||||
{ | |||||
var dbSet = await GetDbSetAsync(); | |||||
var values = await dbSet.MaxAsync(u => (int?)u.Id); | |||||
return values == null ? 0 +1: (int)values + 1; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,43 @@ | |||||
using System; | |||||
using Microsoft.EntityFrameworkCore.Migrations; | |||||
#nullable disable | |||||
namespace Acme.BookStore.Migrations | |||||
{ | |||||
/// <inheritdoc /> | |||||
public partial class Created_Book_Entity : Migration | |||||
{ | |||||
/// <inheritdoc /> | |||||
protected override void Up(MigrationBuilder migrationBuilder) | |||||
{ | |||||
migrationBuilder.CreateTable( | |||||
name: "AppBooks", | |||||
columns: table => new | |||||
{ | |||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), | |||||
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), | |||||
Type = table.Column<int>(type: "int", nullable: false), | |||||
PublishDate = table.Column<DateTime>(type: "datetime2", nullable: false), | |||||
Price = table.Column<float>(type: "real", nullable: false), | |||||
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false), | |||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false), | |||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), | |||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), | |||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true) | |||||
}, | |||||
constraints: table => | |||||
{ | |||||
table.PrimaryKey("PK_AppBooks", x => x.Id); | |||||
}); | |||||
} | |||||
/// <inheritdoc /> | |||||
protected override void Down(MigrationBuilder migrationBuilder) | |||||
{ | |||||
migrationBuilder.DropTable( | |||||
name: "AppBooks"); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,50 @@ | |||||
using System; | |||||
using Microsoft.EntityFrameworkCore.Migrations; | |||||
#nullable disable | |||||
namespace Acme.BookStore.Migrations | |||||
{ | |||||
/// <inheritdoc /> | |||||
public partial class Added_Authors : Migration | |||||
{ | |||||
/// <inheritdoc /> | |||||
protected override void Up(MigrationBuilder migrationBuilder) | |||||
{ | |||||
migrationBuilder.CreateTable( | |||||
name: "AppAuthors", | |||||
columns: table => new | |||||
{ | |||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), | |||||
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false), | |||||
BirthDate = table.Column<DateTime>(type: "datetime2", nullable: false), | |||||
ShortBio = table.Column<string>(type: "nvarchar(max)", nullable: false), | |||||
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false), | |||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false), | |||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), | |||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), | |||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false), | |||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true) | |||||
}, | |||||
constraints: table => | |||||
{ | |||||
table.PrimaryKey("PK_AppAuthors", x => x.Id); | |||||
}); | |||||
migrationBuilder.CreateIndex( | |||||
name: "IX_AppAuthors_Name", | |||||
table: "AppAuthors", | |||||
column: "Name"); | |||||
} | |||||
/// <inheritdoc /> | |||||
protected override void Down(MigrationBuilder migrationBuilder) | |||||
{ | |||||
migrationBuilder.DropTable( | |||||
name: "AppAuthors"); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,47 @@ | |||||
using System; | |||||
using Microsoft.EntityFrameworkCore.Migrations; | |||||
#nullable disable | |||||
namespace Acme.BookStore.Migrations | |||||
{ | |||||
/// <inheritdoc /> | |||||
public partial class Added_Customers : Migration | |||||
{ | |||||
/// <inheritdoc /> | |||||
protected override void Up(MigrationBuilder migrationBuilder) | |||||
{ | |||||
migrationBuilder.CreateTable( | |||||
name: "AppCustomers", | |||||
columns: table => new | |||||
{ | |||||
Id = table.Column<int>(type: "int", nullable: false) | |||||
.Annotation("SqlServer:Identity", "1, 1"), | |||||
firstName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false), | |||||
lastName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false), | |||||
phone = table.Column<string>(type: "nvarchar(14)", maxLength: 14, nullable: false), | |||||
address = table.Column<string>(type: "nvarchar(max)", nullable: false), | |||||
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false), | |||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false), | |||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), | |||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), | |||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false), | |||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true) | |||||
}, | |||||
constraints: table => | |||||
{ | |||||
table.PrimaryKey("PK_AppCustomers", x => x.Id); | |||||
}); | |||||
} | |||||
/// <inheritdoc /> | |||||
protected override void Down(MigrationBuilder migrationBuilder) | |||||
{ | |||||
migrationBuilder.DropTable( | |||||
name: "AppCustomers"); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,50 @@ | |||||
using System; | |||||
using Microsoft.EntityFrameworkCore.Migrations; | |||||
#nullable disable | |||||
namespace Acme.BookStore.Migrations | |||||
{ | |||||
/// <inheritdoc /> | |||||
public partial class Added_BookIssued : Migration | |||||
{ | |||||
/// <inheritdoc /> | |||||
protected override void Up(MigrationBuilder migrationBuilder) | |||||
{ | |||||
migrationBuilder.EnsureSchema( | |||||
name: "BKN"); | |||||
migrationBuilder.CreateTable( | |||||
name: "AppBookIssued", | |||||
schema: "BKN", | |||||
columns: table => new | |||||
{ | |||||
Id = table.Column<int>(type: "int", nullable: false) | |||||
.Annotation("SqlServer:Identity", "1, 1"), | |||||
bookId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), | |||||
customerId = table.Column<int>(type: "int", nullable: false), | |||||
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false), | |||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false), | |||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), | |||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), | |||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false), | |||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), | |||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true) | |||||
}, | |||||
constraints: table => | |||||
{ | |||||
table.PrimaryKey("PK_AppBookIssued", x => x.Id); | |||||
}); | |||||
} | |||||
/// <inheritdoc /> | |||||
protected override void Down(MigrationBuilder migrationBuilder) | |||||
{ | |||||
migrationBuilder.DropTable( | |||||
name: "AppBookIssued", | |||||
schema: "BKN"); | |||||
} | |||||
} | |||||
} |