Products allowed in meal plan

This commit is contained in:
Kurt Riddlesperger 2020-01-24 00:56:59 -06:00
parent 5c602ce74e
commit 52698e43b0
4 changed files with 127 additions and 12 deletions

View File

@ -132,6 +132,7 @@ class RecipesController extends BaseController
public function MealPlan(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) public function MealPlan(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
{ {
$recipes = $this->Database->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll(); $recipes = $this->Database->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll();
$products = $this->Database->products()->orderBy('name');
$events = array(); $events = array();
foreach($this->Database->meal_plan() as $mealPlanEntry) foreach($this->Database->meal_plan() as $mealPlanEntry)
@ -141,22 +142,39 @@ class RecipesController extends BaseController
if ($recipe !== null) if ($recipe !== null)
{ {
$title = $recipe->name; $title = $recipe->name;
$events[] = array(
'id' => $mealPlanEntry['id'],
'title' => $title,
'start' => $mealPlanEntry['day'],
'date_format' => 'date',
'recipe' => json_encode($recipe),
'mealPlanEntry' => json_encode($mealPlanEntry),
'type' => $mealPlanEntry['type']
);
} }
$events[] = array( $product = FindObjectInArrayByPropertyValue($products, 'id', $mealPlanEntry['product_id']);
'id' => $mealPlanEntry['id'], if ($product !== null)
'title' => $title, {
'start' => $mealPlanEntry['day'], $title = $product->name;
'date_format' => 'date',
'recipe' => json_encode($recipe), $events[] = array(
'mealPlanEntry' => json_encode($mealPlanEntry), 'id' => $mealPlanEntry['id'],
'type' => $mealPlanEntry['type'] 'title' => $title,
); 'start' => $mealPlanEntry['day'],
'date_format' => 'date',
'product' => json_encode($product),
'mealPlanEntry' => json_encode($mealPlanEntry),
'type' => $mealPlanEntry['type']
);
}
} }
return $this->AppContainer->view->render($response, 'mealplan', [ return $this->AppContainer->view->render($response, 'mealplan', [
'fullcalendarEventSources' => $events, 'fullcalendarEventSources' => $events,
'recipes' => $recipes, 'recipes' => $recipes,
'products' => $products,
'internalRecipes' => $this->Database->recipes()->whereNot('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll(), 'internalRecipes' => $this->Database->recipes()->whereNot('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll(),
'recipesResolved' => $this->RecipesService->GetRecipesResolved() 'recipesResolved' => $this->RecipesService->GetRecipesResolved()
]); ]);

View File

@ -6,6 +6,7 @@ CREATE TABLE meal_plan (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
day DATE NOT NULL, day DATE NOT NULL,
type TEXT DEFAULT 'recipe', type TEXT DEFAULT 'recipe',
product_id INTEGER,
recipe_id INTEGER, recipe_id INTEGER,
recipe_servings INTEGER DEFAULT 1, recipe_servings INTEGER DEFAULT 1,
note TEXT, note TEXT,

View File

@ -157,6 +157,33 @@ var calendar = $("#calendar").fullCalendar({
} }
} }
} }
if (event.type == "product")
{
var product = JSON.parse(event.product);
if (product === null || product === undefined)
{
return false;
}
element.attr("data-product", event.product);
var productConsumeButtonDisabledClasses = "";
element.html('\
<div> \
<h5 class="text-truncate">' + product.name + '<h5> \
<h5 class="small text-truncate">' + __n(mealPlanEntry.recipe_servings, "%s serving", "%s servings") + '</h5> \
<h5> \
<a class="ml-1 btn btn-outline-danger btn-xs remove-recipe-button" href="#"><i class="fas fa-trash"></i></a> \
<a class="ml-1 btn btn-outline-success btn-xs product-consume-button ' + productConsumeButtonDisabledClasses + '" href="#" data-toggle="tooltip" title="' + __t("Consume product") + '" data-product-id="' + product.id.toString() + '" data-product-name="' + product.name + '" data-servings-amount="' + mealPlanEntry.recipe_servings + '"><i class="fas fa-utensils"></i></a> \
</h5> \
</div>');
if (product.picture_file_name && !product.picture_file_name.isEmpty())
{
element.html(element.html() + '<div class="mx-auto"><img data-src="' + U("/api/files/productpictures/") + btoa(product.picture_file_name) + '?force_serve_as=picture&best_fit_width=400" class="img-fluid lazy"></div>')
}
}
else if (event.type == "note") else if (event.type == "note")
{ {
element.html('\ element.html('\
@ -254,7 +281,18 @@ $('#save-add-recipe-button').on('click', function(e)
return false; return false;
} }
Grocy.Api.Post('objects/meal_plan', $('#add-recipe-form').serializeJSON(), var jsonData = $('#add-recipe-form').serializeJSON();
if (Grocy.Components.RecipePicker.GetValue() != "")
{
jsonData.type = "recipe";
}
else if (Grocy.Components.ProductPicker.GetValue() != "")
{
jsonData.type = "product";
}
Grocy.Api.Post('objects/meal_plan', jsonData,
function(result) function(result)
{ {
window.location.reload(); window.location.reload();
@ -376,6 +414,45 @@ $(document).on('click', '.recipe-order-missing-button', function(e)
}); });
}); });
$(document).on('click', '.product-consume-button', function(e)
{
e.preventDefault();
// Remove the focus from the current button
// to prevent that the tooltip stays until clicked anywhere else
document.activeElement.blur();
Grocy.FrontendHelpers.BeginUiBusy();
var productId = $(e.currentTarget).attr('data-product-id');
var consumeAmount = $(e.currentTarget).attr('data-servings-amount');
Grocy.Api.Post('stock/products/' + productId + '/consume', { 'amount': consumeAmount, 'spoiled': false },
function(bookingResponse)
{
Grocy.Api.Get('stock/products/' + productId,
function(result)
{
var toastMessage = __t('Removed %1$s of %2$s from stock', consumeAmount.toString() + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse.transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
Grocy.FrontendHelpers.EndUiBusy();
toastr.success(toastMessage);
},
function(xhr)
{
Grocy.FrontendHelpers.EndUiBusy();
console.error(xhr);
}
);
},
function(xhr)
{
Grocy.FrontendHelpers.EndUiBusy();
console.error(xhr);
}
);
});
$(document).on('click', '.recipe-consume-button', function(e) $(document).on('click', '.recipe-consume-button', function(e)
{ {
// Remove the focus from the current button // Remove the focus from the current button
@ -461,3 +538,16 @@ $(window).on("resize", function()
calendar.fullCalendar("changeView", "basicWeek"); calendar.fullCalendar("changeView", "basicWeek");
} }
}); });
function UndoStockTransaction(transactionId)
{
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', { },
function (result)
{
toastr.success(__t("Transaction successfully undone"));
},
function (xhr)
{
console.error(xhr);
}
);
};

View File

@ -45,7 +45,14 @@
@include('components.recipepicker', array( @include('components.recipepicker', array(
'recipes' => $recipes, 'recipes' => $recipes,
'isRequired' => true, 'isRequired' => false,
'nextInputSelector' => '#recipe_servings'
))
@include('components.productpicker', array(
'products' => $products,
'isRequired' => false,
'disallowAllProductWorkflows' => true,
'nextInputSelector' => '#recipe_servings' 'nextInputSelector' => '#recipe_servings'
)) ))
@ -58,7 +65,6 @@
)) ))
<input type="hidden" id="day" name="day" value=""> <input type="hidden" id="day" name="day" value="">
<input type="hidden" name="type" value="recipe">
</form> </form>
</div> </div>