Finish first version of nested recipes feature (references #77)

This commit is contained in:
Bernd Bestel 2018-10-25 20:36:29 +02:00
parent 12a2cb0bdf
commit fc3a4c6899
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
10 changed files with 172 additions and 139 deletions

View File

@ -35,6 +35,9 @@ class RecipesController extends BaseController
} }
} }
$selectedRecipeSubRecipes = $this->Database->recipes()->where('id IN (SELECT includes_recipe_id FROM recipes_nestings_resolved WHERE recipe_id = :1 AND includes_recipe_id != :1)', $selectedRecipe->id)->orderBy('name')->fetchAll();
$selectedRecipeSubRecipesPositions = $this->Database->recipes_pos()->where('recipe_id IN (SELECT includes_recipe_id FROM recipes_nestings_resolved WHERE recipe_id = :1 AND includes_recipe_id != :1)', $selectedRecipe->id)->fetchAll();
return $this->AppContainer->view->render($response, 'recipes', [ return $this->AppContainer->view->render($response, 'recipes', [
'recipes' => $recipes, 'recipes' => $recipes,
'recipesFulfillment' => $this->RecipesService->GetRecipesFulfillment(), 'recipesFulfillment' => $this->RecipesService->GetRecipesFulfillment(),
@ -42,7 +45,9 @@ class RecipesController extends BaseController
'selectedRecipe' => $selectedRecipe, 'selectedRecipe' => $selectedRecipe,
'selectedRecipePositions' => $selectedRecipePositions, 'selectedRecipePositions' => $selectedRecipePositions,
'products' => $this->Database->products(), 'products' => $this->Database->products(),
'quantityunits' => $this->Database->quantity_units() 'quantityunits' => $this->Database->quantity_units(),
'selectedRecipeSubRecipes' => $selectedRecipeSubRecipes,
'selectedRecipeSubRecipesPositions' => $selectedRecipeSubRecipesPositions
]); ]);
} }
@ -67,7 +72,7 @@ class RecipesController extends BaseController
'quantityunits' => $this->Database->quantity_units(), 'quantityunits' => $this->Database->quantity_units(),
'recipesFulfillment' => $this->RecipesService->GetRecipesFulfillment(), 'recipesFulfillment' => $this->RecipesService->GetRecipesFulfillment(),
'recipesSumFulfillment' => $this->RecipesService->GetRecipesSumFulfillment(), 'recipesSumFulfillment' => $this->RecipesService->GetRecipesSumFulfillment(),
'recipes' => $this->Database->recipes(), 'recipes' => $this->Database->recipes()->orderBy('name'),
'recipeNestings' => $this->Database->recipes_nestings()->where('recipe_id', $recipeId) 'recipeNestings' => $this->Database->recipes_nestings()->where('recipe_id', $recipeId)
]); ]);
} }
@ -94,25 +99,4 @@ class RecipesController extends BaseController
]); ]);
} }
} }
public function RecipeIncludeEditForm(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
{
if ($args['recipeIncludeId'] == 'new')
{
return $this->AppContainer->view->render($response, 'recipeincludeform', [
'mode' => 'create',
'recipe' => $this->Database->recipes($args['recipeId']),
'recipes' => $this->Database->recipes()->orderBy('name')
]);
}
else
{
return $this->AppContainer->view->render($response, 'recipeincludeform', [
'mode' => 'edit',
'recipe' => $this->Database->recipes($args['recipeId']),
'recipeInclude' => $this->Database->recipes_nestings($args['recipeIncludeId']),
'recipes' => $this->Database->recipes()->orderBy('name')
]);
}
}
} }

View File

@ -280,6 +280,10 @@ return array(
'No picture available' => 'Kein Bild vorhanden', 'No picture available' => 'Kein Bild vorhanden',
'Filter by product group' => 'Nach Produktgruppe filtern', 'Filter by product group' => 'Nach Produktgruppe filtern',
'Presets for new products' => 'Vorgaben für neue Produkte', 'Presets for new products' => 'Vorgaben für neue Produkte',
'Included recipes' => 'Enthaltene Rezepte',
'A recipe is required' => 'Ein Rezept ist erforderlich',
'Add included recipe' => 'Enthaltenes Rezept hinzufügen',
'Edit included recipe' => 'Enthaltenes Rezept bearbeiten',
//Constants //Constants
'manually' => 'Manuell', 'manually' => 'Manuell',
@ -364,5 +368,13 @@ return array(
'Vegetables/Fruits' => 'Obst/Gemüse', 'Vegetables/Fruits' => 'Obst/Gemüse',
'Refrigerated products' => 'Kühlregal', 'Refrigerated products' => 'Kühlregal',
'Coffee machine' => 'Kaffeemaschine', 'Coffee machine' => 'Kaffeemaschine',
'Dishwasher' => 'Spülmaschine' 'Dishwasher' => 'Spülmaschine',
'Liter' => 'Liter',
'Liters' => 'Liter',
'Bottle' => 'Flasche',
'Bottles' => 'Flaschen',
'Milk' => 'Milch',
'Chocolate sauce' => 'Schokoladensoße',
'Milliliters' => 'Milliliter',
'Milliliter' => 'Milliliter'
); );

