From efd9d1da7a6f74650609b81e2abba9a7547ba76f Mon Sep 17 00:00:00 2001 From: Amritanshu Date: Tue, 15 Jul 2025 17:26:42 +0000 Subject: [PATCH] Support date query param for journal / payment / reciept voucher --- brewman/brewman/routers/__init__.py | 10 ++ brewman/brewman/routers/journal.py | 31 ++--- overlord/src/app/core/voucher.service.ts | 13 +- .../employee-benefits.resolver.ts | 3 +- .../src/app/incentive/incentive.resolver.ts | 3 +- overlord/src/app/issue/issue.component.ts | 89 ++++--------- overlord/src/app/issue/issue.resolver.ts | 3 +- overlord/src/app/journal/journal.component.ts | 120 +++++++----------- overlord/src/app/journal/journal.resolver.ts | 3 +- overlord/src/app/payment/payment.component.ts | 117 +++++++---------- overlord/src/app/payment/payment.resolver.ts | 6 +- .../purchase-return.component.ts | 93 ++++---------- .../purchase-return.resolver.ts | 2 +- .../src/app/purchase/purchase.component.ts | 93 ++++---------- .../src/app/purchase/purchase.resolver.ts | 2 +- overlord/src/app/receipt/receipt.component.ts | 118 +++++++---------- overlord/src/app/receipt/receipt.resolver.ts | 6 +- 17 files changed, 264 insertions(+), 448 deletions(-) diff --git a/brewman/brewman/routers/__init__.py b/brewman/brewman/routers/__init__.py index 3a74c13d..03841d11 100644 --- a/brewman/brewman/routers/__init__.py +++ b/brewman/brewman/routers/__init__.py @@ -1,9 +1,12 @@ from collections.abc import Sequence from datetime import UTC, date, datetime, timedelta +from fastapi import Request from sqlalchemy import or_, select from sqlalchemy.orm import Session +from brewman.core.session import get_date + from ..models.db_setting import DbSetting from ..models.setting_type import SettingType from ..models.voucher_type import VoucherType @@ -83,3 +86,10 @@ def effective_date(d: str | None = None) -> date: if d is None else datetime.strptime(d, "%d-%b-%Y").date() ) + + +def session_or_query_date(request: Request, d: str | None = None) -> date: + if d: + return datetime.strptime(d, "%d-%b-%Y").date() + session_date_str = get_date(request.session) + return datetime.strptime(session_date_str, "%d-%b-%Y").date() diff --git a/brewman/brewman/routers/journal.py b/brewman/brewman/routers/journal.py index c97fd26b..cdcf9e97 100644 --- a/brewman/brewman/routers/journal.py +++ b/brewman/brewman/routers/journal.py @@ -1,6 +1,6 @@ import uuid -from datetime import UTC, datetime +from datetime import UTC, date, datetime from fastapi import APIRouter, Depends, File, HTTPException, Request, Security, status from sqlalchemy import distinct, select @@ -8,7 +8,7 @@ from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import Session from ..core.security import get_current_active_user as get_user -from ..core.session import get_date, set_date +from ..core.session import set_date from ..db.session import SessionFuture from ..models.account_base import AccountBase from ..models.journal import Journal @@ -20,7 +20,7 @@ from ..schemas import voucher as output from ..schemas.account import AccountLink from ..schemas.blank_voucher_info import BlankVoucherInfo from ..schemas.user import UserToken -from . import get_lock_info +from . import get_lock_info, session_or_query_date from .db_image import save_files, update_files from .tag import save_tags, update_tags from .voucher import blank_voucher, check_voucher_edit_allowed, voucher_info @@ -99,8 +99,8 @@ def update_route( t: list[bytes] = File(None), user: UserToken = Security(get_user, scopes=["journal"]), ) -> output.Voucher: - try: - with SessionFuture() as db: + with SessionFuture() as db: + try: item: Voucher = update_voucher(id_, data, user, db) check_journals_are_valid(item) update_files(item.id, data.files, i, t, db) @@ -108,15 +108,15 @@ def update_route( db.commit() set_date(data.date_.strftime("%d-%b-%Y"), request.session) return voucher_info(item, db) - except SQLAlchemyError as e: - db.rollback() - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=str(e), - ) - except Exception: - db.rollback() - raise + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=str(e), + ) + except Exception: + db.rollback() + raise def update_voucher(id_: uuid.UUID, data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher: @@ -192,6 +192,7 @@ def get_id( def show_blank( request: Request, a: uuid.UUID | None = None, + date_: date = Depends(session_or_query_date), user: UserToken = Security(get_user, scopes=["journal"]), ) -> output.Voucher: if request.scope.get("path") == "/api/payment": @@ -201,7 +202,7 @@ def show_blank( else: type_ = VoucherType.JOURNAL - additional_info = BlankVoucherInfo(date_=get_date(request.session), type_=type_) # type: ignore[arg-type] + additional_info = BlankVoucherInfo(date_=date_, type_=type_) # type: ignore[arg-type] if a: additional_info.account = AccountLink(id_=a) with SessionFuture() as db: diff --git a/overlord/src/app/core/voucher.service.ts b/overlord/src/app/core/voucher.service.ts index ee4d74f2..1b1cdb41 100644 --- a/overlord/src/app/core/voucher.service.ts +++ b/overlord/src/app/core/voucher.service.ts @@ -38,11 +38,16 @@ export class VoucherService { .pipe(catchError(this.log.handleError(serviceName, 'Get Voucher'))) as Observable; } - getOfType(type: string, account?: string): Observable { + getOfType(type: string, account: string | null, date: string | null): Observable { const endpoint = type.replace(/ /g, '-').toLowerCase(); - let options = {}; - if (account !== undefined && account !== null) { - options = { params: new HttpParams().set('a', account) }; + const options = { + params: new HttpParams(), + }; + if (account !== null) { + options.params = options.params.set('a', account); + } + if (date !== null) { + options.params = options.params.set('d', date); } return this.http .get(`${url}/${endpoint}`, options) diff --git a/overlord/src/app/employee-benefits/employee-benefits.resolver.ts b/overlord/src/app/employee-benefits/employee-benefits.resolver.ts index efee72e7..e92ffe0a 100644 --- a/overlord/src/app/employee-benefits/employee-benefits.resolver.ts +++ b/overlord/src/app/employee-benefits/employee-benefits.resolver.ts @@ -6,8 +6,9 @@ import { VoucherService } from '../core/voucher.service'; export const employeeBenefitsResolver: ResolveFn = (route) => { const id = route.paramMap.get('id'); + const date = route.queryParamMap.get('d') || null; if (id === null) { - return inject(VoucherService).getOfType('Employee Benefit'); + return inject(VoucherService).getOfType('Employee Benefit', null, date); } return inject(VoucherService).get(id, 'Employee Benefit'); }; diff --git a/overlord/src/app/incentive/incentive.resolver.ts b/overlord/src/app/incentive/incentive.resolver.ts index e10a47f8..09144136 100644 --- a/overlord/src/app/incentive/incentive.resolver.ts +++ b/overlord/src/app/incentive/incentive.resolver.ts @@ -6,8 +6,9 @@ import { VoucherService } from '../core/voucher.service'; export const incentiveResolver: ResolveFn = (route) => { const id = route.paramMap.get('id'); + const date = route.queryParamMap.get('d') || null; if (id === null) { - return inject(VoucherService).getOfType('Incentive'); + return inject(VoucherService).getOfType('Incentive', null, date); } return inject(VoucherService).get(id, 'Incentive'); }; diff --git a/overlord/src/app/issue/issue.component.ts b/overlord/src/app/issue/issue.component.ts index 231b74ee..7fb0210d 100644 --- a/overlord/src/app/issue/issue.component.ts +++ b/overlord/src/app/issue/issue.component.ts @@ -1,37 +1,19 @@ import { AsyncPipe, CurrencyPipe, DecimalPipe } from '@angular/common'; import { AfterViewInit, Component, ElementRef, HostListener, inject, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { MatButton, MatIconButton } from '@angular/material/button'; -import { - MatCard, - MatCardActions, - MatCardContent, - MatCardFooter, - MatCardHeader, - MatCardTitle, -} from '@angular/material/card'; -import { MatOption } from '@angular/material/core'; -import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker'; +import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatOptionModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialog } from '@angular/material/dialog'; -import { MatFormField, MatLabel, MatPrefix, MatSuffix } from '@angular/material/form-field'; -import { MatIcon } from '@angular/material/icon'; -import { MatInput } from '@angular/material/input'; -import { MatSelect } from '@angular/material/select'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; -import { - MatCell, - MatCellDef, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatHeaderRow, - MatHeaderRowDef, - MatRow, - MatRowDef, - MatTable, -} from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import { round } from 'mathjs'; import moment from 'moment'; @@ -60,39 +42,18 @@ import { IssueGridService } from './issue-grid.service'; templateUrl: './issue.component.html', styleUrls: ['./issue.component.css'], imports: [ - MatCard, - MatCardHeader, - MatCardTitle, - MatCardContent, + MatCardModule, ReactiveFormsModule, - MatFormField, - MatLabel, - MatInput, - MatDatepickerInput, - MatDatepickerToggle, - MatSuffix, - MatDatepicker, - MatSelect, - MatOption, - MatPrefix, - MatAutocompleteTrigger, - MatAutocomplete, - MatButton, - MatTable, - MatSort, - MatColumnDef, - MatHeaderCellDef, - MatHeaderCell, - MatCellDef, - MatCell, - MatIconButton, - MatIcon, - MatHeaderRowDef, - MatHeaderRow, - MatRowDef, - MatRow, - MatCardActions, - MatCardFooter, + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + MatSelectModule, + MatOptionModule, + MatAutocompleteModule, + MatIconModule, + MatButtonModule, + MatTableModule, + MatSortModule, AsyncPipe, DecimalPipe, CurrencyPipe, @@ -133,7 +94,7 @@ export class IssueComponent implements OnInit, AfterViewInit { dataSource: IssueDataSource = new IssueDataSource(this.inventoryObservable); gridDataSource: IssueGridDataSource = new IssueGridDataSource(this.gridObservable); form: FormGroup<{ - date: FormControl; + date: FormControl; source: FormControl; destination: FormControl; amount: FormControl; @@ -155,7 +116,7 @@ export class IssueComponent implements OnInit, AfterViewInit { constructor() { this.form = new FormGroup({ - date: new FormControl(new Date(), { nonNullable: true }), + date: new FormControl(moment(new Date()), { nonNullable: true }), source: new FormControl(null), destination: new FormControl(null), amount: new FormControl({ value: 0, disabled: true }, { nonNullable: true }), @@ -198,7 +159,7 @@ export class IssueComponent implements OnInit, AfterViewInit { loadVoucher(voucher: Voucher) { this.voucher = voucher; this.form.setValue({ - date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(), + date: moment(this.voucher.date, 'DD-MMM-YYYY'), source: (this.voucher.source as CostCentre).id ?? '', destination: (this.voucher.destination as CostCentre).id ?? '', amount: Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)), diff --git a/overlord/src/app/issue/issue.resolver.ts b/overlord/src/app/issue/issue.resolver.ts index 4a746e82..1c65d96b 100644 --- a/overlord/src/app/issue/issue.resolver.ts +++ b/overlord/src/app/issue/issue.resolver.ts @@ -6,8 +6,9 @@ import { VoucherService } from '../core/voucher.service'; export const issueResolver: ResolveFn = (route) => { const id = route.paramMap.get('id'); + const date = route.queryParamMap.get('d') || null; if (id === null) { - return inject(VoucherService).getOfType('Issue'); + return inject(VoucherService).getOfType('Issue', null, date); } return inject(VoucherService).get(id, 'Issue'); }; diff --git a/overlord/src/app/journal/journal.component.ts b/overlord/src/app/journal/journal.component.ts index 76bd75d3..fd9f117b 100644 --- a/overlord/src/app/journal/journal.component.ts +++ b/overlord/src/app/journal/journal.component.ts @@ -2,38 +2,20 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { AsyncPipe, CurrencyPipe } from '@angular/common'; import { AfterViewInit, Component, ElementRef, HostListener, inject, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { MatButton, MatIconButton } from '@angular/material/button'; -import { - MatCard, - MatCardActions, - MatCardContent, - MatCardHeader, - MatCardTitle, - MatCardTitleGroup, -} from '@angular/material/card'; -import { MatChipGrid, MatChipInput, MatChipInputEvent, MatChipRemove, MatChipRow } from '@angular/material/chips'; -import { MatOption } from '@angular/material/core'; -import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker'; +import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatChipInputEvent, MatChipsModule } from '@angular/material/chips'; +import { MatOptionModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialog } from '@angular/material/dialog'; -import { MatFormField, MatHint, MatLabel, MatPrefix, MatSuffix } from '@angular/material/form-field'; -import { MatIcon } from '@angular/material/icon'; -import { MatInput } from '@angular/material/input'; -import { MatSelect } from '@angular/material/select'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; -import { - MatCell, - MatCellDef, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatHeaderRow, - MatHeaderRowDef, - MatRow, - MatRowDef, - MatTable, -} from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import { round } from 'mathjs'; import moment from 'moment'; @@ -65,44 +47,19 @@ import { JournalDialogComponent } from './journal-dialog.component'; templateUrl: './journal.component.html', styleUrls: ['./journal.component.css'], imports: [ - MatCard, - MatCardHeader, - MatCardTitleGroup, - MatCardTitle, - MatIcon, - MatSuffix, - MatCardContent, + MatCardModule, + MatIconModule, ReactiveFormsModule, - MatFormField, - MatLabel, - MatInput, - MatDatepickerInput, - MatDatepickerToggle, - MatDatepicker, - MatSelect, - MatOption, - MatAutocompleteTrigger, - MatHint, - MatAutocomplete, - MatPrefix, - MatButton, - MatTable, - MatSort, - MatColumnDef, - MatHeaderCellDef, - MatHeaderCell, - MatCellDef, - MatCell, - MatIconButton, - MatHeaderRowDef, - MatHeaderRow, - MatRowDef, - MatRow, - MatChipGrid, - MatChipRow, - MatChipRemove, - MatChipInput, - MatCardActions, + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + MatSelectModule, + MatOptionModule, + MatAutocompleteModule, + MatButtonModule, + MatTableModule, + MatSortModule, + MatChipsModule, AsyncPipe, CurrencyPipe, AccountingPipe, @@ -135,13 +92,23 @@ export class JournalComponent implements OnInit, AfterViewInit { @HostListener('window:keydown.f5', ['$event']) redirectToPayment(event: KeyboardEvent) { event.preventDefault(); - this.router.navigate(['payment']); + this.router.navigate(['payment'], { + queryParams: { + d: this.form.controls.date.value.format('DD-MMM-YYYY'), + }, + queryParamsHandling: 'merge', + }); } @HostListener('window:keydown.f6', ['$event']) redirectToReciept(event: KeyboardEvent) { event.preventDefault(); - this.router.navigate(['receipt']); + this.router.navigate(['receipt'], { + queryParams: { + d: this.form.controls.date.value.format('DD-MMM-YYYY'), + }, + queryParamsHandling: 'merge', + }); } @HostListener('window:keydown.f7', ['$event']) @@ -169,7 +136,7 @@ export class JournalComponent implements OnInit, AfterViewInit { public journalObservable = new BehaviorSubject([]); dataSource: JournalDataSource = new JournalDataSource(this.journalObservable); form: FormGroup<{ - date: FormControl; + date: FormControl; addRow: FormGroup<{ debit: FormControl; account: FormControl; @@ -191,7 +158,7 @@ export class JournalComponent implements OnInit, AfterViewInit { constructor() { this.account = null; this.form = new FormGroup({ - date: new FormControl(new Date(), { nonNullable: true }), + date: new FormControl(moment(new Date()), { nonNullable: true }), addRow: new FormGroup({ debit: new FormControl(1, { nonNullable: true }), account: new FormControl(''), @@ -213,6 +180,15 @@ export class JournalComponent implements OnInit, AfterViewInit { map((tag: string | Tag | null) => (tag === null ? '' : typeof tag !== 'string' ? tag.name.toLowerCase() : tag)), switchMap((tag: string) => this.tagSer.autocomplete(tag)), ); + // Listen to Date Change + this.form.controls.date.valueChanges.subscribe((x) => + this.router.navigate([], { + relativeTo: this.route, + queryParams: { d: moment(x).format('DD-MMM-YYYY') }, + replaceUrl: true, + queryParamsHandling: 'merge', + }), + ); } ngOnInit() { @@ -230,7 +206,7 @@ export class JournalComponent implements OnInit, AfterViewInit { loadVoucher(voucher: Voucher) { this.voucher = voucher; this.form.setValue({ - date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(), + date: moment(this.voucher.date, 'DD-MMM-YYYY'), addRow: { debit: 1, account: null, diff --git a/overlord/src/app/journal/journal.resolver.ts b/overlord/src/app/journal/journal.resolver.ts index 8826f89b..7c42b5ea 100644 --- a/overlord/src/app/journal/journal.resolver.ts +++ b/overlord/src/app/journal/journal.resolver.ts @@ -6,8 +6,9 @@ import { VoucherService } from '../core/voucher.service'; export const journalResolver: ResolveFn = (route) => { const id = route.paramMap.get('id'); + const date = route.queryParamMap.get('d') || null; if (id === null) { - return inject(VoucherService).getOfType('Journal'); + return inject(VoucherService).getOfType('Journal', null, date); } return inject(VoucherService).get(id, 'Journal'); }; diff --git a/overlord/src/app/payment/payment.component.ts b/overlord/src/app/payment/payment.component.ts index 89f13927..401350ba 100644 --- a/overlord/src/app/payment/payment.component.ts +++ b/overlord/src/app/payment/payment.component.ts @@ -2,38 +2,20 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { AsyncPipe, CurrencyPipe } from '@angular/common'; import { AfterViewInit, Component, ElementRef, HostListener, inject, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { MatButton, MatIconButton } from '@angular/material/button'; -import { - MatCard, - MatCardActions, - MatCardContent, - MatCardHeader, - MatCardTitle, - MatCardTitleGroup, -} from '@angular/material/card'; -import { MatChipGrid, MatChipInput, MatChipInputEvent, MatChipRemove, MatChipRow } from '@angular/material/chips'; -import { MatOption } from '@angular/material/core'; -import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker'; +import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatChipInputEvent, MatChipsModule } from '@angular/material/chips'; +import { MatOptionModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialog } from '@angular/material/dialog'; -import { MatFormField, MatHint, MatLabel, MatPrefix, MatSuffix } from '@angular/material/form-field'; -import { MatIcon } from '@angular/material/icon'; -import { MatInput } from '@angular/material/input'; -import { MatSelect } from '@angular/material/select'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; -import { - MatCell, - MatCellDef, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatHeaderRow, - MatHeaderRowDef, - MatRow, - MatRowDef, - MatTable, -} from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import { round } from 'mathjs'; import moment from 'moment'; @@ -65,44 +47,19 @@ import { PaymentDialogComponent } from './payment-dialog.component'; templateUrl: './payment.component.html', styleUrls: ['./payment.component.css'], imports: [ - MatCard, - MatCardHeader, - MatCardTitleGroup, - MatCardTitle, - MatIcon, - MatSuffix, - MatCardContent, + MatCardModule, + MatIconModule, ReactiveFormsModule, - MatFormField, - MatLabel, - MatInput, - MatDatepickerInput, - MatDatepickerToggle, - MatDatepicker, - MatSelect, - MatOption, - MatPrefix, - MatAutocompleteTrigger, - MatHint, - MatAutocomplete, - MatButton, - MatTable, - MatSort, - MatColumnDef, - MatHeaderCellDef, - MatHeaderCell, - MatCellDef, - MatCell, - MatIconButton, - MatHeaderRowDef, - MatHeaderRow, - MatRowDef, - MatRow, - MatChipGrid, - MatChipRow, - MatChipRemove, - MatChipInput, - MatCardActions, + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + MatSelectModule, + MatOptionModule, + MatAutocompleteModule, + MatButtonModule, + MatTableModule, + MatSortModule, + MatChipsModule, AsyncPipe, CurrencyPipe, AccountingPipe, @@ -143,14 +100,22 @@ export class PaymentComponent implements OnInit, AfterViewInit { this.router.navigate(['receipt'], { queryParams: { a: this.form.controls.paymentAccount.value, + d: this.form.controls.date.value.format('DD-MMM-YYYY'), }, + queryParamsHandling: 'merge', }); } @HostListener('window:keydown.f7', ['$event']) redirectToJournal(event: KeyboardEvent) { event.preventDefault(); - this.router.navigate(['journal']); + this.router.navigate(['journal'], { + queryParams: { + a: this.form.controls.paymentAccount.value, + d: this.form.controls.date.value.format('DD-MMM-YYYY'), + }, + queryParamsHandling: 'merge', + }); } @HostListener('window:keydown.control.s', ['$event']) @@ -173,7 +138,7 @@ export class PaymentComponent implements OnInit, AfterViewInit { public journalObservable = new BehaviorSubject([]); dataSource: PaymentDataSource = new PaymentDataSource(this.journalObservable); form: FormGroup<{ - date: FormControl; + date: FormControl; paymentAccount: FormControl; paymentAmount: FormControl; addRow: FormGroup<{ @@ -198,7 +163,7 @@ export class PaymentComponent implements OnInit, AfterViewInit { constructor() { this.account = null; this.form = new FormGroup({ - date: new FormControl(new Date(), { nonNullable: true }), + date: new FormControl(moment(new Date()), { nonNullable: true }), paymentAccount: new FormControl('', { nonNullable: true }), paymentAmount: new FormControl({ value: 0, disabled: true }, { nonNullable: true }), addRow: new FormGroup({ @@ -221,12 +186,22 @@ export class PaymentComponent implements OnInit, AfterViewInit { map((tag: string | Tag | null) => (tag === null ? '' : typeof tag !== 'string' ? tag.name.toLowerCase() : tag)), switchMap((tag: string) => this.tagSer.autocomplete(tag)), ); + // Listen to Date Change + this.form.controls.date.valueChanges.subscribe((x) => + this.router.navigate([], { + relativeTo: this.route, + queryParams: { d: x.format('DD-MMM-YYYY') }, + replaceUrl: true, + queryParamsHandling: 'merge', + }), + ); // Listen to Payment Account Change this.form.controls.paymentAccount.valueChanges.subscribe((x) => this.router.navigate([], { relativeTo: this.route, queryParams: { a: x }, replaceUrl: true, + queryParamsHandling: 'merge', }), ); } @@ -248,7 +223,7 @@ export class PaymentComponent implements OnInit, AfterViewInit { this.voucher = voucher; [this.paymentJournal] = this.voucher.journals.filter((x) => x.debit === -1); this.form.setValue({ - date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(), + date: moment(this.voucher.date, 'DD-MMM-YYYY'), paymentAccount: this.paymentJournal.account.id ?? '', paymentAmount: this.paymentJournal.amount, addRow: { diff --git a/overlord/src/app/payment/payment.resolver.ts b/overlord/src/app/payment/payment.resolver.ts index 891a1177..a7827c18 100644 --- a/overlord/src/app/payment/payment.resolver.ts +++ b/overlord/src/app/payment/payment.resolver.ts @@ -7,11 +7,9 @@ import { VoucherService } from '../core/voucher.service'; export const paymentResolver: ResolveFn = (route) => { const id = route.paramMap.get('id'); const account = route.queryParamMap.get('a') || null; + const date = route.queryParamMap.get('d') || null; if (id !== null) { return inject(VoucherService).get(id, 'Payment'); } - if (account !== null) { - return inject(VoucherService).getOfType('Payment', account); - } - return inject(VoucherService).getOfType('Payment'); + return inject(VoucherService).getOfType('Payment', account, date); }; diff --git a/overlord/src/app/purchase-return/purchase-return.component.ts b/overlord/src/app/purchase-return/purchase-return.component.ts index 560e8045..694c0fac 100644 --- a/overlord/src/app/purchase-return/purchase-return.component.ts +++ b/overlord/src/app/purchase-return/purchase-return.component.ts @@ -2,37 +2,19 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { AsyncPipe, CurrencyPipe, DecimalPipe, PercentPipe } from '@angular/common'; import { AfterViewInit, Component, ElementRef, HostListener, inject, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { MatButton, MatIconButton } from '@angular/material/button'; -import { - MatCard, - MatCardActions, - MatCardContent, - MatCardHeader, - MatCardTitle, - MatCardTitleGroup, -} from '@angular/material/card'; -import { MatChipGrid, MatChipInput, MatChipInputEvent, MatChipRemove, MatChipRow } from '@angular/material/chips'; -import { MatOption } from '@angular/material/core'; -import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker'; +import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatChipInputEvent, MatChipsModule } from '@angular/material/chips'; +import { MatOptionModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialog } from '@angular/material/dialog'; -import { MatFormField, MatHint, MatLabel, MatPrefix, MatSuffix } from '@angular/material/form-field'; -import { MatIcon } from '@angular/material/icon'; -import { MatInput } from '@angular/material/input'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; -import { - MatCell, - MatCellDef, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatHeaderRow, - MatHeaderRowDef, - MatRow, - MatRowDef, - MatTable, -} from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import { round } from 'mathjs'; import moment from 'moment'; @@ -66,43 +48,18 @@ import { PurchaseReturnDialogComponent } from './purchase-return-dialog.componen templateUrl: './purchase-return.component.html', styleUrls: ['./purchase-return.component.css'], imports: [ - MatCard, - MatCardHeader, - MatCardTitleGroup, - MatCardTitle, - MatIcon, - MatSuffix, - MatCardContent, + MatCardModule, + MatIconModule, ReactiveFormsModule, - MatFormField, - MatLabel, - MatInput, - MatDatepickerInput, - MatDatepickerToggle, - MatDatepicker, - MatAutocompleteTrigger, - MatHint, - MatAutocomplete, - MatOption, - MatPrefix, - MatButton, - MatTable, - MatSort, - MatColumnDef, - MatHeaderCellDef, - MatHeaderCell, - MatCellDef, - MatCell, - MatIconButton, - MatHeaderRowDef, - MatHeaderRow, - MatRowDef, - MatRow, - MatChipGrid, - MatChipRow, - MatChipRemove, - MatChipInput, - MatCardActions, + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + MatAutocompleteModule, + MatOptionModule, + MatButtonModule, + MatTableModule, + MatSortModule, + MatChipsModule, AsyncPipe, DecimalPipe, PercentPipe, @@ -156,7 +113,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit { public inventoryObservable = new BehaviorSubject([]); dataSource: PurchaseReturnDataSource = new PurchaseReturnDataSource(this.inventoryObservable); form: FormGroup<{ - date: FormControl; + date: FormControl; account: FormControl; amount: FormControl; addRow: FormGroup<{ @@ -179,7 +136,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit { constructor() { this.form = new FormGroup({ - date: new FormControl(new Date(), { nonNullable: true }), + date: new FormControl(moment(new Date()), { nonNullable: true }), account: new FormControl(null), amount: new FormControl({ value: 0, disabled: true }, { nonNullable: true }), addRow: new FormGroup({ @@ -228,7 +185,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit { loadVoucher(voucher: Voucher) { this.voucher = voucher; this.form.setValue({ - date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(), + date: moment(this.voucher.date, 'DD-MMM-YYYY'), account: this.voucher.vendor?.name ?? null, amount: Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)), addRow: { diff --git a/overlord/src/app/purchase-return/purchase-return.resolver.ts b/overlord/src/app/purchase-return/purchase-return.resolver.ts index a5034315..f34f8322 100644 --- a/overlord/src/app/purchase-return/purchase-return.resolver.ts +++ b/overlord/src/app/purchase-return/purchase-return.resolver.ts @@ -7,7 +7,7 @@ import { VoucherService } from '../core/voucher.service'; export const purchaseReturnResolver: ResolveFn = (route) => { const id = route.paramMap.get('id'); if (id === null) { - return inject(VoucherService).getOfType('Purchase Return'); + return inject(VoucherService).getOfType('Purchase Return', null, null); } return inject(VoucherService).get(id, 'Purchase Return'); }; diff --git a/overlord/src/app/purchase/purchase.component.ts b/overlord/src/app/purchase/purchase.component.ts index b0ecab9f..2f9ae62c 100644 --- a/overlord/src/app/purchase/purchase.component.ts +++ b/overlord/src/app/purchase/purchase.component.ts @@ -2,37 +2,19 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { AsyncPipe, CurrencyPipe, DecimalPipe, PercentPipe } from '@angular/common'; import { AfterViewInit, Component, ElementRef, HostListener, inject, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { MatButton, MatIconButton } from '@angular/material/button'; -import { - MatCard, - MatCardActions, - MatCardContent, - MatCardHeader, - MatCardTitle, - MatCardTitleGroup, -} from '@angular/material/card'; -import { MatChipGrid, MatChipInput, MatChipInputEvent, MatChipRemove, MatChipRow } from '@angular/material/chips'; -import { MatOption } from '@angular/material/core'; -import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker'; +import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatChipInputEvent, MatChipsModule } from '@angular/material/chips'; +import { MatOptionModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialog } from '@angular/material/dialog'; -import { MatFormField, MatHint, MatLabel, MatPrefix, MatSuffix } from '@angular/material/form-field'; -import { MatIcon } from '@angular/material/icon'; -import { MatInput } from '@angular/material/input'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; -import { - MatCell, - MatCellDef, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatHeaderRow, - MatHeaderRowDef, - MatRow, - MatRowDef, - MatTable, -} from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import { round } from 'mathjs'; import moment from 'moment'; @@ -68,43 +50,18 @@ import { PurchaseDialogComponent } from './purchase-dialog.component'; templateUrl: './purchase.component.html', styleUrls: ['./purchase.component.css'], imports: [ - MatCard, - MatCardHeader, - MatCardTitleGroup, - MatCardTitle, - MatIcon, - MatSuffix, - MatCardContent, + MatCardModule, + MatIconModule, ReactiveFormsModule, - MatFormField, - MatLabel, - MatInput, - MatDatepickerInput, - MatDatepickerToggle, - MatDatepicker, - MatAutocompleteTrigger, - MatHint, - MatAutocomplete, - MatOption, - MatPrefix, - MatButton, - MatTable, - MatSort, - MatColumnDef, - MatHeaderCellDef, - MatHeaderCell, - MatCellDef, - MatCell, - MatIconButton, - MatHeaderRowDef, - MatHeaderRow, - MatRowDef, - MatRow, - MatChipGrid, - MatChipRow, - MatChipRemove, - MatChipInput, - MatCardActions, + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + MatAutocompleteModule, + MatOptionModule, + MatButtonModule, + MatTableModule, + MatSortModule, + MatChipsModule, AsyncPipe, DecimalPipe, PercentPipe, @@ -158,7 +115,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit { public inventoryObservable = new BehaviorSubject([]); dataSource: PurchaseDataSource = new PurchaseDataSource(this.inventoryObservable); form: FormGroup<{ - date: FormControl; + date: FormControl; account: FormControl; amount: FormControl; addRow: FormGroup<{ @@ -184,7 +141,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit { constructor() { this.form = new FormGroup({ - date: new FormControl(new Date(), { nonNullable: true }), + date: new FormControl(moment(new Date()), { nonNullable: true }), account: new FormControl(null), amount: new FormControl({ value: 0, disabled: true }, { nonNullable: true }), addRow: new FormGroup({ @@ -243,7 +200,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit { loadVoucher(voucher: Voucher) { this.voucher = voucher; this.form.setValue({ - date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(), + date: moment(this.voucher.date, 'DD-MMM-YYYY'), account: this.voucher.vendor?.name ?? null, amount: Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)), addRow: { diff --git a/overlord/src/app/purchase/purchase.resolver.ts b/overlord/src/app/purchase/purchase.resolver.ts index 0b784c9c..659e9ead 100644 --- a/overlord/src/app/purchase/purchase.resolver.ts +++ b/overlord/src/app/purchase/purchase.resolver.ts @@ -7,7 +7,7 @@ import { VoucherService } from '../core/voucher.service'; export const purchaseResolver: ResolveFn = (route) => { const id = route.paramMap.get('id'); if (id === null) { - return inject(VoucherService).getOfType('Purchase'); + return inject(VoucherService).getOfType('Purchase', null, null); } return inject(VoucherService).get(id, 'Purchase'); }; diff --git a/overlord/src/app/receipt/receipt.component.ts b/overlord/src/app/receipt/receipt.component.ts index f2048185..713ffe63 100644 --- a/overlord/src/app/receipt/receipt.component.ts +++ b/overlord/src/app/receipt/receipt.component.ts @@ -2,38 +2,20 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { AsyncPipe, CurrencyPipe } from '@angular/common'; import { AfterViewInit, Component, ElementRef, HostListener, inject, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocomplete, MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { MatButton, MatIconButton } from '@angular/material/button'; -import { - MatCard, - MatCardActions, - MatCardContent, - MatCardHeader, - MatCardTitle, - MatCardTitleGroup, -} from '@angular/material/card'; -import { MatChipGrid, MatChipInput, MatChipInputEvent, MatChipRemove, MatChipRow } from '@angular/material/chips'; -import { MatOption } from '@angular/material/core'; -import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker'; +import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatChipInputEvent, MatChipsModule } from '@angular/material/chips'; +import { MatOptionModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialog } from '@angular/material/dialog'; -import { MatFormField, MatHint, MatLabel, MatPrefix, MatSuffix } from '@angular/material/form-field'; -import { MatIcon } from '@angular/material/icon'; -import { MatInput } from '@angular/material/input'; -import { MatSelect } from '@angular/material/select'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; -import { - MatCell, - MatCellDef, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatHeaderRow, - MatHeaderRowDef, - MatRow, - MatRowDef, - MatTable, -} from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import { round } from 'mathjs'; import moment from 'moment'; @@ -65,44 +47,19 @@ import { ReceiptDialogComponent } from './receipt-dialog.component'; templateUrl: './receipt.component.html', styleUrls: ['./receipt.component.css'], imports: [ - MatCard, - MatCardHeader, - MatCardTitleGroup, - MatCardTitle, - MatIcon, - MatSuffix, - MatCardContent, + MatCardModule, + MatIconModule, ReactiveFormsModule, - MatFormField, - MatLabel, - MatInput, - MatDatepickerInput, - MatDatepickerToggle, - MatDatepicker, - MatSelect, - MatOption, - MatPrefix, - MatAutocompleteTrigger, - MatHint, - MatAutocomplete, - MatButton, - MatTable, - MatSort, - MatColumnDef, - MatHeaderCellDef, - MatHeaderCell, - MatCellDef, - MatCell, - MatIconButton, - MatHeaderRowDef, - MatHeaderRow, - MatRowDef, - MatRow, - MatChipGrid, - MatChipRow, - MatChipRemove, - MatChipInput, - MatCardActions, + MatFormFieldModule, + MatDatepickerModule, + MatInputModule, + MatSelectModule, + MatOptionModule, + MatAutocompleteModule, + MatButtonModule, + MatTableModule, + MatSortModule, + MatChipsModule, AsyncPipe, CurrencyPipe, AccountingPipe, @@ -138,7 +95,9 @@ export class ReceiptComponent implements OnInit, AfterViewInit { this.router.navigate(['payment'], { queryParams: { a: this.form.controls.receiptAccount.value, + d: this.form.controls.date.value.format('DD-MMM-YYYY'), }, + queryParamsHandling: 'merge', }); } @@ -150,7 +109,13 @@ export class ReceiptComponent implements OnInit, AfterViewInit { @HostListener('window:keydown.f7', ['$event']) redirectToJournal(event: KeyboardEvent) { event.preventDefault(); - this.router.navigate(['journal']); + this.router.navigate(['journal'], { + queryParams: { + a: this.form.controls.receiptAccount.value, + d: this.form.controls.date.value.format('DD-MMM-YYYY'), + }, + queryParamsHandling: 'merge', + }); } @HostListener('window:keydown.control.s', ['$event']) @@ -173,7 +138,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit { public journalObservable = new BehaviorSubject([]); dataSource: ReceiptDataSource = new ReceiptDataSource(this.journalObservable); form: FormGroup<{ - date: FormControl; + date: FormControl; receiptAccount: FormControl; receiptAmount: FormControl; addRow: FormGroup<{ @@ -197,7 +162,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit { constructor() { this.form = new FormGroup({ - date: new FormControl(new Date(), { nonNullable: true }), + date: new FormControl(moment(new Date()), { nonNullable: true }), receiptAccount: new FormControl('', { nonNullable: true }), receiptAmount: new FormControl({ value: 0, disabled: true }, { nonNullable: true }), addRow: new FormGroup({ @@ -220,12 +185,21 @@ export class ReceiptComponent implements OnInit, AfterViewInit { map((tag: string | Tag | null) => (tag === null ? '' : typeof tag !== 'string' ? tag.name.toLowerCase() : tag)), switchMap((tag: string) => this.tagSer.autocomplete(tag)), ); + // Listen to Date Change + this.form.controls.date.valueChanges.subscribe((x) => + this.router.navigate([], { + relativeTo: this.route, + queryParams: { d: x.format('DD-MMM-YYYY') }, + replaceUrl: true, + queryParamsHandling: 'merge', + }), + ); // Listen to Receipt Account Change this.form.controls.receiptAccount.valueChanges.subscribe((x) => this.router.navigate([], { relativeTo: this.route, queryParams: { a: x }, - replaceUrl: true, + queryParamsHandling: 'merge', }), ); } @@ -247,7 +221,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit { this.voucher = voucher; [this.receiptJournal] = this.voucher.journals.filter((x) => x.debit === 1); this.form.setValue({ - date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(), + date: moment(this.voucher.date, 'DD-MMM-YYYY'), receiptAccount: this.receiptJournal.account.id ?? '', receiptAmount: this.receiptJournal.amount, addRow: { diff --git a/overlord/src/app/receipt/receipt.resolver.ts b/overlord/src/app/receipt/receipt.resolver.ts index 18840480..897093d7 100644 --- a/overlord/src/app/receipt/receipt.resolver.ts +++ b/overlord/src/app/receipt/receipt.resolver.ts @@ -7,11 +7,9 @@ import { VoucherService } from '../core/voucher.service'; export const receiptResolver: ResolveFn = (route) => { const id = route.paramMap.get('id'); const account = route.queryParamMap.get('a') || null; + const date = route.queryParamMap.get('d') || null; if (id !== null) { return inject(VoucherService).get(id, 'Receipt'); } - if (account !== null) { - return inject(VoucherService).getOfType('Receipt', account); - } - return inject(VoucherService).getOfType('Receipt'); + return inject(VoucherService).getOfType('Receipt', account, date); };