From d5b4dfeaca3e1713bd0134717dfce18312b4ec84 Mon Sep 17 00:00:00 2001 From: tanshu Date: Fri, 26 Mar 2021 08:53:17 +0530 Subject: [PATCH] Feature: The guestbook now autocompletes on phone number --- barker/barker/main.py | 2 + barker/barker/routers/customer.py | 12 ++++++ barker/barker/schemas/customer.py | 2 +- barker/barker/schemas/guest_book.py | 2 +- bookie/src/app/guest-book/customer.ts | 12 ++++++ .../guest-book-detail.component.html | 20 ++++++++- .../guest-book-detail.component.ts | 41 ++++++++++++++++--- .../src/app/guest-book/guest-book.module.ts | 2 + .../src/app/guest-book/guest-book.service.ts | 11 +++++ .../product-list/product-list.component.ts | 1 - .../tax-detail/tax-detail.component.html | 1 + 11 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 bookie/src/app/guest-book/customer.ts diff --git a/barker/barker/main.py b/barker/barker/main.py index 2c0f032..ef197e5 100644 --- a/barker/barker/main.py +++ b/barker/barker/main.py @@ -7,6 +7,7 @@ from .core.config import settings from .db.base_class import Base from .db.session import engine from .routers import ( + customer, device, guest_book, header_footer, @@ -97,6 +98,7 @@ app.include_router(sale_report.router, prefix="/api/sale-report", tags=["reports app.include_router(tax_report.router, prefix="/api/tax-report", tags=["reports"]) app.include_router(guest_book.router, prefix="/api/guest-book", tags=["guest-book"]) +app.include_router(customer.router, prefix="/api/customers", tags=["guest-book"]) app.include_router(show.router, prefix="/api/voucher", tags=["voucher"]) app.include_router(save.router, prefix="/api/voucher", tags=["voucher"]) app.include_router(update.router, prefix="/api/voucher", tags=["voucher"]) diff --git a/barker/barker/routers/customer.py b/barker/barker/routers/customer.py index aa15139..1aed153 100644 --- a/barker/barker/routers/customer.py +++ b/barker/barker/routers/customer.py @@ -106,6 +106,18 @@ def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user) return [customer_info(item) for item in db.query(Customer).order_by(Customer.name).all()] +@router.get("/query", response_model=List[schemas.Customer]) +async def show_term( + q: str, + db: Session = Depends(get_db), + current_user: UserToken = Depends(get_user), +) -> List[schemas.Customer]: + return [ + customer_info(item) + for item in db.query(Customer).filter(Customer.phone.ilike(f"%{q}%")).order_by(Customer.name).all() + ] + + @router.get("/{id_}", response_model=schemas.Customer) def show_id( id_: uuid.UUID, diff --git a/barker/barker/schemas/customer.py b/barker/barker/schemas/customer.py index 341f59a..0f4f018 100644 --- a/barker/barker/schemas/customer.py +++ b/barker/barker/schemas/customer.py @@ -10,7 +10,7 @@ from . import to_camel class CustomerIn(BaseModel): name: str = Field(..., min_length=1) phone: str = Field(..., min_length=1) - address: str + address: Optional[str] class Config: fields = {"id_": "id"} diff --git a/barker/barker/schemas/guest_book.py b/barker/barker/schemas/guest_book.py index 9ea3a3d..76ff8b0 100644 --- a/barker/barker/schemas/guest_book.py +++ b/barker/barker/schemas/guest_book.py @@ -11,7 +11,7 @@ from . import to_camel class GuestBookIn(BaseModel): name: str phone: str - address: str + address: Optional[str] pax: int = Field(ge=0) class Config: diff --git a/bookie/src/app/guest-book/customer.ts b/bookie/src/app/guest-book/customer.ts new file mode 100644 index 0000000..08aad4d --- /dev/null +++ b/bookie/src/app/guest-book/customer.ts @@ -0,0 +1,12 @@ +export class Customer { + name: string; + phone: string; + address: string; + + public constructor(init?: Partial) { + this.name = ''; + this.phone = ''; + this.address = ''; + Object.assign(this, init); + } +} diff --git a/bookie/src/app/guest-book/guest-book-detail/guest-book-detail.component.html b/bookie/src/app/guest-book/guest-book-detail/guest-book-detail.component.html index 6f2483b..cccf5e7 100644 --- a/bookie/src/app/guest-book/guest-book-detail/guest-book-detail.component.html +++ b/bookie/src/app/guest-book/guest-book-detail/guest-book-detail.component.html @@ -29,8 +29,26 @@ > Phone - + + + {{ customer.name }} - {{ customer.phone }} +
; constructor( private fb: FormBuilder, @@ -30,6 +36,14 @@ export class GuestBookDetailComponent implements OnInit, AfterViewInit { pax: ['0', Validators.required], address: null, }); + // Setup Account Autocomplete + this.customers = (this.form.get('phone') as FormControl).valueChanges.pipe( + startWith(null), + map((x) => (x !== null && x.length >= 1 ? x : null)), + debounceTime(150), + distinctUntilChanged(), + switchMap((x) => (x === null ? observableOf([]) : this.ser.autocomplete(x))), + ); } ngOnInit() { @@ -41,8 +55,8 @@ export class GuestBookDetailComponent implements OnInit, AfterViewInit { ngAfterViewInit() { setTimeout(() => { - if (this.nameElement !== undefined) { - this.nameElement.nativeElement.focus(); + if (this.phoneElement !== undefined) { + this.phoneElement.nativeElement.focus(); } }, 0); } @@ -69,10 +83,27 @@ export class GuestBookDetailComponent implements OnInit, AfterViewInit { ); } + displayFn(customer?: Customer): string { + return customer ? customer.phone : ''; + } + + selected(event: MatAutocompleteSelectedEvent): void { + const customer = event.option.value; + this.form.patchValue({ + name: customer.name, + // phone: customer.phone, + address: customer.address, + }); + } + getItem(): GuestBook { const formModel = this.form.value; this.item.name = formModel.name; - this.item.phone = formModel.phone; + if (typeof formModel.phone === 'string') { + this.item.phone = formModel.phone; + } else { + this.item.phone = (formModel.phone as Customer).phone; + } this.item.pax = parseInt(formModel.pax, 10); this.item.address = formModel.address; return this.item; diff --git a/bookie/src/app/guest-book/guest-book.module.ts b/bookie/src/app/guest-book/guest-book.module.ts index b66e883..10dc58c 100644 --- a/bookie/src/app/guest-book/guest-book.module.ts +++ b/bookie/src/app/guest-book/guest-book.module.ts @@ -3,6 +3,7 @@ import { NgModule } from '@angular/core'; import { FlexLayoutModule } from '@angular/flex-layout'; import { ReactiveFormsModule } from '@angular/forms'; import { MomentDateAdapter } from '@angular/material-moment-adapter'; +import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { @@ -53,6 +54,7 @@ export const MY_FORMATS = { FlexLayoutModule, GuestBookRoutingModule, SharedModule, + MatAutocompleteModule, ], providers: [ { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] }, diff --git a/bookie/src/app/guest-book/guest-book.service.ts b/bookie/src/app/guest-book/guest-book.service.ts index 1cfc795..5da050a 100644 --- a/bookie/src/app/guest-book/guest-book.service.ts +++ b/bookie/src/app/guest-book/guest-book.service.ts @@ -5,6 +5,7 @@ import { catchError } from 'rxjs/operators'; import { ErrorLoggerService } from '../core/error-logger.service'; +import { Customer } from './customer'; import { GuestBook } from './guest-book'; import { GuestBookList } from './guest-book-list'; @@ -13,6 +14,7 @@ const httpOptions = { }; const url = '/api/guest-book'; +const customerUrl = '/api/customers'; const serviceName = 'GuestBookService'; @Injectable({ providedIn: 'root' }) @@ -57,4 +59,13 @@ export class GuestBookService { .delete(`${url}/${id}`, httpOptions) .pipe(catchError(this.log.handleError(serviceName, 'delete'))) as Observable; } + + autocomplete(query: string): Observable { + const options = { params: new HttpParams().set('q', query) }; + return this.http + .get(`${customerUrl}/query`, options) + .pipe(catchError(this.log.handleError(serviceName, 'autocomplete'))) as Observable< + Customer[] + >; + } } diff --git a/bookie/src/app/product/product-list/product-list.component.ts b/bookie/src/app/product/product-list/product-list.component.ts index 374da9c..953654a 100644 --- a/bookie/src/app/product/product-list/product-list.component.ts +++ b/bookie/src/app/product/product-list/product-list.component.ts @@ -14,7 +14,6 @@ import { ProductService } from '../product.service'; import { ProductListDataSource } from './product-list-datasource'; - @Component({ selector: 'app-product-list', templateUrl: './product-list.component.html', diff --git a/bookie/src/app/taxes/tax-detail/tax-detail.component.html b/bookie/src/app/taxes/tax-detail/tax-detail.component.html index 25c408e..52a56f5 100644 --- a/bookie/src/app/taxes/tax-detail/tax-detail.component.html +++ b/bookie/src/app/taxes/tax-detail/tax-detail.component.html @@ -21,6 +21,7 @@ formControlName="name" (keyup.enter)="save()" /> + Format for GST: ST GST @ x% (1/2) ; CGST @ x% (1/2)