feat: add rematch functionality for recipe ingredients and enhance inventory management
Test Suite / test (24.15.0) (push) Has been cancelled
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:
+176
-137
@@ -23,11 +23,7 @@ export declare class RecipesController {
|
||||
quantity: number;
|
||||
unit: string;
|
||||
note: string | null;
|
||||
suggestions: {
|
||||
productId: number;
|
||||
productName: string;
|
||||
score: number;
|
||||
}[];
|
||||
suggestions: import("./recipe-matching.service").IngredientSuggestion[];
|
||||
}[];
|
||||
}>;
|
||||
getAiSuggestions(user: {
|
||||
@@ -56,30 +52,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -90,16 +86,16 @@ export declare class RecipesController {
|
||||
userId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
isPublic: boolean;
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number | null;
|
||||
description: string | null;
|
||||
instructions: string | null;
|
||||
imageUrl: string | null;
|
||||
servings: number | null;
|
||||
isPublic: boolean;
|
||||
ownerId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
})[]>;
|
||||
getInventoryPreview(id: number, user: {
|
||||
userId: number;
|
||||
@@ -157,7 +153,7 @@ export declare class RecipesController {
|
||||
quantity: number;
|
||||
unit: any;
|
||||
note: any;
|
||||
status: "missing" | "exact_match" | "covered_by_pantry" | "substitutable";
|
||||
status: "missing" | "substitutable" | "exact_match" | "covered_by_pantry";
|
||||
matchedProductId: any;
|
||||
matchedProductName: any;
|
||||
source: string;
|
||||
@@ -169,7 +165,50 @@ export declare class RecipesController {
|
||||
quantity: number;
|
||||
unit: any;
|
||||
note: any;
|
||||
status: "missing" | "exact_match" | "covered_by_pantry" | "substitutable";
|
||||
status: "missing" | "substitutable" | "exact_match" | "covered_by_pantry";
|
||||
matchedProductId: any;
|
||||
matchedProductName: any;
|
||||
source: null;
|
||||
availableQuantity: number;
|
||||
missingQuantity: number;
|
||||
})[];
|
||||
summary: {
|
||||
exactCount: number;
|
||||
pantryCount: number;
|
||||
substituteCount: number;
|
||||
missingCount: number;
|
||||
};
|
||||
shoppingListCandidates: {
|
||||
ingredientId: any;
|
||||
rawName: any;
|
||||
quantity: number;
|
||||
unit: any;
|
||||
missingQuantity: number;
|
||||
}[];
|
||||
}>;
|
||||
rematchRecipeIngredients(id: number, user: {
|
||||
userId: number;
|
||||
}): Promise<{
|
||||
recipeId: number;
|
||||
ingredients: ({
|
||||
ingredientId: any;
|
||||
rawName: any;
|
||||
quantity: number;
|
||||
unit: any;
|
||||
note: any;
|
||||
status: "missing" | "substitutable" | "exact_match" | "covered_by_pantry";
|
||||
matchedProductId: any;
|
||||
matchedProductName: any;
|
||||
source: string;
|
||||
availableQuantity: number;
|
||||
missingQuantity: number;
|
||||
} | {
|
||||
ingredientId: any;
|
||||
rawName: any;
|
||||
quantity: number;
|
||||
unit: any;
|
||||
note: any;
|
||||
status: "missing" | "substitutable" | "exact_match" | "covered_by_pantry";
|
||||
matchedProductId: any;
|
||||
matchedProductName: any;
|
||||
source: null;
|
||||
@@ -211,30 +250,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -245,16 +284,16 @@ export declare class RecipesController {
|
||||
userId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
isPublic: boolean;
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number | null;
|
||||
description: string | null;
|
||||
instructions: string | null;
|
||||
imageUrl: string | null;
|
||||
servings: number | null;
|
||||
isPublic: boolean;
|
||||
ownerId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}>;
|
||||
create(createRecipeDto: CreateRecipeDto, user: {
|
||||
userId: number;
|
||||
@@ -273,30 +312,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -304,16 +343,16 @@ export declare class RecipesController {
|
||||
analysisStatus: string | null;
|
||||
})[];
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
isPublic: boolean;
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number | null;
|
||||
description: string | null;
|
||||
instructions: string | null;
|
||||
imageUrl: string | null;
|
||||
servings: number | null;
|
||||
isPublic: boolean;
|
||||
ownerId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}>;
|
||||
update(id: number, createRecipeDto: CreateRecipeDto, user: {
|
||||
userId: number;
|
||||
@@ -332,30 +371,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -363,16 +402,16 @@ export declare class RecipesController {
|
||||
analysisStatus: string | null;
|
||||
})[];
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
isPublic: boolean;
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number | null;
|
||||
description: string | null;
|
||||
instructions: string | null;
|
||||
imageUrl: string | null;
|
||||
servings: number | null;
|
||||
isPublic: boolean;
|
||||
ownerId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}>;
|
||||
remove(id: number, user: {
|
||||
userId: number;
|
||||
@@ -398,30 +437,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -432,16 +471,16 @@ export declare class RecipesController {
|
||||
userId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
isPublic: boolean;
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number | null;
|
||||
description: string | null;
|
||||
instructions: string | null;
|
||||
imageUrl: string | null;
|
||||
servings: number | null;
|
||||
isPublic: boolean;
|
||||
ownerId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}>;
|
||||
addIngredient(id: number, ingredient: CreateIngredientDto, user: {
|
||||
userId: number;
|
||||
@@ -459,30 +498,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -510,30 +549,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -544,16 +583,16 @@ export declare class RecipesController {
|
||||
userId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
isPublic: boolean;
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number | null;
|
||||
description: string | null;
|
||||
instructions: string | null;
|
||||
imageUrl: string | null;
|
||||
servings: number | null;
|
||||
isPublic: boolean;
|
||||
ownerId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}>;
|
||||
shareRecipe(id: number, dto: ShareRecipeDto, user: {
|
||||
userId: number;
|
||||
@@ -576,30 +615,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -610,16 +649,16 @@ export declare class RecipesController {
|
||||
userId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
isPublic: boolean;
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number | null;
|
||||
description: string | null;
|
||||
instructions: string | null;
|
||||
imageUrl: string | null;
|
||||
servings: number | null;
|
||||
isPublic: boolean;
|
||||
ownerId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}>;
|
||||
unshareRecipe(id: number, username: string, user: {
|
||||
userId: number;
|
||||
@@ -642,30 +681,30 @@ export declare class RecipesController {
|
||||
fiber: number | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
normalizedName: string;
|
||||
category: string | null;
|
||||
status: string;
|
||||
id: number;
|
||||
categoryId: number | null;
|
||||
normalizedName: string;
|
||||
canonicalName: string | null;
|
||||
isActive: boolean;
|
||||
deletedAt: Date | null;
|
||||
categoryId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number;
|
||||
isPrivate: boolean;
|
||||
}) | null;
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
recipeId: number;
|
||||
productId: number | null;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
quantity: import("@prisma/client/runtime/library").Decimal | null;
|
||||
unit: string | null;
|
||||
recipeId: number;
|
||||
rawName: string;
|
||||
rawLine: string | null;
|
||||
note: string | null;
|
||||
alternativeProductIds: import("@prisma/client/runtime/library").JsonValue | null;
|
||||
matchConfidence: number | null;
|
||||
@@ -676,16 +715,16 @@ export declare class RecipesController {
|
||||
userId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
name: string;
|
||||
isPublic: boolean;
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
ownerId: number | null;
|
||||
description: string | null;
|
||||
instructions: string | null;
|
||||
imageUrl: string | null;
|
||||
servings: number | null;
|
||||
isPublic: boolean;
|
||||
ownerId: number | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}>;
|
||||
}
|
||||
export {};
|
||||
|
||||
Reference in New Issue
Block a user