Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
985993f273 | ||
|
|
3df19b7eb8 | ||
|
|
09b11e7e79 |
@@ -1 +1 @@
|
|||||||
__version__ = "15.2.4"
|
__version__ = "15.2.5"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "brewman"
|
name = "brewman"
|
||||||
version = "15.2.4"
|
version = "15.2.5"
|
||||||
description = "Accounting plus inventory management for a restaurant."
|
description = "Accounting plus inventory management 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" }]
|
||||||
|
|||||||
Generated
+1
-1
@@ -211,7 +211,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brewman"
|
name = "brewman"
|
||||||
version = "15.2.4"
|
version = "15.2.5"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "alembic" },
|
{ name = "alembic" },
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "overlord",
|
"name": "overlord",
|
||||||
"version": "15.2.4",
|
"version": "15.2.5",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry
|
ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry
|
||||||
version: '15.2.4',
|
version: '15.2.5',
|
||||||
title: 'HnG / TGB',
|
title: 'HnG / TGB',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,16 @@
|
|||||||
<div class="row-container">
|
<div class="row-container">
|
||||||
<mat-form-field class="flex-auto">
|
<mat-form-field class="flex-auto">
|
||||||
<mat-select [formField]="form.period">
|
<mat-select [formField]="form.period">
|
||||||
@for (p of periods(); track p.id) {
|
@for (p of periods(); track p) {
|
||||||
<mat-option [value]="p"> {{ p.validFrom }} to {{ p.validTill }} </mat-option>
|
<mat-option [value]="p.id"> {{ p.validFrom }} to {{ p.validTill }} </mat-option>
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-auto">
|
<mat-form-field class="flex-auto">
|
||||||
<mat-label>Product Type</mat-label>
|
<mat-label>Product Type</mat-label>
|
||||||
<mat-select [formField]="form.productGroup" (selectionChange)="filterProductGroup($event.value)">
|
<mat-select [formField]="form.productGroup">
|
||||||
<mat-option>-- All Products --</mat-option>
|
<mat-option [value]="null">-- All Products --</mat-option>
|
||||||
@for (mc of productGroups(); track mc.id) {
|
@for (mc of productGroups(); track mc) {
|
||||||
<mat-option [value]="mc.id">
|
<mat-option [value]="mc.id">
|
||||||
{{ mc.name }}
|
{{ mc.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, inject, input, computed, effect, signal } from '@angular/core';
|
import { Component, inject, input, computed, effect, signal, linkedSignal } from '@angular/core';
|
||||||
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
|
import { form as createForm, FormField, FormRoot } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatOptionModule } from '@angular/material/core';
|
import { MatOptionModule } from '@angular/material/core';
|
||||||
@@ -11,7 +11,6 @@ import { MatSortModule, Sort } from '@angular/material/sort';
|
|||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { Router, RouterModule } from '@angular/router';
|
import { Router, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
import { ProductGroup } from '../../core/product-group';
|
|
||||||
import { Period } from '../../period/period';
|
import { Period } from '../../period/period';
|
||||||
import { PeriodService } from '../../period/period.service';
|
import { PeriodService } from '../../period/period.service';
|
||||||
import { ProductGroupService } from '../../product-group/product-group.service';
|
import { ProductGroupService } from '../../product-group/product-group.service';
|
||||||
@@ -19,6 +18,10 @@ import { ErrorStateComponent } from '../../shared/error-state/error-state.compon
|
|||||||
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
|
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
|
||||||
import { RecipeService } from '../recipe.service';
|
import { RecipeService } from '../recipe.service';
|
||||||
|
|
||||||
|
export interface RecipeListFormData {
|
||||||
|
period: string | null;
|
||||||
|
productGroup: string | null;
|
||||||
|
}
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-recipe-list',
|
selector: 'app-recipe-list',
|
||||||
templateUrl: './recipe-list.component.html',
|
templateUrl: './recipe-list.component.html',
|
||||||
@@ -52,31 +55,34 @@ export class RecipeListComponent {
|
|||||||
sortActive = signal('');
|
sortActive = signal('');
|
||||||
sortDirection = signal('');
|
sortDirection = signal('');
|
||||||
|
|
||||||
p = input<string>();
|
p = input('', { transform: (v: string | null | undefined) => v ?? null });
|
||||||
model = signal({
|
|
||||||
period: null as Period | null,
|
|
||||||
productGroup: null as ProductGroup | string | null,
|
|
||||||
});
|
|
||||||
|
|
||||||
form = createForm(this.model);
|
|
||||||
|
|
||||||
periodsResource = this.periodSer.list();
|
periodsResource = this.periodSer.list();
|
||||||
periods = computed(() => this.periodsResource.value() ?? []);
|
periods = computed(() => this.periodsResource.value() ?? []);
|
||||||
|
|
||||||
|
model = linkedSignal<string | null, RecipeListFormData>({
|
||||||
|
source: () => this.p(),
|
||||||
|
computation: (period) => ({
|
||||||
|
period: period,
|
||||||
|
productGroup: null,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
form = createForm(this.model);
|
||||||
|
|
||||||
productGroupsResource = this.productGroupSer.list();
|
productGroupsResource = this.productGroupSer.list();
|
||||||
productGroups = computed(() => this.productGroupsResource.value() ?? []);
|
productGroups = computed(() => this.productGroupsResource.value() ?? []);
|
||||||
|
|
||||||
periodFilter = computed(() => this.p() || '');
|
resource = this.ser.list(this.p);
|
||||||
resource = this.ser.list(this.periodFilter);
|
productGroupFilter = computed(() => this.model().productGroup ?? null);
|
||||||
|
|
||||||
info = computed(() => this.resource.value() ?? []);
|
info = computed(() => this.resource.value() ?? []);
|
||||||
sortedList = computed(() => {
|
sortedList = computed(() => {
|
||||||
let data = this.info() ?? [];
|
let data = this.info() ?? [];
|
||||||
|
|
||||||
const pg = this.model().productGroup;
|
const pg = this.productGroupFilter();
|
||||||
if (pg) {
|
if (pg) {
|
||||||
const pgId = typeof pg === 'string' ? pg : pg.id;
|
data = data.filter((r) => r.productGroupId === pg);
|
||||||
data = data.filter((r) => r.productGroupId === pgId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const active = this.sortActive();
|
const active = this.sortActive();
|
||||||
@@ -118,18 +124,13 @@ export class RecipeListComponent {
|
|||||||
const x = this.model().period;
|
const x = this.model().period;
|
||||||
if (!x) return;
|
if (!x) return;
|
||||||
this.router.navigate([], {
|
this.router.navigate([], {
|
||||||
queryParams: { p: x.id },
|
queryParams: { p: x },
|
||||||
replaceUrl: true,
|
replaceUrl: true,
|
||||||
queryParamsHandling: 'merge',
|
queryParamsHandling: 'merge',
|
||||||
});
|
});
|
||||||
this.period = x;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
filterProductGroup(val: string) {
|
|
||||||
this.model.update((m) => ({ ...m, productGroup: val }));
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePageEvent(e: PageEvent) {
|
handlePageEvent(e: PageEvent) {
|
||||||
this.pageSize.set(e.pageSize);
|
this.pageSize.set(e.pageSize);
|
||||||
this.pageIndex.set(e.pageIndex);
|
this.pageIndex.set(e.pageIndex);
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
<mat-form-field class="flex-auto basis-30">
|
<mat-form-field class="flex-auto basis-30">
|
||||||
<mat-label>Product Group</mat-label>
|
<mat-label>Product Group</mat-label>
|
||||||
<mat-select [formField]="form.productGroup">
|
<mat-select [formField]="form.productGroup">
|
||||||
<mat-option>-- All Products --</mat-option>
|
<mat-option [value]="null">-- All Products --</mat-option>
|
||||||
@for (pg of productGroups(); track pg) {
|
@for (pg of productGroups(); track pg) {
|
||||||
<mat-option [value]="pg.id">
|
<mat-option [value]="pg.id">
|
||||||
{{ pg.name }}
|
{{ pg.name }}
|
||||||
|
|||||||
+4
-10
@@ -9,7 +9,6 @@ import { MatSelectModule } from '@angular/material/select';
|
|||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { Product, StockKeepingUnit } from '../../core/product';
|
|
||||||
import { ProductGroupService } from '../../product-group/product-group.service';
|
import { ProductGroupService } from '../../product-group/product-group.service';
|
||||||
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
|
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
|
||||||
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
|
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
|
||||||
@@ -18,7 +17,7 @@ import { TemporalProductService } from '../temporal-product.service';
|
|||||||
|
|
||||||
export interface TemporalProductListFormData {
|
export interface TemporalProductListFormData {
|
||||||
filter: string;
|
filter: string;
|
||||||
productGroup: Product | StockKeepingUnit | string | null;
|
productGroup: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -66,16 +65,11 @@ export class TemporalProductListComponent {
|
|||||||
form = createForm(this.formModel);
|
form = createForm(this.formModel);
|
||||||
filterSignal = computed(() => this.formModel().filter);
|
filterSignal = computed(() => this.formModel().filter);
|
||||||
debouncedFilter = debounced(this.filterSignal, 150);
|
debouncedFilter = debounced(this.filterSignal, 150);
|
||||||
|
productGroupFilter = computed(() => this.formModel().productGroup ?? null);
|
||||||
filteredList = computed(() => {
|
filteredList = computed(() => {
|
||||||
const data = this.list();
|
const data = this.list();
|
||||||
const search = this.debouncedFilter.value() ?? '';
|
const search = this.debouncedFilter.value() ?? '';
|
||||||
const productGroup = this.formModel().productGroup;
|
const productGroup = this.productGroupFilter();
|
||||||
const groupId =
|
|
||||||
typeof productGroup === 'string'
|
|
||||||
? productGroup
|
|
||||||
: productGroup && 'id' in productGroup
|
|
||||||
? (productGroup.id ?? '')
|
|
||||||
: '';
|
|
||||||
|
|
||||||
const tokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
const tokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
||||||
|
|
||||||
@@ -97,7 +91,7 @@ export class TemporalProductListComponent {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const matchesProductGroup = !groupId || products.some((k) => (k.productGroup?.id ?? '') === groupId);
|
const matchesProductGroup = !productGroup || products.some((k) => k.productGroup?.id === productGroup);
|
||||||
return matchesSearch && matchesProductGroup;
|
return matchesSearch && matchesProductGroup;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user