View File

@ -23,3 +23,18 @@ AS (
) )
SELECT * SELECT *
FROM r1; FROM r1;
DROP VIEW recipes_fulfillment_sum;
CREATE VIEW recipes_fulfillment_sum
AS
SELECT
r.id AS recipe_id,
IFNULL(MIN(rf.need_fulfilled), 1) AS need_fulfilled,
IFNULL(MIN(rf.need_fulfilled_with_shopping_list), 1) AS need_fulfilled_with_shopping_list,
(SELECT COUNT(*) FROM recipes_fulfillment WHERE recipe_id IN (SELECT includes_recipe_id FROM recipes_nestings_resolved rnr2 WHERE rnr2.recipe_id = r.id) AND need_fulfilled = 0 AND recipe_pos_id IS NOT NULL) AS missing_products_count
FROM recipes r
LEFT JOIN recipes_nestings_resolved rnr
ON r.id = rnr.recipe_id
LEFT JOIN recipes_fulfillment rf
ON rnr.includes_recipe_id = rf.recipe_id
GROUP BY r.id;

View File

@ -118,7 +118,7 @@ $(document).on('click', '.recipe-pos-delete-button', function(e)
}); });
}); });
$(document).on('click', '.recipe-inlcude-delete-button', function(e) $(document).on('click', '.recipe-include-delete-button', function(e)
{ {
var objectName = $(e.currentTarget).attr('data-recipe-include-name'); var objectName = $(e.currentTarget).attr('data-recipe-include-name');
var objectId = $(e.currentTarget).attr('data-recipe-include-id'); var objectId = $(e.currentTarget).attr('data-recipe-include-id');
@ -206,11 +206,17 @@ $(document).on('click', '.recipe-pos-edit-button', function (e)
$(document).on('click', '.recipe-include-edit-button', function (e) $(document).on('click', '.recipe-include-edit-button', function (e)
{ {
var id = $(e.currentTarget).attr('data-recipe-include-id'); var id = $(e.currentTarget).attr('data-recipe-include-id');
var recipeId = $(e.currentTarget).attr('data-recipe-included-recipe-id');
console.log(recipeId);
Grocy.Api.Post('edit-object/recipes/' + Grocy.EditObjectId, $('#recipe-form').serializeJSON(), Grocy.Api.Post('edit-object/recipes/' + Grocy.EditObjectId, $('#recipe-form').serializeJSON(),
function(result) function(result)
{ {
window.location.href = U('/recipe/' + Grocy.EditObjectId + '/included_recipe/' + id); $("#recipe-include-editform-title").text(L("Edit included recipe"));
$("#recipe-include-form").data("edit-mode", "edit");
$("#recipe-include-form").data("recipe-nesting-id", id);
$("#includes_recipe_id").val(recipeId);
$("#recipe-include-editform-modal").modal("show");
Grocy.FrontendHelpers.ValidateForm("recipe-include-form");
}, },
function(xhr) function(xhr)
{ {
@ -238,7 +244,11 @@ $("#recipe-include-add-button").on("click", function(e)
Grocy.Api.Post('edit-object/recipes/' + Grocy.EditObjectId, $('#recipe-form').serializeJSON(), Grocy.Api.Post('edit-object/recipes/' + Grocy.EditObjectId, $('#recipe-form').serializeJSON(),
function(result) function(result)
{ {
window.location.href = U('/recipe/' + Grocy.EditObjectId + '/included_recipe/new'); $("#recipe-include-editform-title").text(L("Add included recipe"));
$("#recipe-include-form").data("edit-mode", "create");
$("#includes_recipe_id").val("");
$("#recipe-include-editform-modal").modal("show");
Grocy.FrontendHelpers.ValidateForm("recipe-include-form");
}, },
function(xhr) function(xhr)
{ {
@ -247,6 +257,44 @@ $("#recipe-include-add-button").on("click", function(e)
); );
}); });
$('#save-recipe-include-button').on('click', function(e)
{
e.preventDefault();
var nestingId = $("#recipe-include-form").data("recipe-nesting-id");
var editMode = $("#recipe-include-form").data("edit-mode");
var jsonData = $('#recipe-include-form').serializeJSON();
jsonData.recipe_id = Grocy.EditObjectId;
if (editMode === 'create')
{
Grocy.Api.Post('add-object/recipes_nestings', jsonData,
function(result)
{
window.location.href = U('/recipe/' + Grocy.EditObjectId);
},
function(xhr)
{
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
}
);
}
else
{
Grocy.Api.Post('edit-object/recipes_nestings/' + nestingId, jsonData,
function(result)
{
window.location.href = U('/recipe/' + Grocy.EditObjectId);
},
function(xhr)
{
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
}
);
}
});
$('#description').summernote({ $('#description').summernote({
minHeight: '300px', minHeight: '300px',
lang: L('summernote_locale') lang: L('summernote_locale')

View File

@ -1,62 +0,0 @@
$('#save-recipe-include-button').on('click', function(e)
{
e.preventDefault();
var jsonData = $('#recipe-include-form').serializeJSON();
jsonData.recipe_id = Grocy.EditObjectParentId;
if (Grocy.EditMode === 'create')
{
Grocy.Api.Post('add-object/recipes_nestings', jsonData,
function(result)
{
window.location.href = U('/recipe/' + Grocy.EditObjectParentId);
},
function(xhr)
{
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
}
);
}
else
{
Grocy.Api.Post('edit-object/recipes_nestings/' + Grocy.EditObjectId, jsonData,
function(result)
{
window.location.href = U('/recipe/' + Grocy.EditObjectParentId);
},
function(xhr)
{
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
}
);
}
});
Grocy.FrontendHelpers.ValidateForm('recipe-include-form');
$('#recipe-include-form input').keyup(function(event)
{
Grocy.FrontendHelpers.ValidateForm('recipe-include-form');
});
$('#recipe-include-form select').change(function(event)
{
Grocy.FrontendHelpers.ValidateForm('recipe-include-form');
});
$('#recipe-include-form input').keydown(function(event)
{
if (event.keyCode === 13) //Enter
{
event.preventDefault();
if (document.getElementById('recipe-include-form').checkValidity() === false) //There is at least one validation error
{
return false;
}
else
{
$('#save-include-include-button').click();
}
}
});

View File

@ -40,7 +40,6 @@ $app->group('', function()
$this->get('/recipes', '\Grocy\Controllers\RecipesController:Overview'); $this->get('/recipes', '\Grocy\Controllers\RecipesController:Overview');
$this->get('/recipe/{recipeId}', '\Grocy\Controllers\RecipesController:RecipeEditForm'); $this->get('/recipe/{recipeId}', '\Grocy\Controllers\RecipesController:RecipeEditForm');
$this->get('/recipe/{recipeId}/pos/{recipePosId}', '\Grocy\Controllers\RecipesController:RecipePosEditForm'); $this->get('/recipe/{recipeId}/pos/{recipePosId}', '\Grocy\Controllers\RecipesController:RecipePosEditForm');
$this->get('/recipe/{recipeId}/included_recipe/{recipeIncludeId}', '\Grocy\Controllers\RecipesController:RecipeIncludeEditForm');
// Chore routes // Chore routes
$this->get('/choresoverview', '\Grocy\Controllers\ChoresController:Overview'); $this->get('/choresoverview', '\Grocy\Controllers\ChoresController:Overview');

View File

@ -31,6 +31,9 @@ class DemoDataGeneratorService extends BaseService
INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Can')}', '{$localizationService->Localize('Cans')}'); --6 INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Can')}', '{$localizationService->Localize('Cans')}'); --6
INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Bunch')}', '{$localizationService->Localize('Bunches')}'); --7 INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Bunch')}', '{$localizationService->Localize('Bunches')}'); --7
INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Gram')}', '{$localizationService->Localize('Grams')}'); --8 INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Gram')}', '{$localizationService->Localize('Grams')}'); --8
INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Liter')}', '{$localizationService->Localize('Liters')}'); --9
INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Bottle')}', '{$localizationService->Localize('Bottles')}'); --10
INSERT INTO quantity_units (name, name_plural) VALUES ('{$localizationService->Localize('Milliliter')}', '{$localizationService->Localize('Milliliters')}'); --11
INSERT INTO product_groups(name) VALUES ('01 {$localizationService->Localize('Sweets')}'); --1 INSERT INTO product_groups(name) VALUES ('01 {$localizationService->Localize('Sweets')}'); --1
INSERT INTO product_groups(name) VALUES ('02 {$localizationService->Localize('Bakery products')}'); --2 INSERT INTO product_groups(name) VALUES ('02 {$localizationService->Localize('Bakery products')}'); --2
@ -62,6 +65,7 @@ class DemoDataGeneratorService extends BaseService
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id) VALUES ('{$localizationService->Localize('Minced meat')}', 2, 3, 3, 1, 4); --20 INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id) VALUES ('{$localizationService->Localize('Minced meat')}', 2, 3, 3, 1, 4); --20
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id) VALUES ('{$localizationService->Localize('Flour')}', 2, 3, 3, 1, 3); --21 INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id) VALUES ('{$localizationService->Localize('Flour')}', 2, 3, 3, 1, 3); --21
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id) VALUES ('{$localizationService->Localize('Sugar')}', 3, 3, 3, 1, 3); --22 INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, product_group_id) VALUES ('{$localizationService->Localize('Sugar')}', 3, 3, 3, 1, 3); --22
INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Milk')}', 2, 10, 10, 1); --23
INSERT INTO shopping_list (note, amount) VALUES ('{$localizationService->Localize('Some good snacks')}', 1); INSERT INTO shopping_list (note, amount) VALUES ('{$localizationService->Localize('Some good snacks')}', 1);
INSERT INTO shopping_list (product_id, amount) VALUES (20, 1); INSERT INTO shopping_list (product_id, amount) VALUES (20, 1);
@ -71,6 +75,8 @@ class DemoDataGeneratorService extends BaseService
INSERT INTO recipes (name, description) VALUES ('{$localizationService->Localize('Spaghetti bolognese')}', '{$loremIpsumWithHtmlFormattings}'); --2 INSERT INTO recipes (name, description) VALUES ('{$localizationService->Localize('Spaghetti bolognese')}', '{$loremIpsumWithHtmlFormattings}'); --2
INSERT INTO recipes (name, description) VALUES ('{$localizationService->Localize('Sandwiches')}', '{$loremIpsumWithHtmlFormattings}'); --3 INSERT INTO recipes (name, description) VALUES ('{$localizationService->Localize('Sandwiches')}', '{$loremIpsumWithHtmlFormattings}'); --3
INSERT INTO recipes (name, description) VALUES ('{$localizationService->Localize('Pancakes')}', '{$loremIpsumWithHtmlFormattings}'); --4 INSERT INTO recipes (name, description) VALUES ('{$localizationService->Localize('Pancakes')}', '{$loremIpsumWithHtmlFormattings}'); --4
INSERT INTO recipes (name, description) VALUES ('{$localizationService->Localize('Chocolate sauce')}', '{$loremIpsumWithHtmlFormattings}'); --5
INSERT INTO recipes (name, description) VALUES ('{$localizationService->Localize('Pancakes')} / {$localizationService->Localize('Chocolate sauce')}', '{$loremIpsumWithHtmlFormattings}'); --6
INSERT INTO recipes_pos (recipe_id, product_id, amount) VALUES (1, 16, 1); INSERT INTO recipes_pos (recipe_id, product_id, amount) VALUES (1, 16, 1);
INSERT INTO recipes_pos (recipe_id, product_id, amount) VALUES (1, 17, 1); INSERT INTO recipes_pos (recipe_id, product_id, amount) VALUES (1, 17, 1);
@ -85,6 +91,11 @@ class DemoDataGeneratorService extends BaseService
INSERT INTO recipes_pos (recipe_id, product_id, amount) VALUES (4, 5, 4); INSERT INTO recipes_pos (recipe_id, product_id, amount) VALUES (4, 5, 4);
INSERT INTO recipes_pos (recipe_id, product_id, amount, qu_id, only_check_single_unit_in_stock) VALUES (4, 21, 200, 8, 1); INSERT INTO recipes_pos (recipe_id, product_id, amount, qu_id, only_check_single_unit_in_stock) VALUES (4, 21, 200, 8, 1);
INSERT INTO recipes_pos (recipe_id, product_id, amount, qu_id, only_check_single_unit_in_stock) VALUES (4, 22, 200, 8, 1); INSERT INTO recipes_pos (recipe_id, product_id, amount, qu_id, only_check_single_unit_in_stock) VALUES (4, 22, 200, 8, 1);
INSERT INTO recipes_pos (recipe_id, product_id, amount) VALUES (5, 2, 1);
INSERT INTO recipes_pos (recipe_id, product_id, amount, qu_id, only_check_single_unit_in_stock) VALUES (5, 23, 200, 11, 1);
INSERt INTO recipes_nestings(recipe_id, includes_recipe_id) VALUES (6, 4);
INSERt INTO recipes_nestings(recipe_id, includes_recipe_id) VALUES (6, 5);
INSERT INTO chores (name, period_type, period_days) VALUES ('{$localizationService->Localize('Changed towels in the bathroom')}', 'manually', 5); --1 INSERT INTO chores (name, period_type, period_days) VALUES ('{$localizationService->Localize('Changed towels in the bathroom')}', 'manually', 5); --1
INSERT INTO chores (name, period_type, period_days) VALUES ('{$localizationService->Localize('Cleaned the kitchen floor')}', 'dynamic-regular', 7); --2 INSERT INTO chores (name, period_type, period_days) VALUES ('{$localizationService->Localize('Cleaned the kitchen floor')}', 'dynamic-regular', 7); --2
@ -184,6 +195,8 @@ class DemoDataGeneratorService extends BaseService
$stockService->AddProduct(21, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice()); $stockService->AddProduct(21, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
$stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice()); $stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-10 days')), $this->RandomPrice());
$stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice()); $stockService->AddProduct(22, 1, date('Y-m-d', strtotime('+200 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-20 days')), $this->RandomPrice());
$stockService->AddProduct(23, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-40 days')), $this->RandomPrice());
$stockService->AddProduct(23, 1, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE, date('Y-m-d', strtotime('-50 days')), $this->RandomPrice());
$stockService->AddMissingProductsToShoppingList(); $stockService->AddMissingProductsToShoppingList();
$choresService = new ChoresService(); $choresService = new ChoresService();

View File

@ -123,15 +123,15 @@
@foreach($recipeNestings as $recipeNesting) @foreach($recipeNestings as $recipeNesting)
<tr> <tr>
<td class="fit-content"> <td class="fit-content">
<a class="btn btn-sm btn-info recipe-include-edit-button" href="#" data-recipe-include-id="{{ $recipeNesting->id }}"> <a class="btn btn-sm btn-info recipe-include-edit-button" href="#" data-recipe-include-id="{{ $recipeNesting->id }}" data-recipe-included-recipe-id="{{ $recipeNesting->includes_recipe_id }}">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</a> </a>
<a class="btn btn-sm btn-danger recipe-inlcude-delete-button" href="#" data-recipe-include-id="{{ $recipeNesting->id }}" data-recipe-include-name="{{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->recipe_id)->name }}"> <a class="btn btn-sm btn-danger recipe-include-delete-button" href="#" data-recipe-include-id="{{ $recipeNesting->id }}" data-recipe-include-name="{{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }}">
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
</a> </a>
</td> </td>
<td> <td>
{{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->recipe_id)->name }} {{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }}
</td> </td>
</tr> </tr>
@endforeach @endforeach
@ -142,4 +142,34 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="recipe-include-editform-modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content text-center">
<div class="modal-header">
<h4 id="recipe-include-editform-title" class="modal-title w-100"></h4>
</div>
<div class="modal-body">
<form id="recipe-include-form" novalidate>
<div class="form-group">
<label for="includes_recipe_id">{{ $L('Recipe') }}</label>
<select required class="form-control" id="includes_recipe_id" name="includes_recipe_id">
<option></option>
@foreach($recipes as $recipeForList)
@if($recipeForList->id !== $recipe->id)
<option data-already-included="{{ BoolToString(FindObjectInArrayByPropertyValue($recipeNestings, 'includes_recipe_id', $recipeForList->id) === null) }}" value="{{ $recipeForList->id }}">{{ $recipeForList->name }}</option>
@endif
@endforeach
</select>
<div class="invalid-feedback">{{ $L('A recipe is required') }}</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ $L('Cancel') }}</button>
<button id="save-recipe-include-button" data-dismiss="modal" class="btn btn-success">{{ $L('Save') }}</button>
</div>
</div>
</div>
</div>
@stop @stop

