feat: add rematch functionality for recipe ingredients and enhance inventory management
Test Suite / test (24.15.0) (push) Has been cancelled

- Added a new API path for rematching recipe ingredients in `api_paths.dart`.
- Implemented a manual product creation dialog in `inventory_screen.dart` to allow users to create new products directly.
- Integrated the rematch functionality in `recipe_repository.dart` to handle rematching of recipe ingredients.
- Updated the recipe detail screen to include a button for triggering the rematch process.
- Introduced a new `RecipeMatchingService` in the backend to handle ingredient matching logic.
- Added database migration to include `aiEngineEnabled` column in the User table.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Nils-Johan Gynther
2026-05-06 09:20:31 +02:00
parent 9fe85a719c
commit 04b1fc3024
53 changed files with 1420 additions and 652 deletions
+66 -66
View File
@@ -13,6 +13,8 @@ export declare class ProductsService {
tag?: string;
}): Promise<({
nutrition: {
id: number;
productId: number;
calories: number | null;
protein: number | null;
fat: number | null;
@@ -20,8 +22,6 @@ export declare class ProductsService {
salt: number | null;
sugar: number | null;
fiber: number | null;
id: number;
productId: number;
} | null;
tags: ({
tag: {
@@ -50,13 +50,13 @@ export declare class ProductsService {
parentId: number | null;
}) | null;
} & {
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -66,18 +66,18 @@ export declare class ProductsService {
})[]>;
findByOwner(userId: number): Promise<{
name: string;
id: number;
categoryId: number | null;
canonicalName: string | null;
id: number;
}[]>;
createPrivate(data: CreateProductDto, userId: number): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -89,13 +89,13 @@ export declare class ProductsService {
normalizedName: string;
count: number;
products: {
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -105,13 +105,13 @@ export declare class ProductsService {
}[];
}[]>;
findOne(id: number): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -120,13 +120,13 @@ export declare class ProductsService {
isPrivate: boolean;
}>;
create(data: CreateProductDto, ownerId?: number): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -136,6 +136,8 @@ export declare class ProductsService {
}>;
update(id: number, data: UpdateProductDto): Promise<{
nutrition: {
id: number;
productId: number;
calories: number | null;
protein: number | null;
fat: number | null;
@@ -143,8 +145,6 @@ export declare class ProductsService {
salt: number | null;
sugar: number | null;
fiber: number | null;
id: number;
productId: number;
} | null;
tags: ({
tag: {
@@ -156,13 +156,13 @@ export declare class ProductsService {
tagId: number;
})[];
} & {
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -171,13 +171,13 @@ export declare class ProductsService {
isPrivate: boolean;
}>;
updateCanonicalName(id: number, canonicalName: string): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -186,13 +186,13 @@ export declare class ProductsService {
isPrivate: boolean;
}>;
findDeleted(): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -201,13 +201,13 @@ export declare class ProductsService {
isPrivate: boolean;
}[]>;
remove(id: number): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -216,13 +216,13 @@ export declare class ProductsService {
isPrivate: boolean;
}>;
permanentDelete(id: number): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -231,13 +231,13 @@ export declare class ProductsService {
isPrivate: boolean;
}>;
restore(id: number): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -252,13 +252,13 @@ export declare class ProductsService {
targetProductId: number;
movedInventoryCount: number;
softDeletedSource: {
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -270,13 +270,13 @@ export declare class ProductsService {
previewMerge(sourceProductId: number, targetProductId: number): Promise<{
source: {
inventoryCount: number;
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -286,13 +286,13 @@ export declare class ProductsService {
};
target: {
inventoryCount: number;
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -310,13 +310,13 @@ export declare class ProductsService {
message: string;
updatedCount: number;
products: {
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -327,6 +327,8 @@ export declare class ProductsService {
}>;
setTags(productId: number, tagNames: string[]): Promise<({
nutrition: {
id: number;
productId: number;
calories: number | null;
protein: number | null;
fat: number | null;
@@ -334,8 +336,6 @@ export declare class ProductsService {
salt: number | null;
sugar: number | null;
fiber: number | null;
id: number;
productId: number;
} | null;
tags: ({
tag: {
@@ -347,13 +347,13 @@ export declare class ProductsService {
tagId: number;
})[];
} & {
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -362,6 +362,8 @@ export declare class ProductsService {
isPrivate: boolean;
}) | null>;
upsertNutrition(productId: number, data: UpsertNutritionDto): Promise<{
id: number;
productId: number;
calories: number | null;
protein: number | null;
fat: number | null;
@@ -369,8 +371,6 @@ export declare class ProductsService {
salt: number | null;
sugar: number | null;
fiber: number | null;
id: number;
productId: number;
}>;
findAllTags(): Promise<{
name: string;
@@ -411,13 +411,13 @@ export declare class ProductsService {
parentId: number | null;
}) | null;
} & {
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -426,13 +426,13 @@ export declare class ProductsService {
isPrivate: boolean;
})[]>;
createPending(data: CreateProductDto, userId: number): Promise<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;
@@ -441,13 +441,13 @@ export declare class ProductsService {
isPrivate: boolean;
}>;
setStatus(id: number, status: string): import(".prisma/client").Prisma.Prisma__ProductClient<{
name: string;
category: string | null;
status: string;
name: string;
categoryId: number | null;
canonicalName: string | null;
id: number;
categoryId: number | null;
normalizedName: string;
canonicalName: string | null;
isActive: boolean;
deletedAt: Date | null;
createdAt: Date;