Implemented the option to automatically consume a product on tracking a chore execution (closes #279)

This commit is contained in:
Bernd Bestel 2019-09-18 10:02:52 +02:00
parent e326e69d49
commit 3df44697bf
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
7 changed files with 122 additions and 36 deletions

View File

@ -1,41 +1,47 @@
- Stock improvements ### Stock improvements
- Products can now have variations (nested products) - Products can now have variations (nested products)
- Define the parent product for a product on the product edit page (only one level is possible, means a product which is used as a parent product in another product, cannot have a parent product itself) - Define the parent product for a product on the product edit page (only one level is possible, means a product which is used as a parent product in another product, cannot have a parent product itself)
- Parent and sub products can have stock (both are regular products, no difference from that side) - Parent and sub products can have stock (both are regular products, no difference from that side)
- On the stock overview page the aggregated amount is displayed next to the amount (sigma sign) - On the stock overview page the aggregated amount is displayed next to the amount (sigma sign)
- When a recipe needs a parent product, the need is also fulfilled when enough sub product(s) are in stock - When a recipe needs a parent product, the need is also fulfilled when enough sub product(s) are in stock
- Quantity units can now be linked (related measurements / unit conversion) - Quantity units can now be linked (related measurements / unit conversion)
- On the quantity unit edit page default conversion can be defined for each unit - On the quantity unit edit page default conversion can be defined for each unit
- Products "inherit" the default conversion and additionally can have their own / override the default ones - Products "inherit" the default conversion and additionally can have their own / override the default ones
- It's now possible to print a "Location Content Sheet" with the current stock per location - new button at the top of the stock overview page (thought to hang it at the location, note used amounts on paper and track it in grocy later) - It's now possible to print a "Location Content Sheet" with the current stock per location - new button at the top of the stock overview page (thought to hang it at the location, note used amounts on paper and track it in grocy later)
- The product description now can have formattings (HTML/WYSIWYG editor like for recipes) - The product description now can have formattings (HTML/WYSIWYG editor like for recipes)
- "Factor purchase to stock quantity unit" (product option) can now also be a decimal number when "Allow partial units in stock" is enabled - "Factor purchase to stock quantity unit" (product option) can now also be a decimal number when "Allow partial units in stock" is enabled
- Recipe improvements
- Based on the new linked quantity units, recipe ingredients can now use any product related unit, the amount is calculated according to the cnoversion factor of the unit relation ### Recipe improvements
- Chores improvements - Based on the new linked quantity units, recipe ingredients can now use any product related unit, the amount is calculated according to the cnoversion factor of the unit relation
- Chores can now be assigned to users
- Option per chore, different "assignment types" like "Random", "Who least did first", etc. ### Chores improvements
- On the chores overview page the list can be filterd to only show chores assigned to the currently logged in user (or to any other user) - Chores can now be assigned to users
- New option "Due date rollover" per chore which means the chore can never be overdue, the due date will shift forward each day when due - Option per chore, different "assignment types" like "Random", "Who least did first", etc.
- When tracking an execution from the chores overview page, filters are re-applied afterwards (means when have filtered the page to only show overdue chores and after the execution the chore is not overdue anymore, it will now immediately hide id) - On the chores overview page the list can be filterd to only show chores assigned to the currently logged in user (or to any other user)
- Equipment improvements/fixes - New option "Due date rollover" per chore which means the chore can never be overdue, the due date will shift forward each day when due
- Fixed that the delete button not always deleted the currently selected equipment item - New option "Consume product on chore execution" per chore to automatically consume a product when a chore execution is tracked
- Userfield improvements/fixes - When tracking an execution from the chores overview page, filters are re-applied afterwards (means when have filtered the page to only show overdue chores and after the execution the chore is not overdue anymore, it will now immediately hide id)
- New Userfield type "Select list" for a list of predefined values where a single or also multiple values can then be selected on the entity object
- New Userfield type "Link" - a single-line-textbox where the content will be rendered as a clickable link ### Equipment improvements/fixes
- Userfields of type "checkbox" are rendered as a checkmark in tables when checked (instead of "1" as till now) - Fixed that the delete button not always deleted the currently selected equipment item
- Product Userfields are now also rendered on the shopping list (for items which have a product referenced)
- Fixed that the Userfield type "Preset list" had always the caption "Product group" instead of the configured one (thanks @oncleben31) ### Userfield improvements/fixes
- General improvements/fixes - New Userfield type "Select list" for a list of predefined values where a single or also multiple values can then be selected on the entity object
- Improved the handling which entry page to use with disabled feature flags (thanks @nielstholenaar) - New Userfield type "Link" - a single-line-textbox where the content will be rendered as a clickable link
- Boolean settings provided via environment variables (so the strings `true` and `false`) are now parsed correctly (thanks @mduret) - Userfields of type "checkbox" are rendered as a checkmark in tables when checked (instead of "1" as till now)
- API improvements & non-breaking changes - Product Userfields are now also rendered on the shopping list (for items which have a product referenced)
- Fixed that the Userfield type "Preset list" had always the caption "Product group" instead of the configured one (thanks @oncleben31)
### General improvements/fixes
- Improved the handling which entry page to use with disabled feature flags (thanks @nielstholenaar)
- Boolean settings provided via environment variables (so the strings `true` and `false`) are now parsed correctly (thanks @mduret)
### API improvements & non-breaking changes
- New endpoint `/stock/shoppinglist/add-product` to add a product to a shopping list (thanks @Forceu) - New endpoint `/stock/shoppinglist/add-product` to add a product to a shopping list (thanks @Forceu)
- New endpoint `/stock/shoppinglist/remove-product` to remove a product from a shopping list (thanks @Forceu) - New endpoint `/stock/shoppinglist/remove-product` to remove a product from a shopping list (thanks @Forceu)
- New endpoint `/chores/executions/calculate-next-assignments` to (re)calculate next user assignments for a single or all chores - New endpoint `/chores/executions/calculate-next-assignments` to (re)calculate next user assignments for a single or all chores
- New endpoint `/objects/{entity}/search/{searchString}` search for objects by name (contains search) - New endpoint `/objects/{entity}/search/{searchString}` search for objects by name (contains search)
- When adding a product (through `stock/product/{productId}/add` or `stock/product/{productId}/inventory`) with omitted best before date and if the given product has "Default best before days" set, the best before date is calculated based on that (so far always today was used which is still the case when no date is supplied and also the product has no "Default best before days set) (thanks @Forceu) - When adding a product (through `stock/product/{productId}/add` or `stock/product/{productId}/inventory`) with omitted best before date and if the given product has "Default best before days" set, the best before date is calculated based on that (so far always today was used which is still the case when no date is supplied and also the product has no "Default best before days set) (thanks @Forceu)
- Field `stock_amount` of endpoint `/stock/products/{productId}´ now returns `0` instead of `null` when the given product is not in stock (thanks @Forceu) - Field `stock_amount` of endpoint `/stock/products/{productId}´ now returns `0` instead of `null` when the given product is not in stock (thanks @Forceu)
- `/stock/products/{productId}` returns additional fields for the aggregated amount(s): `stock_amount_aggregated` and `stock_amount_opened_aggregated` - contains the same for "normal" products, `is_aggregated_amount` indicates if aggregation has happened
- Fixed that `/system/db-changed-time` always returned the current time (more or less) due to that that time is the database file modification time and the database is effectively changed on each request because of session information tracking - which now explicitly does not change the database file modification time, so this should work again to determine if any data changes happened - Fixed that `/system/db-changed-time` always returned the current time (more or less) due to that that time is the database file modification time and the database is effectively changed on each request because of session information tracking - which now explicitly does not change the database file modification time, so this should work again to determine if any data changes happened
- It's now also possible to provide the API key via a query parameter (same name as the header, so `GROCY-API-KEY`) - It's now also possible to provide the API key via a query parameter (same name as the header, so `GROCY-API-KEY`)

View File

@ -71,7 +71,8 @@ class ChoresController extends BaseController
'mode' => 'create', 'mode' => 'create',
'userfields' => $this->UserfieldsService->GetFields('chores'), 'userfields' => $this->UserfieldsService->GetFields('chores'),
'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'), 'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'),
'users' => $users 'users' => $users,
'products' => $this->Database->products()->orderBy('name')
]); ]);
} }
else else
@ -82,7 +83,8 @@ class ChoresController extends BaseController
'mode' => 'edit', 'mode' => 'edit',
'userfields' => $this->UserfieldsService->GetFields('chores'), 'userfields' => $this->UserfieldsService->GetFields('chores'),
'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'), 'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'),
'users' => $users 'users' => $users,
'products' => $this->Database->products()->orderBy('name')
]); ]);
} }
} }