View File

@ -1,44 +0,0 @@
@extends('layout.default')
@if($mode == 'edit')
@section('title', $L('Edit included recipe'))
@else
@section('title', $L('Add included recipe'))
@endif
@section('viewJsName', 'recipeincludeform')
@section('content')
<div class="row">
<div class="col-xs-12 col-md-6 col-xl-5 pb-3">
<h1>@yield('title')</h1>
<h3 class="text-muted">{{ $L('Recipe') }} <strong>{{ $recipe->name }}</strong></h3>
<script>
Grocy.EditMode = '{{ $mode }}';
Grocy.EditObjectParentId = {{ $recipe->id }};
</script>
@if($mode == 'edit')
<script>Grocy.EditObjectId = {{ $recipeInclude->id }};</script>
@endif
<form id="recipe-include-form" novalidate>
<div class="form-group">
<label for="includes_recipe_id">{{ $L('Recipe') }}</label>
<select required class="form-control" id="includes_recipe_id" name="includes_recipe_id">
<option></option>
@foreach($recipes as $recipe)
<option @if($mode == 'edit' && $recipe->id == $recipeInclude->includes_recipe_id) selected="selected" @endif value="{{ $recipe->id }}">{{ $recipe->name }}</option>
@endforeach
</select>
<div class="invalid-feedback">{{ $L('A recipe is required') }}</div>
</div>
<button id="save-recipe-include-button" class="btn btn-success">{{ $L('Save') }}</button>
</form>
</div>
</div>
@stop

