Compare commits

..
6 Commits
14 changed files with 152 additions and 106 deletions
+1 -1
View File
@@ -1 +1 @@
__version__ = "15.1.0" __version__ = "15.1.3"
+2 -2
View File
@@ -121,7 +121,7 @@ def show_list(
guest_book: list[schemas.GuestBookListItem] = [] guest_book: list[schemas.GuestBookListItem] = []
count = 0 count = 0
for i, item in enumerate(db.execute(list_).scalars().all()): for i, item in enumerate(db.execute(list_).scalars().all()):
status = GuestBookType(item.type_.name) if item.status is None else GuestBookType(item.status.status.name) item_status = GuestBookType(item.type_.name) if item.status is None else GuestBookType(item.status.status.name)
if item.type_ != GuestBookType.booking: if item.type_ != GuestBookType.booking:
count += item.pax count += item.pax
gbli = schemas.GuestBookListItem( gbli = schemas.GuestBookListItem(
@@ -134,7 +134,7 @@ def show_list(
booking_date=item.booking_date, booking_date=item.booking_date,
arrival_date=item.arrival_date, arrival_date=item.arrival_date,
last_edit_date=item.last_edit_date, last_edit_date=item.last_edit_date,
status=status, status=item_status,
table_id=None if item.status is None else item.status.food_table.id, table_id=None if item.status is None else item.status.food_table.id,
voucher_id=None if item.status is None else item.status.voucher_id, voucher_id=None if item.status is None else item.status.voucher_id,
table_name=None if item.status is None else item.status.food_table.name, table_name=None if item.status is None else item.status.food_table.name,
+1 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "barker" name = "barker"
version = "15.1.0" version = "15.1.3"
description = "Point of Sale for a restaurant" description = "Point of Sale for a restaurant"
requires-python = ">=3.14" requires-python = ">=3.14"
authors = [{ name = "tanshu", email = "git@tanshu.com" }] authors = [{ name = "tanshu", email = "git@tanshu.com" }]
+1 -1
View File
@@ -231,7 +231,7 @@ wheels = [
[[package]] [[package]]
name = "barker" name = "barker"
version = "15.1.0" version = "15.1.3"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "aiohttp" }, { name = "aiohttp" },
+12 -5
View File
@@ -32,7 +32,9 @@
"input": "public" "input": "public"
} }
], ],
"styles": ["src/styles.sass"], "styles": [
"src/styles.sass"
],
"allowedCommonJsDependencies": [ "allowedCommonJsDependencies": [
"typed-function", "typed-function",
"javascript-natural-sort", "javascript-natural-sort",
@@ -46,8 +48,8 @@
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "500kb", "maximumWarning": "1000kb",
"maximumError": "1mb" "maximumError": "2mb"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
@@ -86,14 +88,19 @@
"lint": { "lint": {
"builder": "@angular-eslint/builder:lint", "builder": "@angular-eslint/builder:lint",
"options": { "options": {
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"] "lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
} }
} }
} }
} }
}, },
"cli": { "cli": {
"schematicCollections": ["@angular-eslint/schematics"], "schematicCollections": [
"@angular-eslint/schematics"
],
"analytics": false "analytics": false
}, },
"schematics": { "schematics": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "bookie", "name": "bookie",
"version": "15.1.0", "version": "15.1.3",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
+1 -1
View File
@@ -1,7 +1,7 @@
export const environment = { export const environment = {
production: true, production: true,
ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry
version: '15.1.0', version: '15.1.3',
}; };
export const dateFormat = { export const dateFormat = {
+14 -7
View File
@@ -10,6 +10,11 @@ import { AuthService } from '../auth/auth.service';
import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component';
export const authInterceptor: HttpInterceptorFn = (req, next) => { export const authInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService);
const snackBar = inject(MatSnackBar);
const dialog = inject(MatDialog);
const router = inject(Router);
return next(req).pipe( return next(req).pipe(
catchError((err) => { catchError((err) => {
// We don't want to refresh token for some requests like login or refresh token itself // We don't want to refresh token for some requests like login or refresh token itself
@@ -18,21 +23,22 @@ export const authInterceptor: HttpInterceptorFn = (req, next) => {
// We do another check to see if refresh token failed // We do another check to see if refresh token failed
// In this case we want to logout user and to redirect it to login page // In this case we want to logout user and to redirect it to login page
if (req.url.includes('/refresh')) { if (req.url.includes('/refresh')) {
inject(AuthService).logout(); authService.logout();
} }
return throwError(() => err); return throwError(() => err);
} }
// If error status is different than 401 we want to skip refresh token // If error status is different than 401 we want to skip refresh token
// So we check that and throw the error if it's the case // So we check that and throw the error if it's the case
if (err.status !== 401) { if (err.status !== 401) {
const error = err.error.message || err.error.detail || err.statusText; const error = err.error?.message || err.error?.detail || err.statusText || err;
return throwError(() => error); return throwError(() => error);
} }
// auto logout if 401 response returned from api // auto logout if 401 response returned from api
inject(AuthService).logout(); authService.logout();
inject(MatSnackBar).open('User has been logged out', 'Danger'); if (dialog.openDialogs.length === 0) {
const dialogRef = inject(MatDialog).open(ConfirmDialogComponent, { snackBar.open('User has been logged out', 'Danger');
width: '250px', const dialogRef = dialog.open(ConfirmDialogComponent, {
width: '350px',
data: { data: {
title: 'Logged out!', title: 'Logged out!',
content: content:
@@ -43,9 +49,10 @@ export const authInterceptor: HttpInterceptorFn = (req, next) => {
}); });
dialogRef.afterClosed().subscribe((result: boolean) => { dialogRef.afterClosed().subscribe((result: boolean) => {
if (result) { if (result) {
inject(Router).navigate(['login']); router.navigate(['/login']);
} }
}); });
}
return throwError(() => err); return throwError(() => err);
}), }),
); );
+37 -6
View File
@@ -37,25 +37,36 @@ export class BillService {
public grossAmount = computed(() => public grossAmount = computed(() =>
this.math.halfRoundEven( this.math.halfRoundEven(
this.data().reduce((t, k) => k.inventories.reduce((a, c) => a + c.price * c.quantity, 0) + t, 0), this.data().reduce(
(t, k) => k.inventories.filter((c) => !c.parentId).reduce((a, c) => a + c.price * c.quantity, 0) + t,
0,
),
2,
), ),
); );
public hhAmount = computed(() => public hhAmount = computed(() =>
this.math.halfRoundEven( this.math.halfRoundEven(
this.data().reduce( this.data().reduce(
(t, k) => k.inventories.reduce((a, c) => a + (c.isHappyHour ? c.price : 0) * c.quantity, 0) + t, (t, k) =>
k.inventories.filter((c) => !c.parentId).reduce((a, c) => a + (c.isHappyHour ? c.price : 0) * c.quantity, 0) +
t,
0, 0,
), ),
2,
), ),
); );
public discountAmount = computed(() => public discountAmount = computed(() =>
this.math.halfRoundEven( this.math.halfRoundEven(
this.data().reduce( this.data().reduce(
(t, k) => k.inventories.reduce((a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount, 0) + t, (t, k) =>
k.inventories
.filter((c) => !c.parentId)
.reduce((a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount, 0) + t,
0, 0,
), ),
2,
), ),
); );
@@ -63,16 +74,36 @@ export class BillService {
this.math.halfRoundEven( this.math.halfRoundEven(
this.data().reduce( this.data().reduce(
(t, k) => (t, k) =>
k.inventories.reduce( k.inventories
(a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate, .filter((c) => !c.parentId)
.reduce((a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate, 0) + t,
0,
),
2,
),
);
public amount = computed(() =>
this.math.halfRoundEven(
this.data().reduce(
(t, k) =>
k.inventories
.filter((c) => !c.parentId)
.reduce(
(a, c) =>
a +
this.math.halfRoundEven(
(c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate),
2,
),
0, 0,
) + t, ) + t,
0, 0,
), ),
0,
), ),
); );
public amount = computed(() => this.grossAmount() - this.discountAmount() + this.taxAmount());
public selection = new SelectionModel<string>(true, []); public selection = new SelectionModel<string>(true, []);
private updateTable = signal<boolean>(true); private updateTable = signal<boolean>(true);
private allowDeactivate = signal<boolean>(false); private allowDeactivate = signal<boolean>(false);
@@ -1,8 +1,3 @@
@if (customersResource.isLoading()) {
<app-skeleton-loader type="card" [count]="1" />
} @else if (customersResource.error()) {
<app-error-state (retryAction)="customersResource.reload()" />
} @else {
<h2 mat-dialog-title>Customer</h2> <h2 mat-dialog-title>Customer</h2>
<mat-dialog-content> <mat-dialog-content>
<form class="flex-col"> <form class="flex-col">
@@ -60,4 +55,3 @@
<button mat-button [mat-dialog-close]="false">Cancel</button> <button mat-button [mat-dialog-close]="false">Cancel</button>
<button type="button" mat-raised-button color="primary" (click)="save()">Select</button> <button type="button" mat-raised-button color="primary" (click)="save()">Select</button>
</mat-dialog-actions> </mat-dialog-actions>
}
@@ -13,8 +13,6 @@ import { MatInputModule } from '@angular/material/input';
import { Customer } from '../../core/customer'; import { Customer } from '../../core/customer';
import { CustomerDiscount } from '../../core/customer-discount'; import { CustomerDiscount } from '../../core/customer-discount';
import { CustomerService } from '../../customers/customer.service'; import { CustomerService } from '../../customers/customer.service';
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
export interface ChooseCustomerFormData { export interface ChooseCustomerFormData {
id: string; id: string;
@@ -40,8 +38,6 @@ export interface ChooseCustomerFormData {
MatOptionModule, MatOptionModule,
PercentPipe, PercentPipe,
FormField, FormField,
ErrorStateComponent,
SkeletonLoaderComponent,
], ],
}) })
export class ChooseCustomerComponent { export class ChooseCustomerComponent {
@@ -66,7 +62,8 @@ export class ChooseCustomerComponent {
form = form(this.formModel); form = form(this.formModel);
phoneSignal = computed(() => { phoneSignal = computed(() => {
return this.formModel().phone; const p = this.formModel().phone;
return typeof p === 'string' ? p.trim() : null;
}); });
debouncedPhone = debounced(this.phoneSignal, 150); debouncedPhone = debounced(this.phoneSignal, 150);
+1
View File
@@ -16,4 +16,5 @@
when: var_file is defined when: var_file is defined
roles: roles:
- printer
- frank - frank
@@ -0,0 +1,2 @@
- name: Reload udev
ansible.builtin.shell: udevadm control --reload-rules && udevadm trigger --action=change
@@ -0,0 +1,7 @@
- name: Add udev rule for usb printer systemd tag
copy:
dest: /etc/udev/rules.d/99-usb-printers.rules
content: |
SUBSYSTEM=="usbmisc", KERNEL=="lp*", TAG+="systemd"
mode: "0644"
notify: Reload udev