View File

@ -1417,3 +1417,6 @@ msgstr ""
msgid "Filter by assignment" msgid "Filter by assignment"
msgstr "" msgstr ""
msgid "Consume product on chore execution"
msgstr ""

8
migrations/0084.sql Normal file
View File

@ -0,0 +1,8 @@
ALTER TABLE chores
ADD consume_product_on_execution TINYINT NOT NULL DEFAULT 0;
ALTER TABLE chores
ADD product_id TINYINT;
ALTER TABLE chores
ADD product_amount REAL;

View File

@ -102,6 +102,10 @@ setTimeout(function()
{ {
$(".input-group-chore-period-type").trigger("change"); $(".input-group-chore-period-type").trigger("change");
$(".input-group-chore-assignment-type").trigger("change"); $(".input-group-chore-assignment-type").trigger("change");
// Click twice to trigger on-click but not change the actual checked state
$("#consume_product_on_execution").click();
$("#consume_product_on_execution").click();
}, 100); }, 100);
$('.input-group-chore-period-type').on('change', function(e) $('.input-group-chore-period-type').on('change', function(e)
@ -180,3 +184,19 @@ $('.input-group-chore-assignment-type').on('change', function(e)
Grocy.FrontendHelpers.ValidateForm('chore-form'); Grocy.FrontendHelpers.ValidateForm('chore-form');
}); });
$("#consume_product_on_execution").on("click", function()
{
if (this.checked)
{
Grocy.Components.ProductPicker.GetInputElement().removeAttr("disabled");
$("#product_amount").removeAttr("disabled");
}
else
{
Grocy.Components.ProductPicker.GetInputElement().attr("disabled", "");
$("#product_amount").attr("disabled", "");
}
Grocy.FrontendHelpers.ValidateForm("chore-form");
});