View File

@ -62,6 +62,41 @@
<i class="fas fa-expand-arrows-alt"></i> <i class="fas fa-expand-arrows-alt"></i>
</a> </a>
</div> </div>
<!-- Subrecipes first -->
@foreach($selectedRecipeSubRecipes as $selectedRecipeSubRecipe)
<div class="card-body">
<h3 class="mb-0">{{ $selectedRecipeSubRecipe->name }}</h3>
</div>
@php $selectedRecipeSubRecipePositionsFiltered = FindAllObjectsInArrayByPropertyValue($selectedRecipeSubRecipesPositions, 'recipe_id', $selectedRecipeSubRecipe->id); @endphp
@if(count($selectedRecipeSubRecipePositionsFiltered) > 0)
<div class="card-body">
<h5 class="mb-0">{{ $L('Ingredients') }}</h5>
</div>
<ul class="list-group list-group-flush">
@foreach($selectedRecipeSubRecipePositionsFiltered as $selectedRecipePosition)
<li class="list-group-item">
{{ $selectedRecipePosition->amount }} {{ Pluralize($selectedRecipePosition->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', $selectedRecipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $selectedRecipePosition->qu_id)->name_plural) }} {{ FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id)->name }}
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $selectedRecipePosition->id)->need_fulfilled == 1) {{ $L('Enough in stock') }} @else {{ $L('Not enough in stock, #1 missing, #2 already on shopping list', FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $selectedRecipePosition->id)->missing_amount, FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $selectedRecipePosition->id)->amount_on_shopping_list) }} @endif</span>
@if(!empty($selectedRecipePosition->note))
<div class="text-muted">{{ $selectedRecipePosition->note }}</div>
@endif
</li>
@endforeach
</ul>
@endif
@if(!empty($selectedRecipeSubRecipe->description))
<div class="card-body">
<h5>{{ $L('Preparation') }}</h5>
{!! $selectedRecipeSubRecipe->description !!}
</div>
@endif
@endforeach
<!-- Selected recipe -->
@if($selectedRecipePositions->count() > 0)
<div class="card-body"> <div class="card-body">
<h5 class="mb-0">{{ $L('Ingredients') }}</h5> <h5 class="mb-0">{{ $L('Ingredients') }}</h5>
</div> </div>
@ -77,10 +112,13 @@
</li> </li>
@endforeach @endforeach
</ul> </ul>
@endif
@if(!empty($selectedRecipe->description))
<div class="card-body"> <div class="card-body">
<h5>{{ $L('Preparation') }}</h5> <h5>{{ $L('Preparation') }}</h5>
{!! $selectedRecipe->description !!} {!! $selectedRecipe->description !!}
</div> </div>
@endif
</div> </div>
</div> </div>
@endif @endif