View File

@ -2,6 +2,8 @@
namespace Grocy\Services; namespace Grocy\Services;
use \Grocy\Services\StockService;
class ChoresService extends BaseService class ChoresService extends BaseService
{ {
const CHORE_PERIOD_TYPE_MANUALLY = 'manually'; const CHORE_PERIOD_TYPE_MANUALLY = 'manually';
@ -15,6 +17,14 @@ class ChoresService extends BaseService
const CHORE_ASSIGNMENT_TYPE_RANDOM = 'random'; const CHORE_ASSIGNMENT_TYPE_RANDOM = 'random';
const CHORE_ASSIGNMENT_TYPE_IN_ALPHABETICAL_ORDER = 'in-alphabetical-order'; const CHORE_ASSIGNMENT_TYPE_IN_ALPHABETICAL_ORDER = 'in-alphabetical-order';
public function __construct()
{
parent::__construct();
$this->StockService = new StockService();
}
protected $StockService;
public function GetCurrent() public function GetCurrent()
{ {
$sql = 'SELECT * from chores_current'; $sql = 'SELECT * from chores_current';
@ -84,9 +94,15 @@ class ChoresService extends BaseService
'done_by_user_id' => $doneBy 'done_by_user_id' => $doneBy
)); ));
$logRow->save(); $logRow->save();
$lastInsertId = $this->Database->lastInsertId(); $lastInsertId = $this->Database->lastInsertId();
$this->CalculateNextExecutionAssignment($choreId); $this->CalculateNextExecutionAssignment($choreId);
if ($chore->consume_product_on_execution == 1 && !empty($chore->product_id))
{
$this->StockService->ConsumeProduct($chore->product_id, $chore->product_amount, false, StockService::TRANSACTION_TYPE_CONSUME);
}
return $lastInsertId; return $lastInsertId;
} }

View File

@ -126,6 +126,37 @@
</div> </div>
</div> </div>
@if(GROCY_FEATURE_FLAG_STOCK)
<div class="form-group mt-4 mb-1">
<div class="form-check">
<input type="hidden" name="consume_product_on_execution" value="0">
<input @if($mode == 'edit' && $chore->consume_product_on_execution == 1) checked @endif class="form-check-input" type="checkbox" id="consume_product_on_execution" name="consume_product_on_execution" value="1">
<label class="form-check-label" for="consume_product_on_execution">{{ $__t('Consume product on chore execution') }}</label>
</div>
</div>
@php $prefillById = ''; if($mode=='edit' && !empty($chore->product_id)) { $prefillById = $chore->product_id; } @endphp
@include('components.productpicker', array(
'products' => $products,
'nextInputSelector' => '#product_amount',
'isRequired' => false,
'disallowAllProductWorkflows' => true,
'prefillById' => $prefillById
))
@php if($mode == 'edit') { $value = $chore->product_amount; } else { $value = ''; } @endphp
@include('components.numberpicker', array(
'id' => 'product_amount',
'label' => 'Amount',
'hintId' => 'amount_qu_unit',
'min' => 0.0001,
'step' => 0.0001,
'invalidFeedback' => $__t('The amount cannot be lower than %s', '1'),
'isRequired' => false,
'value' => $value
))
@endif
@include('components.userfieldsform', array( @include('components.userfieldsform', array(
'userfields' => $userfields, 'userfields' => $userfields,
'entity' => 'chores' 'entity' => 'chores'