diff --git a/controllers/BaseApiController.php b/controllers/BaseApiController.php index 56714c91..710835dc 100644 --- a/controllers/BaseApiController.php +++ b/controllers/BaseApiController.php @@ -6,7 +6,7 @@ use LessQL\Result; class BaseApiController extends BaseController { - const PATTERN_FIELD = '[A-Za-z_][A-Za-z0-9_]+'; + const PATTERN_FIELD = '[A-Za-z_][A-Za-z0-9_\.]+'; const PATTERN_OPERATOR = '!?(=|~|<|>|(>=)|(<=)|(§))'; @@ -16,8 +16,7 @@ class BaseApiController extends BaseController protected function ApiResponse(\Psr\Http\Message\ResponseInterface $response, $data, $cache = false) { - if ($cache) - { + if ($cache) { $response = $response->withHeader('Cache-Control', 'max-age=2592000'); } @@ -39,38 +38,93 @@ class BaseApiController extends BaseController public function FilteredApiResponse(\Psr\Http\Message\ResponseInterface $response, Result $data, array $query) { - $data = $this->queryData($data, $query); + // get total row count + $response = $response->withHeader('x-rowcount-total', $data->count()); + + // apply filter, get filtered row count + $data = $this->applyQuery($data, $query); + $response = $response->withHeader('x-rowcount-filtered', $data->count()); + + // apply limit/order + $data = $this->applyOrder($data, $query); + $data = $this->applyLimit($data, $query); return $this->ApiResponse($response, $data); } - protected function queryData(Result $data, array $query) + protected function applyQuery(Result $data, array $query): Result { - if (isset($query['query'])) - { + if (isset($query['query'])) { $data = $this->filter($data, $query['query']); } - if (isset($query['limit'])) - { + if (isset($query['search'])) { + // get list of fields from table + $stmt = $this->getDatabase()->prepare('SELECT `sql` FROM sqlite_master WHERE `name` = ? LIMIT 1'); + $stmt->execute([$data->getTable()]); + $sql = $stmt->fetchColumn(); + $sql = substr($sql, strpos($sql, '(') + 1); + $sql = substr($sql, 0, strrpos($sql, ')')); + $sql = trim($sql); + while (preg_match('/\(.*?\)/', $sql) === 1) { + $sql = preg_replace('/\([^\(\)]*\)/', '', $sql); + } + $fields = array_map(function ($field) { + preg_match('/\s*([^\s]+)/', $field, $matches); + return $matches[1]; + }, explode(',', $sql)); + + $join_info = match ($data->getTable()) { + 'products' => [ + 'product_group_id' => ['field' => 'name', 'table' => 'product_groups'], + 'location_id' => ['field' => 'name', 'table' => 'locations'], + 'shopping_location_id' => ['field' => 'name', 'table' => 'shopping_locations'], + 'qu_id_purchase' => ['field' => 'name', 'table' => 'quantity_units'], + 'qu_id_stock' => ['field' => 'name', 'table' => 'quantity_units'], + 'parent_product_id' => ['field' => 'name', 'table' => 'products'], + ], + default => [], + }; + + // create search query that matches any field + $fields_query = implode(' OR ', array_map(function ($field) use ($join_info) { + $field_escaped = '`' . str_replace('`', '``', $field) . '`'; + if (array_key_exists($field, $join_info)) { + $table_escaped = '`' . str_replace('`', '``', $join_info[$field]['table']) . '`'; + return $field_escaped . ' IN(SELECT id FROM ' . $table_escaped . ' WHERE `' . str_replace('`', '``', $join_info[$field]['field']) . '` LIKE ? ESCAPE \'\\\')'; + } + return $field_escaped . ' LIKE ? ESCAPE \'\\\''; + }, $fields)); + + // apply search query + $data = $data->where($fields_query, array_fill(0, count($fields), '%' . str_replace(['\\', '%', '_', '*'], ['\\\\', '\\%', '\\_', '%'], $query['search']) . '%')); + } + + return $data; + } + + protected function applyLimit(Result $data, array $query): Result + { + if (isset($query['limit'])) { $data = $data->limit(intval($query['limit']), intval($query['offset'] ?? 0)); } - if (isset($query['order'])) - { - $parts = explode(':', $query['order']); + return $data; + } - if (count($parts) == 1) - { - $data = $data->orderBy($parts[0]); - } - else - { - if ($parts[1] != 'asc' && $parts[1] != 'desc') - { - throw new \Exception('Invalid sort order ' . $parts[1]); + protected function applyOrder(Result $data, array $query): Result + { + if (isset($query['order'])) { + $parts = explode(',', $query['order']); + foreach ($parts as $part) { + $col_dir = explode(':', $part, 2); + if (count($col_dir) == 1) { + $data = $data->orderBy($col_dir[0]); + } else { + if ($col_dir[1] != 'asc' && $col_dir[1] != 'desc' && $col_dir[1] != 'collate nocase') { + throw new \Exception('Invalid sort order ' . $col_dir[1]); + } + $data = $data->orderBy($col_dir[0], $col_dir[1]); } - - $data = $data->orderBy($parts[0], $parts[1]); } } @@ -79,58 +133,73 @@ class BaseApiController extends BaseController protected function filter(Result $data, array $query): Result { - foreach ($query as $q) - { + foreach ($query as $q) { $matches = []; preg_match( '/(?P' . self::PATTERN_FIELD . ')' - . '(?P' . self::PATTERN_OPERATOR . ')' - . '(?P' . self::PATTERN_VALUE . ')/u', + . '(?P' . self::PATTERN_OPERATOR . ')' + . '(?P' . self::PATTERN_VALUE . ')/u', $q, $matches ); - if (!array_key_exists('field', $matches) || !array_key_exists('op', $matches) || !array_key_exists('value', $matches)) - { + if (!array_key_exists('field', $matches) || !array_key_exists('op', $matches) || !array_key_exists('value', $matches) || !in_array($matches['op'], ['=', '!=', '~', '!~', '<', '>', '>=', '<=', '§'], true)) { throw new \Exception('Invalid query'); } + list('field' => $field, 'op' => $op, 'value' => $value) = $matches; - $sqlOrNull = ''; - if (strtolower($matches['value']) == 'null') - { - $sqlOrNull = ' OR ' . $matches['field'] . ' IS NULL'; + $params = match ($op) { + '=' => [$value], + '!=' => [$value], + '~' => ['%' . $value . '%'], + '!~' => ['%' . $value . '%'], + '<' => [$value], + '>' => [$value], + '>=' => [$value], + '<=' => [$value], + '§' => [$value], + default => [], + }; + + $where_prefix = ''; + $where_suffix = ''; + if (strpos($field, '.') !== false) { + list($join, $field) = explode('.', $field, 2); + $join_info = match ($data->getTable()) { + 'products' => [ + 'product_group' => ['id_field' => 'product_group_id', 'table' => 'product_groups'], + 'location' => ['id_field' => 'location_id', 'table' => 'locations'], + 'shopping_location' => ['id_field' => 'shopping_location_id', 'table' => 'shopping_locations'], + 'qu_purchase' => ['id_field' => 'qu_id_purchase', 'table' => 'quantity_units'], + 'qu_stock' => ['id_field' => 'qu_id_stock', 'table' => 'quantity_units'], + 'parent_product' => ['id_field' => 'parent_product_id', 'table' => 'products'], + ], + default => [], + }; + if (!array_key_exists($join, $join_info)) { + throw new \Exception('Invalid query'); + } + $field_escaped = '`' . str_replace('`', '``', $join_info[$join]['id_field']) . '`'; + $table_escaped = '`' . str_replace('`', '``', $join_info[$join]['table']) . '`'; + $where_prefix = $field_escaped . ' IN(SELECT id FROM ' . $table_escaped . ' WHERE '; + $where_suffix = ')'; } - switch ($matches['op']) { - case '=': - $data = $data->where($matches['field'] . ' = ?' . $sqlOrNull, $matches['value']); - break; - case '!=': - $data = $data->where($matches['field'] . ' != ?' . $sqlOrNull, $matches['value']); - break; - case '~': - $data = $data->where($matches['field'] . ' LIKE ?', '%' . $matches['value'] . '%'); - break; - case '!~': - $data = $data->where($matches['field'] . ' NOT LIKE ?', '%' . $matches['value'] . '%'); - break; - case '<': - $data = $data->where($matches['field'] . ' < ?', $matches['value']); - break; - case '>': - $data = $data->where($matches['field'] . ' > ?', $matches['value']); - break; - case '>=': - $data = $data->where($matches['field'] . ' >= ?', $matches['value']); - break; - case '<=': - $data = $data->where($matches['field'] . ' <= ?', $matches['value']); - break; - case '§': - $data = $data->where($matches['field'] . ' REGEXP ?', $matches['value']); - break; + $field_escaped = '`' . str_replace('`', '``', $field) . '`'; + $where = match ($op) { + '=' => $field_escaped . ' = ?' . (strtolower($value) === 'null' ? ' OR ' . $field_escaped . ' IS NULL' : ''), + '!=' => $field_escaped . ' != ?' . (strtolower($value) === 'null' ? ' OR ' . $field_escaped . ' IS NULL' : ''), + '~' => $field_escaped . ' LIKE ?', + '!~' => $field_escaped . ' NOT LIKE ?', + '<' => $field_escaped . ' < ?', + '>' => $field_escaped . ' > ?', + '>=' => $field_escaped . ' >= ?', + '<=' => $field_escaped . ' <= ?', + '§' => $field_escaped . ' REGEXP ?', + default => '', + }; - } + $data = $data->where($where_prefix . $where . $where_suffix, $params); } return $data; @@ -138,8 +207,7 @@ class BaseApiController extends BaseController protected function getOpenApispec() { - if ($this->OpenApiSpec == null) - { + if ($this->OpenApiSpec == null) { $this->OpenApiSpec = json_decode(file_get_contents(__DIR__ . '/../grocy.openapi.json')); } diff --git a/controllers/ChoresController.php b/controllers/ChoresController.php index 6eed1a5d..0465ddd2 100644 --- a/controllers/ChoresController.php +++ b/controllers/ChoresController.php @@ -13,19 +13,15 @@ class ChoresController extends BaseController $usersService = $this->getUsersService(); $users = $usersService->GetUsersAsDto(); - if ($args['choreId'] == 'new') - { + if ($args['choreId'] == 'new') { return $this->renderPage($response, 'choreform', [ 'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_PERIOD_TYPE_'), 'mode' => 'create', 'userfields' => $this->getUserfieldsService()->GetFields('chores'), 'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'), 'users' => $users, - 'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE') ]); - } - else - { + } else { return $this->renderPage($response, 'choreform', [ 'chore' => $this->getDatabase()->chores($args['choreId']), 'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_PERIOD_TYPE_'), @@ -33,19 +29,15 @@ class ChoresController extends BaseController 'userfields' => $this->getUserfieldsService()->GetFields('chores'), 'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'), 'users' => $users, - 'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE') ]); } } public function ChoresList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if (isset($request->getQueryParams()['include_disabled'])) - { + if (isset($request->getQueryParams()['include_disabled'])) { $chores = $this->getDatabase()->chores()->orderBy('name', 'COLLATE NOCASE'); - } - else - { + } else { $chores = $this->getDatabase()->chores()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'); } @@ -63,19 +55,15 @@ class ChoresController extends BaseController public function Journal(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if (isset($request->getQueryParams()['months']) && filter_var($request->getQueryParams()['months'], FILTER_VALIDATE_INT) !== false) - { + if (isset($request->getQueryParams()['months']) && filter_var($request->getQueryParams()['months'], FILTER_VALIDATE_INT) !== false) { $months = $request->getQueryParams()['months']; $where = "tracked_time > DATE(DATE('now', 'localtime'), '-$months months')"; - } - else - { + } else { // Default 1 year $where = "tracked_time > DATE(DATE('now', 'localtime'), '-12 months')"; } - if (isset($request->getQueryParams()['chore']) && filter_var($request->getQueryParams()['chore'], FILTER_VALIDATE_INT) !== false) - { + if (isset($request->getQueryParams()['chore']) && filter_var($request->getQueryParams()['chore'], FILTER_VALIDATE_INT) !== false) { $choreId = $request->getQueryParams()['chore']; $where .= " AND chore_id = $choreId"; } @@ -96,20 +84,13 @@ class ChoresController extends BaseController $chores = $this->getDatabase()->chores()->orderBy('name', 'COLLATE NOCASE'); $currentChores = $this->getChoresService()->GetCurrent(); - foreach ($currentChores as $currentChore) - { - if (FindObjectInArrayByPropertyValue($chores, 'id', $currentChore->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY) - { - if ($currentChore->next_estimated_execution_time < date('Y-m-d H:i:s')) - { + foreach ($currentChores as $currentChore) { + if (FindObjectInArrayByPropertyValue($chores, 'id', $currentChore->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY) { + if ($currentChore->next_estimated_execution_time < date('Y-m-d H:i:s')) { $currentChore->due_type = 'overdue'; - } - elseif ($currentChore->next_estimated_execution_time <= date('Y-m-d 23:59:59')) - { + } elseif ($currentChore->next_estimated_execution_time <= date('Y-m-d 23:59:59')) { $currentChore->due_type = 'duetoday'; - } - elseif ($nextXDays > 0 && $currentChore->next_estimated_execution_time <= date('Y-m-d H:i:s', strtotime('+' . $nextXDays . ' days'))) - { + } elseif ($nextXDays > 0 && $currentChore->next_estimated_execution_time <= date('Y-m-d H:i:s', strtotime('+' . $nextXDays . ' days'))) { $currentChore->due_type = 'duesoon'; } } diff --git a/controllers/GenericEntityApiController.php b/controllers/GenericEntityApiController.php index bbaf83c4..41da2235 100644 --- a/controllers/GenericEntityApiController.php +++ b/controllers/GenericEntityApiController.php @@ -3,7 +3,7 @@ namespace Grocy\Controllers; use Grocy\Controllers\Users\User; -use Slim\Exception\HttpBadRequestException; +use LessQL\Row; class GenericEntityApiController extends BaseApiController { @@ -11,37 +11,28 @@ class GenericEntityApiController extends BaseApiController { User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT); - if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoEdit($args['entity'])) - { - if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) - { + if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoEdit($args['entity'])) { + if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) { User::checkPermission($request, User::PERMISSION_ADMIN); } $requestBody = $this->GetParsedAndFilteredRequestBody($request); - try - { - if ($requestBody === null) - { + try { + if ($requestBody === null) { throw new \Exception('Request body could not be parsed (probably invalid JSON format or missing/wrong Content-Type header)'); } $newRow = $this->getDatabase()->{$args['entity']}()->createRow($requestBody); $newRow->save(); - $success = $newRow->isClean(); return $this->ApiResponse($response, [ 'created_object_id' => $this->getDatabase()->lastInsertId() ]); - } - catch (\Exception $ex) - { + } catch (\Exception $ex) { return $this->GenericErrorResponse($response, $ex->getMessage()); } - } - else - { + } else { return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed'); } } @@ -50,26 +41,20 @@ class GenericEntityApiController extends BaseApiController { User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT); - if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoDelete($args['entity'])) - { - if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) - { + if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoDelete($args['entity'])) { + if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) { User::checkPermission($request, User::PERMISSION_ADMIN); } $row = $this->getDatabase()->{$args['entity']}($args['objectId']); - if ($row == null) - { + if ($row == null) { return $this->GenericErrorResponse($response, 'Object not found', 400); } $row->delete(); - $success = $row->isClean(); return $this->EmptyApiResponse($response); - } - else - { + } else { return $this->GenericErrorResponse($response, 'Invalid entity'); } } @@ -78,102 +63,78 @@ class GenericEntityApiController extends BaseApiController { User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT); - if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoEdit($args['entity'])) - { - if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) - { + if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoEdit($args['entity'])) { + if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) { User::checkPermission($request, User::PERMISSION_ADMIN); } $requestBody = $this->GetParsedAndFilteredRequestBody($request); - try - { - if ($requestBody === null) - { + try { + if ($requestBody === null) { throw new \Exception('Request body could not be parsed (probably invalid JSON format or missing/wrong Content-Type header)'); } $row = $this->getDatabase()->{$args['entity']}($args['objectId']); - if ($row == null) - { + if ($row == null) { return $this->GenericErrorResponse($response, 'Object not found', 400); } $row->update($requestBody); - $success = $row->isClean(); return $this->EmptyApiResponse($response); - } - catch (\Exception $ex) - { + } catch (\Exception $ex) { return $this->GenericErrorResponse($response, $ex->getMessage()); } - } - else - { + } else { return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed'); } } public function GetObject(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoListing($args['entity'])) - { - $userfields = $this->getUserfieldsService()->GetValues($args['entity'], $args['objectId']); - if (count($userfields) === 0) - { - $userfields = null; - } - + if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoListing($args['entity'])) { $object = $this->getDatabase()->{$args['entity']}($args['objectId']); - if ($object == null) - { + if ($object == null) { return $this->GenericErrorResponse($response, 'Object not found', 404); } - $object['userfields'] = $userfields; + $this->addUserfieldsAndJoinsToRow($object, $args); return $this->ApiResponse($response, $object); - } - else - { + } else { return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed'); } } public function GetObjects(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if (!$this->IsValidExposedEntity($args['entity']) || $this->IsEntityWithNoListing($args['entity'])) - { + if (!$this->IsValidExposedEntity($args['entity']) || $this->IsEntityWithNoListing($args['entity'])) { return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed'); } - $objects = $this->queryData($this->getDatabase()->{$args['entity']}(), $request->getQueryParams()); - $userfields = $this->getUserfieldsService()->GetFields($args['entity']); + $query = $request->getQueryParams(); - if (count($userfields) > 0) - { - $allUserfieldValues = $this->getUserfieldsService()->GetAllValues($args['entity']); + // get result and total row count + $objects = $this->getDatabase()->{$args['entity']}(); + $response = $response->withHeader('x-rowcount-total', $objects->count()); - foreach ($objects as $object) - { - $userfieldKeyValuePairs = null; - foreach ($userfields as $userfield) - { - $value = FindObjectInArrayByPropertyValue(FindAllObjectsInArrayByPropertyValue($allUserfieldValues, 'object_id', $object->id), 'name', $userfield->name); - if ($value) - { - $userfieldKeyValuePairs[$userfield->name] = $value->value; - } - else - { - $userfieldKeyValuePairs[$userfield->name] = null; - } - } + // apply filter, get filtered row count + $objects = $this->applyQuery($objects, $query); + $response = $response->withHeader('x-rowcount-filtered', $objects->count()); - $object->userfields = $userfieldKeyValuePairs; - } + // apply limit/order + $objects = $this->applyLimit($objects, $query); + $objects = $this->applyOrder($objects, $query); + + // add entity-specific queries + if ($args['entity'] === 'products' && isset($query['only_in_stock'])) { + $objects = $objects->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)'); + } + + // add userfields and joins to objects + foreach ($objects as $object) { + $this->addUserfieldsAndJoinsToRow($object, $args); } return $this->ApiResponse($response, $objects); @@ -181,12 +142,9 @@ class GenericEntityApiController extends BaseApiController public function GetUserfields(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - try - { + try { return $this->ApiResponse($response, $this->getUserfieldsService()->GetValues($args['entity'], $args['objectId'])); - } - catch (\Exception $ex) - { + } catch (\Exception $ex) { return $this->GenericErrorResponse($response, $ex->getMessage()); } } @@ -197,22 +155,40 @@ class GenericEntityApiController extends BaseApiController $requestBody = $this->GetParsedAndFilteredRequestBody($request); - try - { - if ($requestBody === null) - { + try { + if ($requestBody === null) { throw new \Exception('Request body could not be parsed (probably invalid JSON format or missing/wrong Content-Type header)'); } $this->getUserfieldsService()->SetValues($args['entity'], $args['objectId'], $requestBody); return $this->EmptyApiResponse($response); - } - catch (\Exception $ex) - { + } catch (\Exception $ex) { return $this->GenericErrorResponse($response, $ex->getMessage()); } } + private function addUserfieldsAndJoinsToRow(Row $object, array $args) + { + // add userfields + $userfields = $this->getUserfieldsService()->GetValues($args['entity'], $object->id); + if (count($userfields) === 0) { + $userfields = null; + } + $object->userfields = $userfields; + + // add entity-specific joins + if ($args['entity'] === 'products') { + $object->product_group = $object->product_group_id !== null ? $this->getDatabase()->product_groups($object->product_group_id) : null; + $object->location = $object->location_id !== null ? $this->getDatabase()->locations($object->location_id) : null; + $object->shopping_location = $object->shopping_location_id !== null ? $this->getDatabase()->shopping_locations($object->shopping_location_id) : null; + $object->qu_purchase = $object->qu_id_purchase !== null ? $this->getDatabase()->quantity_units($object->qu_id_purchase) : null; + $object->qu_stock = $object->qu_id_stock !== null ? $this->getDatabase()->quantity_units($object->qu_id_stock) : null; + $object->parent_product = $object->parent_product_id !== null ? $this->getDatabase()->products($object->parent_product_id) : null; + } + + return $object; + } + private function IsEntityWithEditRequiresAdmin($entity) { return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntityEditRequiresAdmin->enum); diff --git a/controllers/RecipesController.php b/controllers/RecipesController.php index 8c6df6c1..e59e6c25 100644 --- a/controllers/RecipesController.php +++ b/controllers/RecipesController.php @@ -12,14 +12,12 @@ class RecipesController extends BaseController public function MealPlan(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { $start = date('Y-m-d'); - if (isset($request->getQueryParams()['start']) && IsIsoDate($request->getQueryParams()['start'])) - { + if (isset($request->getQueryParams()['start']) && IsIsoDate($request->getQueryParams()['start'])) { $start = $request->getQueryParams()['start']; } $days = 6; - if (isset($request->getQueryParams()['days']) && filter_var($request->getQueryParams()['days'], FILTER_VALIDATE_INT) !== false) - { + if (isset($request->getQueryParams()['days']) && filter_var($request->getQueryParams()['days'], FILTER_VALIDATE_INT) !== false) { $days = $request->getQueryParams()['days']; } @@ -27,19 +25,16 @@ class RecipesController extends BaseController $recipes = $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll(); $events = []; - foreach ($this->getDatabase()->meal_plan()->where($mealPlanWhereTimespan) as $mealPlanEntry) - { + foreach ($this->getDatabase()->meal_plan()->where($mealPlanWhereTimespan) as $mealPlanEntry) { $recipe = FindObjectInArrayByPropertyValue($recipes, 'id', $mealPlanEntry['recipe_id']); $title = ''; - if ($recipe !== null) - { + if ($recipe !== null) { $title = $recipe->name; } $productDetails = null; - if ($mealPlanEntry['product_id'] !== null) - { + if ($mealPlanEntry['product_id'] !== null) { $productDetails = $this->getStockService()->GetProductDetails($mealPlanEntry['product_id']); } @@ -60,7 +55,6 @@ class RecipesController extends BaseController 'recipes' => $recipes, 'internalRecipes' => $this->getDatabase()->recipes()->where("id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan)")->fetchAll(), 'recipesResolved' => $this->getRecipesService()->GetRecipesResolved("recipe_id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan)"), - 'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(), 'mealplanSections' => $this->getDatabase()->meal_plan_sections()->orderBy('sort_number'), @@ -74,14 +68,10 @@ class RecipesController extends BaseController $recipesResolved = $this->getRecipesService()->GetRecipesResolved('recipe_id > 0'); $selectedRecipe = null; - if (isset($request->getQueryParams()['recipe'])) - { + if (isset($request->getQueryParams()['recipe'])) { $selectedRecipe = $this->getDatabase()->recipes($request->getQueryParams()['recipe']); - } - else - { - foreach ($recipes as $recipe) - { + } else { + foreach ($recipes as $recipe) { $selectedRecipe = $recipe; break; } @@ -89,8 +79,7 @@ class RecipesController extends BaseController $totalCosts = null; $totalCalories = null; - if ($selectedRecipe) - { + if ($selectedRecipe) { $totalCosts = FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->costs; $totalCalories = FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->calories; } @@ -109,27 +98,22 @@ class RecipesController extends BaseController 'selectedRecipeTotalCalories' => $totalCalories ]; - if ($selectedRecipe) - { + if ($selectedRecipe) { $selectedRecipeSubRecipes = $this->getDatabase()->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', 'COLLATE NOCASE')->fetchAll(); $includedRecipeIdsAbsolute = []; $includedRecipeIdsAbsolute[] = $selectedRecipe->id; - foreach ($selectedRecipeSubRecipes as $subRecipe) - { + foreach ($selectedRecipeSubRecipes as $subRecipe) { $includedRecipeIdsAbsolute[] = $subRecipe->id; } // TODO: Why not directly use recipes_pos_resolved for all recipe positions here (parent and child)? // This view already correctly recolves child recipe amounts... $allRecipePositions = []; - foreach ($includedRecipeIdsAbsolute as $id) - { + foreach ($includedRecipeIdsAbsolute as $id) { $allRecipePositions[$id] = $this->getDatabase()->recipes_pos_resolved()->where('recipe_id = :1 AND is_nested_recipe_pos = 0', $id)->orderBy('ingredient_group', 'ASC', 'product_group', 'ASC'); - foreach ($allRecipePositions[$id] as $pos) - { - if ($id != $selectedRecipe->id) - { + foreach ($allRecipePositions[$id] as $pos) { + if ($id != $selectedRecipe->id) { $pos2 = $this->getDatabase()->recipes_pos_resolved()->where('recipe_id = :1 AND recipe_pos_id = :2 AND is_nested_recipe_pos = 1', $selectedRecipe->id, $pos->recipe_pos_id)->fetch(); $pos->recipe_amount = $pos2->recipe_amount; $pos->missing_amount = $pos2->missing_amount; @@ -153,6 +137,7 @@ class RecipesController extends BaseController 'recipe' => $this->getDatabase()->recipes($recipeId), 'recipePositions' => $this->getDatabase()->recipes_pos()->where('recipe_id', $recipeId), 'mode' => $recipeId == 'new' ? 'create' : 'edit', + // TODO: remove 'products' after converting DataTable 'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'), 'quantityunits' => $this->getDatabase()->quantity_units(), 'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'), @@ -164,24 +149,21 @@ class RecipesController extends BaseController public function RecipePosEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['recipePosId'] == 'new') - { + if ($args['recipePosId'] == 'new') { return $this->renderPage($response, 'recipeposform', [ 'mode' => 'create', 'recipe' => $this->getDatabase()->recipes($args['recipeId']), 'recipePos' => new \stdClass(), - 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'), + 'recipePosId' => $args['recipePosId'], 'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved() ]); - } - else - { + } else { return $this->renderPage($response, 'recipeposform', [ 'mode' => 'edit', 'recipe' => $this->getDatabase()->recipes($args['recipeId']), 'recipePos' => $this->getDatabase()->recipes_pos($args['recipePosId']), - 'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'), + 'recipePosId' => $args['recipePosId'], 'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved() ]); @@ -195,14 +177,11 @@ class RecipesController extends BaseController public function MealPlanSectionEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['sectionId'] == 'new') - { + if ($args['sectionId'] == 'new') { return $this->renderPage($response, 'mealplansectionform', [ 'mode' => 'create' ]); - } - else - { + } else { return $this->renderPage($response, 'mealplansectionform', [ 'mealplanSection' => $this->getDatabase()->meal_plan_sections($args['sectionId']), 'mode' => 'edit' diff --git a/controllers/StockController.php b/controllers/StockController.php index 7de604fe..ab0bdd05 100644 --- a/controllers/StockController.php +++ b/controllers/StockController.php @@ -12,8 +12,6 @@ class StockController extends BaseController public function Consume(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { return $this->renderPage($response, 'consume', [ - 'products' => $this->getDatabase()->products()->where('active = 1')->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)')->orderBy('name'), - 'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(), 'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'), 'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), @@ -24,8 +22,6 @@ class StockController extends BaseController public function Inventory(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { return $this->renderPage($response, 'inventory', [ - 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'), - 'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(), 'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'), 'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), @@ -35,19 +31,15 @@ class StockController extends BaseController public function Journal(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if (isset($request->getQueryParams()['months']) && filter_var($request->getQueryParams()['months'], FILTER_VALIDATE_INT) !== false) - { + if (isset($request->getQueryParams()['months']) && filter_var($request->getQueryParams()['months'], FILTER_VALIDATE_INT) !== false) { $months = $request->getQueryParams()['months']; $where = "row_created_timestamp > DATE(DATE('now', 'localtime'), '-$months months')"; - } - else - { + } else { // Default 6 months $where = "row_created_timestamp > DATE(DATE('now', 'localtime'), '-6 months')"; } - if (isset($request->getQueryParams()['product']) && filter_var($request->getQueryParams()['product'], FILTER_VALIDATE_INT) !== false) - { + if (isset($request->getQueryParams()['product']) && filter_var($request->getQueryParams()['product'], FILTER_VALIDATE_INT) !== false) { $productId = $request->getQueryParams()['product']; $where .= " AND product_id = $productId"; } @@ -56,7 +48,6 @@ class StockController extends BaseController return $this->renderPage($response, 'stockjournal', [ 'stockLog' => $this->getDatabase()->uihelper_stock_journal()->where($where)->orderBy('row_created_timestamp', 'DESC'), - 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'), 'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'), 'users' => $usersService->GetUsersAsDto(), 'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_') @@ -75,15 +66,12 @@ class StockController extends BaseController public function LocationEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['locationId'] == 'new') - { + if ($args['locationId'] == 'new') { return $this->renderPage($response, 'locationform', [ 'mode' => 'create', 'userfields' => $this->getUserfieldsService()->GetFields('locations') ]); - } - else - { + } else { return $this->renderPage($response, 'locationform', [ 'location' => $this->getDatabase()->locations($args['locationId']), 'mode' => 'edit', @@ -121,13 +109,11 @@ class StockController extends BaseController { $product = null; - if (isset($request->getQueryParams()['product'])) - { + if (isset($request->getQueryParams()['product'])) { $product = $this->getDatabase()->products($request->getQueryParams()['product']); } - if ($args['productBarcodeId'] == 'new') - { + if ($args['productBarcodeId'] == 'new') { return $this->renderPage($response, 'productbarcodeform', [ 'mode' => 'create', 'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'), @@ -137,9 +123,7 @@ class StockController extends BaseController 'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(), 'userfields' => $this->getUserfieldsService()->GetFields('product_barcodes') ]); - } - else - { + } else { return $this->renderPage($response, 'productbarcodeform', [ 'mode' => 'edit', 'barcode' => $this->getDatabase()->product_barcodes($args['productBarcodeId']), @@ -154,8 +138,7 @@ class StockController extends BaseController public function ProductEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['productId'] == 'new') - { + if ($args['productId'] == 'new') { return $this->renderPage($response, 'productform', [ 'locations' => $this->getDatabase()->locations()->orderBy('name'), 'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'), @@ -163,13 +146,10 @@ class StockController extends BaseController 'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'), 'productgroups' => $this->getDatabase()->product_groups()->orderBy('name', 'COLLATE NOCASE'), 'userfields' => $this->getUserfieldsService()->GetFields('products'), - 'products' => $this->getDatabase()->products()->where('parent_product_id IS NULL and active = 1')->orderBy('name', 'COLLATE NOCASE'), 'isSubProductOfOthers' => false, 'mode' => 'create' ]); - } - else - { + } else { $product = $this->getDatabase()->products($args['productId']); return $this->renderPage($response, 'productform', [ @@ -180,7 +160,6 @@ class StockController extends BaseController 'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'), 'productgroups' => $this->getDatabase()->product_groups()->orderBy('name', 'COLLATE NOCASE'), 'userfields' => $this->getUserfieldsService()->GetFields('products'), - 'products' => $this->getDatabase()->products()->where('id != :1 AND parent_product_id IS NULL and active = 1', $product->id)->orderBy('name', 'COLLATE NOCASE'), 'isSubProductOfOthers' => $this->getDatabase()->products()->where('parent_product_id = :1', $product->id)->count() !== 0, 'mode' => 'edit', 'quConversions' => $this->getDatabase()->quantity_unit_conversions(), @@ -198,15 +177,12 @@ class StockController extends BaseController public function ProductGroupEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['productGroupId'] == 'new') - { + if ($args['productGroupId'] == 'new') { return $this->renderPage($response, 'productgroupform', [ 'mode' => 'create', 'userfields' => $this->getUserfieldsService()->GetFields('product_groups') ]); - } - else - { + } else { return $this->renderPage($response, 'productgroupform', [ 'group' => $this->getDatabase()->product_groups($args['productGroupId']), 'mode' => 'edit', @@ -227,21 +203,21 @@ class StockController extends BaseController public function ProductsList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - $products = $this->getDatabase()->products(); - if (!isset($request->getQueryParams()['include_disabled'])) - { - $products = $products->where('active = 1'); - } + // $products = $this->getDatabase()->products(); + // if (!isset($request->getQueryParams()['include_disabled'])) + // { + // $products = $products->where('active = 1'); + // } - if (isset($request->getQueryParams()['only_in_stock'])) - { - $products = $products->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)'); - } + // if (isset($request->getQueryParams()['only_in_stock'])) + // { + // $products = $products->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)'); + // } - $products = $products->orderBy('name', 'COLLATE NOCASE'); + // $products = $products->orderBy('name', 'COLLATE NOCASE'); return $this->renderPage($response, 'products', [ - 'products' => $products, + // 'products' => $products, 'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'), 'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), 'productGroups' => $this->getDatabase()->product_groups()->orderBy('name', 'COLLATE NOCASE'), @@ -254,8 +230,6 @@ class StockController extends BaseController public function Purchase(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { return $this->renderPage($response, 'purchase', [ - 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'), - 'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(), 'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'), 'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), @@ -267,20 +241,17 @@ class StockController extends BaseController { $product = null; - if (isset($request->getQueryParams()['product'])) - { + if (isset($request->getQueryParams()['product'])) { $product = $this->getDatabase()->products($request->getQueryParams()['product']); } $defaultQuUnit = null; - if (isset($request->getQueryParams()['qu-unit'])) - { + if (isset($request->getQueryParams()['qu-unit'])) { $defaultQuUnit = $this->getDatabase()->quantity_units($request->getQueryParams()['qu-unit']); } - if ($args['quConversionId'] == 'new') - { + if ($args['quConversionId'] == 'new') { return $this->renderPage($response, 'quantityunitconversionform', [ 'mode' => 'create', 'userfields' => $this->getUserfieldsService()->GetFields('quantity_unit_conversions'), @@ -288,9 +259,7 @@ class StockController extends BaseController 'product' => $product, 'defaultQuUnit' => $defaultQuUnit ]); - } - else - { + } else { return $this->renderPage($response, 'quantityunitconversionform', [ 'quConversion' => $this->getDatabase()->quantity_unit_conversions($args['quConversionId']), 'mode' => 'edit', @@ -304,17 +273,14 @@ class StockController extends BaseController public function QuantityUnitEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['quantityunitId'] == 'new') - { + if ($args['quantityunitId'] == 'new') { return $this->renderPage($response, 'quantityunitform', [ 'mode' => 'create', 'userfields' => $this->getUserfieldsService()->GetFields('quantity_units'), 'pluralCount' => $this->getLocalizationService()->GetPluralCount(), 'pluralRule' => $this->getLocalizationService()->GetPluralDefinition() ]); - } - else - { + } else { $quantityUnit = $this->getDatabase()->quantity_units($args['quantityunitId']); return $this->renderPage($response, 'quantityunitform', [ @@ -349,8 +315,7 @@ class StockController extends BaseController { $listId = 1; - if (isset($request->getQueryParams()['list'])) - { + if (isset($request->getQueryParams()['list'])) { $listId = $request->getQueryParams()['list']; } @@ -371,15 +336,12 @@ class StockController extends BaseController public function ShoppingListEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['listId'] == 'new') - { + if ($args['listId'] == 'new') { return $this->renderPage($response, 'shoppinglistform', [ 'mode' => 'create', 'userfields' => $this->getUserfieldsService()->GetFields('shopping_lists') ]); - } - else - { + } else { return $this->renderPage($response, 'shoppinglistform', [ 'shoppingList' => $this->getDatabase()->shopping_lists($args['listId']), 'mode' => 'edit', @@ -390,8 +352,7 @@ class StockController extends BaseController public function ShoppingListItemEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['itemId'] == 'new') - { + if ($args['itemId'] == 'new') { return $this->renderPage($response, 'shoppinglistitemform', [ 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'), 'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name', 'COLLATE NOCASE'), @@ -400,12 +361,9 @@ class StockController extends BaseController 'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(), 'userfields' => $this->getUserfieldsService()->GetFields('shopping_list') ]); - } - else - { + } else { return $this->renderPage($response, 'shoppinglistitemform', [ 'listItem' => $this->getDatabase()->shopping_list($args['itemId']), - 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'), 'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name', 'COLLATE NOCASE'), 'mode' => 'edit', 'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), @@ -422,15 +380,12 @@ class StockController extends BaseController public function ShoppingLocationEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - if ($args['shoppingLocationId'] == 'new') - { + if ($args['shoppingLocationId'] == 'new') { return $this->renderPage($response, 'shoppinglocationform', [ 'mode' => 'create', 'userfields' => $this->getUserfieldsService()->GetFields('shopping_locations') ]); - } - else - { + } else { return $this->renderPage($response, 'shoppinglocationform', [ 'shoppinglocation' => $this->getDatabase()->shopping_locations($args['shoppingLocationId']), 'mode' => 'edit', @@ -489,6 +444,7 @@ class StockController extends BaseController $nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_due_soon_days']; return $this->renderPage($response, 'stockentries', [ + // TODO: remove 'products' after converting DataTable 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'), 'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), 'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'), @@ -504,8 +460,6 @@ class StockController extends BaseController public function Transfer(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { return $this->renderPage($response, 'transfer', [ - 'products' => $this->getDatabase()->products()->where('active = 1')->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)')->orderBy('name', 'COLLATE NOCASE'), - 'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(), 'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'), 'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved() @@ -515,23 +469,19 @@ class StockController extends BaseController public function JournalSummary(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { $entries = $this->getDatabase()->uihelper_stock_journal_summary(); - if (isset($request->getQueryParams()['product_id'])) - { + if (isset($request->getQueryParams()['product_id'])) { $entries = $entries->where('product_id', $request->getQueryParams()['product_id']); } - if (isset($request->getQueryParams()['user_id'])) - { + if (isset($request->getQueryParams()['user_id'])) { $entries = $entries->where('user_id', $request->getQueryParams()['user_id']); } - if (isset($request->getQueryParams()['transaction_type'])) - { + if (isset($request->getQueryParams()['transaction_type'])) { $entries = $entries->where('transaction_type', $request->getQueryParams()['transaction_type']); } $usersService = $this->getUsersService(); return $this->renderPage($response, 'stockjournalsummary', [ 'entries' => $entries, - 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'), 'users' => $usersService->GetUsersAsDto(), 'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_') ]); diff --git a/localization/strings.pot b/localization/strings.pot index f90e7b8e..acc3682a 100644 --- a/localization/strings.pot +++ b/localization/strings.pot @@ -2308,3 +2308,18 @@ msgstr "" msgid "Average execution frequency" msgstr "" + +msgid "Pakke" +msgstr "" + +msgid "Del" +msgstr "" + +msgid "Boks" +msgstr "" + +msgid "Bunt" +msgstr "" + +msgid "Flaske" +msgstr "" diff --git a/package.json b/package.json index faa38e88..b8b47553 100644 --- a/package.json +++ b/package.json @@ -12,15 +12,15 @@ "bootstrap-select": "^1.13.18", "bwip-js": "^3.0.1", "chart.js": "^2.8.0", - "datatables.net": "^1.10.22", - "datatables.net-bs4": "^1.10.22", - "datatables.net-colreorder": "^1.5.2", - "datatables.net-colreorder-bs4": "^1.5.2", - "datatables.net-plugins": "^1.10.20", - "datatables.net-rowgroup": "^1.1.2", - "datatables.net-rowgroup-bs4": "^1.1.2", - "datatables.net-select": "^1.3.1", - "datatables.net-select-bs4": "^1.3.1", + "datatables.net": "^1.11.5", + "datatables.net-bs4": "^1.11.5", + "datatables.net-colreorder": "^1.5.5", + "datatables.net-colreorder-bs4": "^1.5.5", + "datatables.net-plugins": "^1.11.5", + "datatables.net-rowgroup": "^1.1.4", + "datatables.net-rowgroup-bs4": "^1.1.4", + "datatables.net-select": "^1.3.4", + "datatables.net-select-bs4": "^1.3.4", "fullcalendar": "^3.10.1", "gettext-translator": "2.1.0", "jquery": "3.5.1", @@ -28,6 +28,8 @@ "jquery-serializejson": "^2.9.0", "moment": "^2.27.0", "nosleep.js": "^0.12.0", + "select2": "^4.0.13", + "select2-theme-bootstrap4": "^1.0.1", "sprintf-js": "^1.1.2", "startbootstrap-sb-admin": "4.0.0", "summernote": "^0.8.18", diff --git a/public/css/grocy.css b/public/css/grocy.css index a68fc2b8..2e6707bf 100755 --- a/public/css/grocy.css +++ b/public/css/grocy.css @@ -94,10 +94,10 @@ body.fullscreen-card { margin: 0 auto; } -.form-check-input.is-valid ~ .form-check-label, -.was-validated .form-check-input:valid ~ .form-check-label, -.custom-control-input.is-valid ~ .custom-control-label, -.was-validated .custom-control-input:valid ~ .custom-control-label { +.form-check-input.is-valid~.form-check-label, +.was-validated .form-check-input:valid~.form-check-label, +.custom-control-input.is-valid~.custom-control-label, +.was-validated .custom-control-input:valid~.custom-control-label { color: inherit; } @@ -192,20 +192,20 @@ form.has-sticky-form-footer .form-group:nth-last-child(2) { border-color: #d6d6d6 !important; } -.navbar-sidenav > li, -.sidenav-second-level > li { +.navbar-sidenav>li, +.sidenav-second-level>li { transition: all 0.3s !important; } -.navbar-sidenav > li:hover, -.sidenav-second-level > li:hover, +.navbar-sidenav>li:hover, +.sidenav-second-level>li:hover, .navbar-nav .dropdown-item:hover { box-shadow: inset 5px 0 0 #337ab7 !important; background-color: #d6d6d6 !important; } -.navbar-sidenav > li > a:focus, -.sidenav-second-level > li > a:focus, +.navbar-sidenav>li>a:focus, +.sidenav-second-level>li>a:focus, .navbar-nav .dropdown-item:focus { box-shadow: inset 5px 0 0 #ab2230 !important; background-color: #d6d6d6 !important; @@ -228,7 +228,8 @@ form.has-sticky-form-footer .form-group:nth-last-child(2) { cursor: wait; } -.expandable-text .collapse, .module .collapsing { +.expandable-text .collapse, +.module .collapsing { height: 2.4rem; } @@ -255,7 +256,8 @@ form.has-sticky-form-footer .form-group:nth-last-child(2) { .table-inline-menu.dropdown-menu { padding-left: 12px; padding-right: 12px; - width: 96vw; /* Set width of popup menu to screen size */ + width: 96vw; + /* Set width of popup menu to screen size */ } a:not([href]) { @@ -326,12 +328,39 @@ a:not([href]) { background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px; } +.select2-hidden-accessible.custom-select.is-invalid+.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection, +.was-validated .select2-hidden-accessible.custom-select:invalid+.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection { + border-color: #dc3545; +} + +.select2-hidden-accessible.custom-select.is-invalid+.select2-container--focus.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection, +.was-validated .select2-hidden-accessible.custom-select:invalid+.select2-container--focus.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection, +.select2-hidden-accessible.custom-select.is-invalid+.select2-container--open.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection, +.was-validated .select2-hidden-accessible.custom-select:invalid+.select2-container--open.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgb(220 53 69 / 25%); +} + +.select2-hidden-accessible.custom-select.is-valid+.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection, +.was-validated .select2-hidden-accessible.custom-select:valid+.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection { + border-color: #28a745; +} + +.select2-hidden-accessible.custom-select.is-valid+.select2-container--focus.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection, +.was-validated .select2-hidden-accessible.custom-select:valid+.select2-container--focus.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection, +.select2-hidden-accessible.custom-select.is-valid+.select2-container--open.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection, +.was-validated .select2-hidden-accessible.custom-select:valid+.select2-container--open.select2-container--bootstrap:not(:last-child)>.selection>.select2-selection { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgb(40 167 69 / 25%); +} + /* There is a little too much padding on form inputs */ .form-control { padding-right: 0.75rem !important; } -.btn-group-xs > .btn, .btn-xs { +.btn-group-xs>.btn, +.btn-xs { padding: 0.25rem 0.4rem; font-size: 0.875rem; line-height: 0.5; @@ -346,7 +375,7 @@ a:not([href]) { font-size: 125%; } -.input-group > .form-control:focus { +.input-group>.form-control:focus { z-index: inherit; } @@ -384,7 +413,7 @@ tr.dtrg-group { } /* Third party component customizations - toastr */ -#toast-container > div { +#toast-container>div { opacity: 1; filter: alpha(opacity=100); } @@ -397,7 +426,7 @@ tr.dtrg-group { background-color: #dc3545; } -#toast-container > div { +#toast-container>div { box-shadow: none; } @@ -408,19 +437,19 @@ tr.dtrg-group { } /* Third party component customizations - SB Admin 2 */ -#mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link:after, +#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link:after, #mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse:after { font-family: 'Font Awesome 5 Free'; font-weight: 900; } -#mainNav .navbar-collapse .navbar-nav > .nav-item.dropdown > .nav-link.py-0:after, +#mainNav .navbar-collapse .navbar-nav>.nav-item.dropdown>.nav-link.py-0:after, #mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse.py-0:after { padding-top: 8px; } -#mainNav .navbar-collapse .navbar-sidenav > .nav-item > .nav-link, -#mainNav .navbar-collapse .navbar-sidenav > .nav-item .sidenav-second-level > li > a { +#mainNav .navbar-collapse .navbar-sidenav>.nav-item>.nav-link, +#mainNav .navbar-collapse .navbar-sidenav>.nav-item .sidenav-second-level>li>a { padding: 0.75em; } @@ -460,7 +489,7 @@ html { margin-left: -0.15em !important; } -#mainNav .navbar-collapse .navbar-sidenav > .nav-item > .nav-link { +#mainNav .navbar-collapse .navbar-sidenav>.nav-item>.nav-link { padding-right: 1.25em !important; } @@ -603,7 +632,7 @@ canvas.drawingBuffer { margin-bottom: -.65rem; } -.grocy-tabs.tab-content > .active { +.grocy-tabs.tab-content>.active { display: flex; flex-direction: column; } @@ -615,7 +644,7 @@ canvas.drawingBuffer { } @media print { - .grocy-tabs.print.tab-content > .tab-pane { + .grocy-tabs.print.tab-content>.tab-pane { display: flex !important; flex-direction: column !important; opacity: 1 !important; @@ -625,7 +654,7 @@ canvas.drawingBuffer { height: auto !important; } - .grocy-tabs.break > .tab-pane { + .grocy-tabs.break>.tab-pane { page-break-after: always; } @@ -656,3 +685,9 @@ canvas.drawingBuffer { pointer-events: none; opacity: 0.5; } + +/* Fix Select2 in .input-group */ +.input-group>.select2-hidden-accessible+.select2-container--bootstrap>.selection>.select2-selection, +.input-group>.select2-hidden-accessible+.select2-container--bootstrap>.selection>.select2-selection.form-control { + width: 100%; +} diff --git a/public/js/grocy.js b/public/js/grocy.js index 70c28d2e..04e66317 100644 --- a/public/js/grocy.js +++ b/public/js/grocy.js @@ -1,31 +1,23 @@ Grocy.Api = {}; -Grocy.Api.Get = function(apiFunction, success, error) -{ +Grocy.Api.Get = function(apiFunction, success, error) { var xhr = new XMLHttpRequest(); var url = U('/api/' + apiFunction); - xhr.onreadystatechange = function() - { - if (xhr.readyState === XMLHttpRequest.DONE) - { - if (xhr.status === 200 || xhr.status === 204) - { - if (success) - { - if (xhr.status === 200) - { - success(JSON.parse(xhr.responseText)); - } - else - { + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status === 200 || xhr.status === 204) { + if (success) { + if (xhr.status === 200) { + success(JSON.parse(xhr.responseText), { + recordsTotal: xhr.getResponseHeader('x-rowcount-total'), + recordsFiltered: xhr.getResponseHeader('x-rowcount-filtered'), + }); + } else { success({}); } } - } - else - { - if (error) - { + } else { + if (error) { error(xhr); } } @@ -34,35 +26,26 @@ Grocy.Api.Get = function(apiFunction, success, error) xhr.open('GET', url, true); xhr.send(); + + return xhr; }; -Grocy.Api.Post = function(apiFunction, jsonData, success, error) -{ +Grocy.Api.Post = function(apiFunction, jsonData, success, error) { var xhr = new XMLHttpRequest(); var url = U('/api/' + apiFunction); - xhr.onreadystatechange = function() - { - if (xhr.readyState === XMLHttpRequest.DONE) - { - if (xhr.status === 200 || xhr.status === 204) - { - if (success) - { - if (xhr.status === 200) - { + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status === 200 || xhr.status === 204) { + if (success) { + if (xhr.status === 200) { success(JSON.parse(xhr.responseText)); - } - else - { + } else { success({}); } } - } - else - { - if (error) - { + } else { + if (error) { error(xhr); } } @@ -72,35 +55,26 @@ Grocy.Api.Post = function(apiFunction, jsonData, success, error) xhr.open('POST', url, true); xhr.setRequestHeader('Content-type', 'application/json'); xhr.send(JSON.stringify(jsonData)); + + return xhr; }; -Grocy.Api.Put = function(apiFunction, jsonData, success, error) -{ +Grocy.Api.Put = function(apiFunction, jsonData, success, error) { var xhr = new XMLHttpRequest(); var url = U('/api/' + apiFunction); - xhr.onreadystatechange = function() - { - if (xhr.readyState === XMLHttpRequest.DONE) - { - if (xhr.status === 200 || xhr.status === 204) - { - if (success) - { - if (xhr.status === 200) - { + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status === 200 || xhr.status === 204) { + if (success) { + if (xhr.status === 200) { success(JSON.parse(xhr.responseText)); - } - else - { + } else { success({}); } } - } - else - { - if (error) - { + } else { + if (error) { error(xhr); } } @@ -110,35 +84,26 @@ Grocy.Api.Put = function(apiFunction, jsonData, success, error) xhr.open('PUT', url, true); xhr.setRequestHeader('Content-type', 'application/json'); xhr.send(JSON.stringify(jsonData)); + + return xhr; }; -Grocy.Api.Delete = function(apiFunction, jsonData, success, error) -{ +Grocy.Api.Delete = function(apiFunction, jsonData, success, error) { var xhr = new XMLHttpRequest(); var url = U('/api/' + apiFunction); - xhr.onreadystatechange = function() - { - if (xhr.readyState === XMLHttpRequest.DONE) - { - if (xhr.status === 200 || xhr.status === 204) - { - if (success) - { - if (xhr.status === 200) - { + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status === 200 || xhr.status === 204) { + if (success) { + if (xhr.status === 200) { success(JSON.parse(xhr.responseText)); - } - else - { + } else { success({}); } } - } - else - { - if (error) - { + } else { + if (error) { error(xhr); } } @@ -148,35 +113,26 @@ Grocy.Api.Delete = function(apiFunction, jsonData, success, error) xhr.open('DELETE', url, true); xhr.setRequestHeader('Content-type', 'application/json'); xhr.send(JSON.stringify(jsonData)); + + return xhr; }; -Grocy.Api.UploadFile = function(file, group, fileName, success, error) -{ +Grocy.Api.UploadFile = function(file, group, fileName, success, error) { var xhr = new XMLHttpRequest(); var url = U('/api/files/' + group + '/' + btoa(fileName)); - xhr.onreadystatechange = function() - { - if (xhr.readyState === XMLHttpRequest.DONE) - { - if (xhr.status === 200 || xhr.status === 204) - { - if (success) - { - if (xhr.status === 200) - { + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status === 200 || xhr.status === 204) { + if (success) { + if (xhr.status === 200) { success(JSON.parse(xhr.responseText)); - } - else - { + } else { success({}); } } - } - else - { - if (error) - { + } else { + if (error) { error(xhr); } } @@ -186,35 +142,26 @@ Grocy.Api.UploadFile = function(file, group, fileName, success, error) xhr.open('PUT', url, true); xhr.setRequestHeader('Content-type', 'application/octet-stream'); xhr.send(file); + + return xhr; }; -Grocy.Api.DeleteFile = function(fileName, group, success, error) -{ +Grocy.Api.DeleteFile = function(fileName, group, success, error) { var xhr = new XMLHttpRequest(); var url = U('/api/files/' + group + '/' + btoa(fileName)); - xhr.onreadystatechange = function() - { - if (xhr.readyState === XMLHttpRequest.DONE) - { - if (xhr.status === 200 || xhr.status === 204) - { - if (success) - { - if (xhr.status === 200) - { + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status === 200 || xhr.status === 204) { + if (success) { + if (xhr.status === 200) { success(JSON.parse(xhr.responseText)); - } - else - { + } else { success({}); } } - } - else - { - if (error) - { + } else { + if (error) { error(xhr); } } @@ -224,93 +171,75 @@ Grocy.Api.DeleteFile = function(fileName, group, success, error) xhr.open('DELETE', url, true); xhr.setRequestHeader('Content-type', 'application/json'); xhr.send(); + + return xhr; }; -U = function(relativePath) -{ +U = function(relativePath) { return Grocy.BaseUrl.replace(/\/$/, '') + relativePath; } Grocy.Translator = new Translator(Grocy.LocalizationStrings); Grocy.TranslatorQu = new Translator(Grocy.LocalizationStringsQu); -__t = function(text, ...placeholderValues) -{ - if (Grocy.Mode === "dev") - { +__t = function(text, ...placeholderValues) { + if (Grocy.Mode === "dev") { var text2 = text; - if (Grocy.LocalizationStrings && !Grocy.LocalizationStrings.messages[""].hasOwnProperty(text2)) - { - Grocy.Api.Post('system/log-missing-localization', { "text": text2 }); + if (Grocy.LocalizationStrings && !Grocy.LocalizationStrings.messages[""].hasOwnProperty(text2)) { + Grocy.Api.Post('system/log-missing-localization', { + "text": text2 + }); } } return Grocy.Translator.__(text, ...placeholderValues) } -__n = function(number, singularForm, pluralForm, isQu = false) -{ - if (Grocy.Mode === "dev") - { +__n = function(number, singularForm, pluralForm, isQu = false) { + if (Grocy.Mode === "dev") { var singularForm2 = singularForm; - if (Grocy.LocalizationStrings && !Grocy.LocalizationStrings.messages[""].hasOwnProperty(singularForm2)) - { - Grocy.Api.Post('system/log-missing-localization', { "text": singularForm2 }); + if (Grocy.LocalizationStrings && !Grocy.LocalizationStrings.messages[""].hasOwnProperty(singularForm2)) { + Grocy.Api.Post('system/log-missing-localization', { + "text": singularForm2 + }); } } - if (isQu) - { + if (isQu) { return Grocy.TranslatorQu.n__(singularForm, pluralForm, Math.abs(number), Math.abs(number)) - } - else - { + } else { return Grocy.Translator.n__(singularForm, pluralForm, Math.abs(number), Math.abs(number)) } } -if (!Grocy.ActiveNav.isEmpty()) -{ +if (!Grocy.ActiveNav.isEmpty()) { var menuItem = $('#sidebarResponsive').find("[data-nav-for-page='" + Grocy.ActiveNav + "']"); menuItem.addClass('active-page'); - if (menuItem.length) - { + if (menuItem.length) { var parentMenuSelector = menuItem.data("sub-menu-of"); - if (typeof parentMenuSelector !== "undefined") - { + if (typeof parentMenuSelector !== "undefined") { $(parentMenuSelector).collapse("show"); $(parentMenuSelector).prev(".nav-link-collapse").addClass("active-page"); - $(parentMenuSelector).on("shown.bs.collapse", function(e) - { - if (!menuItem.isVisibleInViewport(75)) - { + $(parentMenuSelector).on("shown.bs.collapse", function(e) { + if (!menuItem.isVisibleInViewport(75)) { menuItem[0].scrollIntoView(); } }) - } - else - { - if (!menuItem.isVisibleInViewport(75)) - { + } else { + if (!menuItem.isVisibleInViewport(75)) { menuItem[0].scrollIntoView(); } } } } -var observer = new MutationObserver(function(mutations) -{ - mutations.forEach(function(mutation) - { - if (mutation.attributeName === "class") - { +var observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.attributeName === "class") { var attributeValue = $(mutation.target).prop(mutation.attributeName); - if (attributeValue.contains("sidenav-toggled")) - { + if (attributeValue.contains("sidenav-toggled")) { window.localStorage.setItem("sidebar_state", "collapsed"); - } - else - { + } else { window.localStorage.setItem("sidebar_state", "expanded"); } } @@ -319,27 +248,22 @@ var observer = new MutationObserver(function(mutations) observer.observe(document.body, { attributes: true }); -if (window.localStorage.getItem("sidebar_state") === "collapsed") -{ +if (window.localStorage.getItem("sidebar_state") === "collapsed") { $("#sidenavToggler").click(); } -RefreshContextualTimeago = function(rootSelector = "#page-content") -{ - $(rootSelector + " time.timeago").each(function() - { +RefreshContextualTimeago = function(rootSelector = "#page-content") { + $(rootSelector + " time.timeago").each(function() { var element = $(this); - if (!element.hasAttr("datetime")) - { + if (!element.hasAttr("datetime")) { element.text("") return } var timestamp = element.attr("datetime"); - if (timestamp.isEmpty() || timestamp.length < 10) - { + if (timestamp.isEmpty() || timestamp.length < 10) { element.text("") return } @@ -348,22 +272,16 @@ RefreshContextualTimeago = function(rootSelector = "#page-content") var isToday = timestamp && timestamp.substring(0, 10) == moment().format("YYYY-MM-DD"); var isDateWithoutTime = element.hasClass("timeago-date-only"); - if (isNever) - { + if (isNever) { element.prev().text(__t("Never")); element.text(""); - } - else if (isToday) - { + } else if (isToday) { element.text(__t("Today")); - } - else - { + } else { element.text(moment(timestamp).fromNow()); } - if (isDateWithoutTime) - { + if (isDateWithoutTime) { element.prev().text(element.prev().text().substring(0, 10)); } }); @@ -382,52 +300,41 @@ window.FontAwesomeConfig = { } Grocy.FrontendHelpers = {}; -Grocy.FrontendHelpers.ValidateForm = function(formId) -{ +Grocy.FrontendHelpers.ValidateForm = function(formId) { var form = document.getElementById(formId); - if (form === null || form === undefined) - { + if (form === null || form === undefined) { return; } - if (form.checkValidity() === true) - { + if (form.checkValidity() === true) { $(form).find(':submit').removeClass('disabled'); $(form).find('.keep-disabled').addClass('disabled'); - } - else - { + } else { $(form).find(':submit').addClass('disabled'); } $(form).addClass('was-validated'); } -Grocy.FrontendHelpers.BeginUiBusy = function(formId = null) -{ +Grocy.FrontendHelpers.BeginUiBusy = function(formId = null) { $("body").addClass("cursor-busy"); - if (formId !== null) - { + if (formId !== null) { $("#" + formId + " :input").attr("disabled", true); } } -Grocy.FrontendHelpers.EndUiBusy = function(formId = null) -{ +Grocy.FrontendHelpers.EndUiBusy = function(formId = null) { $("body").removeClass("cursor-busy"); - if (formId !== null) - { + if (formId !== null) { $("#" + formId + " :input").attr("disabled", false); } } -Grocy.FrontendHelpers.ShowGenericError = function(message, exception) -{ +Grocy.FrontendHelpers.ShowGenericError = function(message, exception) { toastr.error(__t(message) + '

' + __t('Click to show technical details'), '', { - onclick: function() - { + onclick: function() { bootbox.alert({ title: __t('Error details'), message: '
' + JSON.stringify(exception, null, 4) + '
', @@ -439,10 +346,8 @@ Grocy.FrontendHelpers.ShowGenericError = function(message, exception) console.error(exception); } -Grocy.FrontendHelpers.SaveUserSetting = function(settingsKey, value) -{ - if (Grocy.UserSettings[settingsKey] == value) - { +Grocy.FrontendHelpers.SaveUserSetting = function(settingsKey, value) { + if (Grocy.UserSettings[settingsKey] == value) { return; } @@ -451,89 +356,73 @@ Grocy.FrontendHelpers.SaveUserSetting = function(settingsKey, value) jsonData = {}; jsonData.value = value; Grocy.Api.Put('user/settings/' + settingsKey, jsonData, - function(result) - { + function(result) { // Nothing to do... }, - function(xhr) - { + function(xhr) { console.error(xhr); } ); } -Grocy.FrontendHelpers.DeleteUserSetting = function(settingsKey, reloadPageOnSuccess = false) -{ +Grocy.FrontendHelpers.DeleteUserSetting = function(settingsKey, reloadPageOnSuccess = false) { delete Grocy.UserSettings[settingsKey]; Grocy.Api.Delete('user/settings/' + settingsKey, {}, - function(result) - { - if (reloadPageOnSuccess) - { + function(result) { + if (reloadPageOnSuccess) { location.reload(); } }, - function(xhr) - { - if (!xhr.statusText.isEmpty()) - { + function(xhr) { + if (!xhr.statusText.isEmpty()) { Grocy.FrontendHelpers.ShowGenericError('Error while deleting, please retry', xhr.response) } } ); } -Grocy.FrontendHelpers.RunWebhook = function(webhook, data, repetitions = 1) -{ +Grocy.FrontendHelpers.RunWebhook = function(webhook, data, repetitions = 1) { Object.assign(data, webhook.extra_data); var hasAlreadyFailed = false; - for (i = 0; i < repetitions; i++) - { - $.post(webhook.hook, data).fail(function(req, status, errorThrown) - { - if (!hasAlreadyFailed) - { + for (i = 0; i < repetitions; i++) { + $.post(webhook.hook, data).fail(function(req, status, errorThrown) { + if (!hasAlreadyFailed) { hasAlreadyFailed = true; - Grocy.FrontendHelpers.ShowGenericError(__t("Error while executing WebHook", { "status": status, "errorThrown": errorThrown })); + Grocy.FrontendHelpers.ShowGenericError(__t("Error while executing WebHook", { + "status": status, + "errorThrown": errorThrown + })); } }); } } -$(document).on("keyup paste change", "input, textarea", function() -{ +$(document).on("keyup paste change", "input, textarea", function() { $(this).closest("form").addClass("is-dirty"); }); -$(document).on("click", "select", function() -{ +$(document).on("click", "select", function() { $(this).closest("form").addClass("is-dirty"); }); // Auto saving user setting controls -$(document).on("change", ".user-setting-control", function() -{ +$(document).on("change", ".user-setting-control", function() { var element = $(this); var settingKey = element.attr("data-setting-key"); - if (!element[0].checkValidity()) - { + if (!element[0].checkValidity()) { return; } var inputType = "unknown"; - if (typeof element.attr("type") !== typeof undefined && element.attr("type") !== false) - { + if (typeof element.attr("type") !== typeof undefined && element.attr("type") !== false) { inputType = element.attr("type").toLowerCase(); } - if (inputType === "checkbox") - { + if (inputType === "checkbox") { value = element.is(":checked"); - } - else - { + } else { var value = element.val(); } @@ -541,46 +430,36 @@ $(document).on("change", ".user-setting-control", function() }); // Show file name Bootstrap custom file input -$('input.custom-file-input').on('change', function() -{ +$('input.custom-file-input').on('change', function() { $(this).next('.custom-file-label').html(GetFileNameFromPath($(this).val())); }); // Translation of "Browse"-button of Bootstrap custom file input -if ($(".custom-file-label").length > 0) -{ +if ($(".custom-file-label").length > 0) { $(" @endpush diff --git a/views/components/locationpicker.blade.php b/views/components/locationpicker.blade.php index e83d929e..a48ff170 100644 --- a/views/components/locationpicker.blade.php +++ b/views/components/locationpicker.blade.php @@ -1,37 +1,50 @@ @once -@push('componentScripts') - -@endpush + @push('componentScripts') + + @endpush @endonce -@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp -@php if(empty($prefillById)) { $prefillById = ''; } @endphp -@php if(!isset($isRequired)) { $isRequired = true; } @endphp -@php if(empty($hint)) { $hint = ''; } @endphp -@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp +@php +if (empty($prefillByName)) { + $prefillByName = ''; +} +@endphp +@php +if (empty($prefillById)) { + $prefillById = ''; +} +@endphp +@php +if (!isset($isRequired)) { + $isRequired = true; +} +@endphp +@php +if (empty($hint)) { + $hint = ''; +} +@endphp +@php +if (empty($nextInputSelector)) { + $nextInputSelector = ''; +} +@endphp -
- - -
{{ $__t('You have to select a location') }}
+
+ + {{-- TODO: Select2: dynamic data: locations --}} + +
{{ $__t('You have to select a location') }}
diff --git a/views/components/productpicker.blade.php b/views/components/productpicker.blade.php index a48ff463..e00315b0 100644 --- a/views/components/productpicker.blade.php +++ b/views/components/productpicker.blade.php @@ -1,72 +1,74 @@ @once -@push('componentScripts') - -@endpush + @push('componentScripts') + + @endpush @endonce -@php if(empty($disallowAddProductWorkflows)) { $disallowAddProductWorkflows = false; } @endphp -@php if(empty($disallowAllProductWorkflows)) { $disallowAllProductWorkflows = false; } @endphp -@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp -@php if(empty($prefillById)) { $prefillById = ''; } @endphp -@php if(!isset($isRequired)) { $isRequired = true; } @endphp -@php if(!isset($label)) { $label = 'Product'; } @endphp -@php if(!isset($disabled)) { $disabled = false; } @endphp -@php if(empty($hint)) { $hint = ''; } @endphp -@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp -@php if(empty($validationMessage)) { $validationMessage = 'You have to select a product'; } @endphp +@php +if (empty($disallowAddProductWorkflows)) { + $disallowAddProductWorkflows = false; +} +if (empty($disallowAllProductWorkflows)) { + $disallowAllProductWorkflows = false; +} +if (empty($prefillByName)) { + $prefillByName = ''; +} +if (empty($prefillById)) { + $prefillById = ''; +} +if (!isset($isRequired)) { + $isRequired = true; +} +if (!isset($label)) { + $label = 'Product'; +} +if (!isset($disabled)) { + $disabled = false; +} +if (empty($hint)) { + $hint = ''; +} +if (empty($nextInputSelector)) { + $nextInputSelector = ''; +} +if (empty($validationMessage)) { + $validationMessage = 'You have to select a product'; +} +if (empty($productsQuery)) { + $productsQuery = ''; +} +@endphp -
- - -
{{ $__t($validationMessage) }}
-
-
{{ $__t('will be added to the list of barcodes for the selected product on submit') }}
+
+ +
+ +
{{ $__t($validationMessage) }}
+
+
+
+ {{ $__t('will be added to the list of barcodes for the selected product on submit') }}
@include('components.barcodescanner') diff --git a/views/components/recipepicker.blade.php b/views/components/recipepicker.blade.php index 21bf624d..fbfd9c3d 100644 --- a/views/components/recipepicker.blade.php +++ b/views/components/recipepicker.blade.php @@ -1,42 +1,53 @@ @once -@push('componentScripts') - -@endpush + @push('componentScripts') + + @endpush @endonce -@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp -@php if(empty($prefillById)) { $prefillById = ''; } @endphp -@php if(!isset($isRequired)) { $isRequired = true; } @endphp -@php if(empty($hint)) { $hint = ''; } @endphp -@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp +@php +if (empty($prefillByName)) { + $prefillByName = ''; +} +@endphp +@php +if (empty($prefillById)) { + $prefillById = ''; +} +@endphp +@php +if (!isset($isRequired)) { + $isRequired = true; +} +@endphp +@php +if (empty($hint)) { + $hint = ''; +} +@endphp +@php +if (empty($nextInputSelector)) { + $nextInputSelector = ''; +} +@endphp -
- - -
{{ $__t('You have to select a recipe') }}
+
+ + {{-- TODO: Select2: dynamic data: recipes --}} + +
{{ $__t('You have to select a recipe') }}
@include('components.barcodescanner') diff --git a/views/components/shoppinglocationpicker.blade.php b/views/components/shoppinglocationpicker.blade.php index fe3e4ce2..dfce2883 100644 --- a/views/components/shoppinglocationpicker.blade.php +++ b/views/components/shoppinglocationpicker.blade.php @@ -1,32 +1,47 @@ @once -@push('componentScripts') - -@endpush + @push('componentScripts') + + @endpush @endonce -@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp -@php if(empty($prefillById)) { $prefillById = ''; } @endphp -@php if(!isset($isRequired)) { $isRequired = false; } @endphp -@php if(empty($hint)) { $hint = ''; } @endphp -@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp +@php +if (empty($prefillByName)) { + $prefillByName = ''; +} +@endphp +@php +if (empty($prefillById)) { + $prefillById = ''; +} +@endphp +@php +if (!isset($isRequired)) { + $isRequired = false; +} +@endphp +@php +if (empty($hint)) { + $hint = ''; +} +@endphp +@php +if (empty($nextInputSelector)) { + $nextInputSelector = ''; +} +@endphp -
- - -
{{ $__t('You have to select a store') }}
+
+ + {{-- TODO: Select2: dynamic data: shopping_locations --}} + +
{{ $__t('You have to select a store') }}
diff --git a/views/components/userpicker.blade.php b/views/components/userpicker.blade.php index d532638c..d714aa03 100644 --- a/views/components/userpicker.blade.php +++ b/views/components/userpicker.blade.php @@ -1,25 +1,34 @@ @once -@push('componentScripts') - -@endpush + @push('componentScripts') + + @endpush @endonce -@php if(empty($prefillByUsername)) { $prefillByUsername = ''; } @endphp -@php if(empty($prefillByUserId)) { $prefillByUserId = ''; } @endphp -@php if(!isset($nextInputSelector)) { $nextInputSelector = ''; } @endphp +@php +if (empty($prefillByUsername)) { + $prefillByUsername = ''; +} +@endphp +@php +if (empty($prefillByUserId)) { + $prefillByUserId = ''; +} +@endphp +@php +if (!isset($nextInputSelector)) { + $nextInputSelector = ''; +} +@endphp -
- - +
+ + {{-- TODO: Select2: dynamic data: users --}} +
diff --git a/views/consume.blade.php b/views/consume.blade.php index 93fbad1f..603ebffe 100644 --- a/views/consume.blade.php +++ b/views/consume.blade.php @@ -5,151 +5,136 @@ @section('viewJsName', 'consume') @push('pageScripts') - + @endpush @section('content') - + -
-
- +
+
+ -
+
-
+ - @include('components.productpicker', array( - 'products' => $products, - 'barcodes' => $barcodes, - 'nextInputSelector' => '#amount', - 'disallowAddProductWorkflows' => true - )) + @include('components.productpicker', [ + 'productsQuery' => 'query%5B%5D=active%3D1&only_in_stock=1&order=name', + 'nextInputSelector' => '#amount', + 'disallowAddProductWorkflows' => true, + ]) -
-
- - -
-
+
+
+ + +
+
- @include('components.productamountpicker', array( - 'value' => 1, - 'additionalHtmlContextHelp' => '
' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '
' - )) + @include('components.productamountpicker', [ + 'value' => 1, + 'additionalHtmlContextHelp' => + '
' . + $__t( + 'Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated' + ) . + '
', + ]) -
- - -
{{ $__t('A location is required') }}
-
+
+ + {{-- TODO: Select2: dynamic data: locations --}} + +
{{ $__t('A location is required') }}
+
-
-
- - -
-
+
+
+ + +
+
-
-
- - -
- -
+
+
+ + +
+ +
- @if (GROCY_FEATURE_FLAG_RECIPES) - @include('components.recipepicker', array( - 'recipes' => $recipes, - 'isRequired' => false, - 'hint' => $__t('This is for statistical purposes only') - )) - @endif + @if (GROCY_FEATURE_FLAG_RECIPES) + @include('components.recipepicker', [ + 'recipes' => $recipes, + 'isRequired' => false, + 'hint' => $__t('This is for statistical purposes only'), + ]) + @endif - + - @if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) - - @endif + @if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) + + @endif -
-
+ +
-
- @include('components.productcard') -
-
+
+ @include('components.productcard') +
+
@stop diff --git a/views/equipment.blade.php b/views/equipment.blade.php index a7ee7cd4..1a12ff2f 100644 --- a/views/equipment.blade.php +++ b/views/equipment.blade.php @@ -5,185 +5,156 @@ @section('viewJsName', 'equipment') @section('content') -
-
- +
+
+ -
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
- - - - - + {{-- TODO: DataTables: dynamic data: equipment --}} +
- {{ $__t('Name') }}
+ + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) - - - - @foreach($equipment as $equipmentItem) - - - + + + + @foreach ($equipment as $equipmentItem) + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $equipmentItem->id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $equipmentItem->id + ), + ]) - - @endforeach - -
+ {{ $__t('Name') }}
- - - - - - {{ $equipmentItem->name }} -
+ + + + + + {{ $equipmentItem->name }} +
-
+ + @endforeach + + +
-
- -
-
-
-
- - - - - - - -
-
-

{{ $__t('The selected equipment has no instruction manual') }}

- -
-
-
-
-
-
- - - - -
-
-
-
-
-
-
-
-
+
+ +
+
+
+
+ + + + + + + +
+
+

+ {{ $__t('The selected equipment has no instruction manual') }}

+ +
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
@stop diff --git a/views/inventory.blade.php b/views/inventory.blade.php index f9cf8d9f..6e88e4b2 100644 --- a/views/inventory.blade.php +++ b/views/inventory.blade.php @@ -21,33 +21,32 @@ novalidate> @include('components.productpicker', array( - 'products' => $products, - 'barcodes' => $barcodes, - 'nextInputSelector' => '#new_amount' + 'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase', + 'nextInputSelector' => '#new_amount' )) @include('components.productamountpicker', array( - 'value' => 1, - 'label' => 'New stock amount', - 'additionalHtmlElements' => '
', - 'additionalHtmlContextHelp' => '
' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '
' + 'value' => 1, + 'label' => 'New stock amount', + 'additionalHtmlElements' => '
', + 'additionalHtmlContextHelp' => '
' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '
' )) @if(boolval($userSettings['show_purchased_date_on_purchase'])) @include('components.datetimepicker2', array( - 'id' => 'purchased_date', - 'label' => 'Purchased date', - 'format' => 'YYYY-MM-DD', - 'hint' => $__t('This will apply to added products'), - 'initWithNow' => true, - 'limitEndToNow' => false, - 'limitStartToNow' => false, - 'invalidFeedback' => $__t('A purchased date is required'), - 'nextInputSelector' => '#best_before_date', - 'additionalCssClasses' => 'date-only-datetimepicker2', - 'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD + 'id' => 'purchased_date', + 'label' => 'Purchased date', + 'format' => 'YYYY-MM-DD', + 'hint' => $__t('This will apply to added products'), + 'initWithNow' => true, + 'limitEndToNow' => false, + 'limitStartToNow' => false, + 'invalidFeedback' => $__t('A purchased date is required'), + 'nextInputSelector' => '#best_before_date', + 'additionalCssClasses' => 'date-only-datetimepicker2', + 'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD )) @endif @@ -59,44 +58,44 @@ } @endphp @include('components.datetimepicker', array( - 'id' => 'best_before_date', - 'label' => 'Due date', - 'hint' => $__t('This will apply to added products'), - 'format' => 'YYYY-MM-DD', - 'initWithNow' => false, - 'limitEndToNow' => false, - 'limitStartToNow' => false, - 'invalidFeedback' => $__t('A due date is required'), - 'nextInputSelector' => '#best_before_date', - 'additionalGroupCssClasses' => 'date-only-datetimepicker', - 'shortcutValue' => '2999-12-31', - 'shortcutLabel' => 'Never overdue', - 'earlierThanInfoLimit' => date('Y-m-d'), - 'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'), - 'additionalGroupCssClasses' => $additionalGroupCssClasses, - 'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD + 'id' => 'best_before_date', + 'label' => 'Due date', + 'hint' => $__t('This will apply to added products'), + 'format' => 'YYYY-MM-DD', + 'initWithNow' => false, + 'limitEndToNow' => false, + 'limitStartToNow' => false, + 'invalidFeedback' => $__t('A due date is required'), + 'nextInputSelector' => '#best_before_date', + 'additionalGroupCssClasses' => 'date-only-datetimepicker', + 'shortcutValue' => '2999-12-31', + 'shortcutLabel' => 'Never overdue', + 'earlierThanInfoLimit' => date('Y-m-d'), + 'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'), + 'additionalGroupCssClasses' => $additionalGroupCssClasses, + 'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD )) @php $additionalGroupCssClasses = ''; @endphp @if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) @include('components.numberpicker', array( - 'id' => 'price', - 'label' => 'Price', - 'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_prices']), - 'decimals' => $userSettings['stock_decimal_places_prices'], - 'value' => '', - 'hint' => $__t('Per stock quantity unit', GROCY_CURRENCY), - 'additionalHtmlContextHelp' => '', - 'isRequired' => false, - 'additionalCssClasses' => 'locale-number-input locale-number-currency' + 'id' => 'price', + 'label' => 'Price', + 'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_prices']), + 'decimals' => $userSettings['stock_decimal_places_prices'], + 'value' => '', + 'hint' => $__t('Per stock quantity unit', GROCY_CURRENCY), + 'additionalHtmlContextHelp' => '', + 'isRequired' => false, + 'additionalCssClasses' => 'locale-number-input locale-number-currency' )) @include('components.shoppinglocationpicker', array( - 'label' => 'Store', - 'shoppinglocations' => $shoppinglocations + 'label' => 'Store', + 'shoppinglocations' => $shoppinglocations )) @else $locations, - 'hint' => $__t('This will apply to added products') + 'locations' => $locations, + 'hint' => $__t('This will apply to added products') )) @endif diff --git a/views/layout/default.blade.php b/views/layout/default.blade.php index 57c8dec1..d3379002 100644 --- a/views/layout/default.blade.php +++ b/views/layout/default.blade.php @@ -73,6 +73,10 @@ rel="stylesheet"> + + @endif + @@ -722,4 +727,4 @@ @endif - + \ No newline at end of file diff --git a/views/locationcontentsheet.blade.php b/views/locationcontentsheet.blade.php index 73e99125..db8eb355 100644 --- a/views/locationcontentsheet.blade.php +++ b/views/locationcontentsheet.blade.php @@ -4,101 +4,102 @@ @section('viewJsName', 'locationcontentsheet') @push('pageStyles') - + @endpush @section('content') - + -
+
-@foreach($locations as $location) -
-

- - {{ $location->name }} - - {{ $__t('Print') . ' (' . $__t('this location') . ')' }} - -

-
- {{ $__t('Time of printing') }}: - -
-
-
- - - - - - - - - - @php $currentStockEntriesForLocation = FindAllObjectsInArrayByPropertyValue($currentStockLocationContent, 'location_id', $location->id); @endphp - @foreach($currentStockEntriesForLocation as $currentStockEntry) - - - - - - @endforeach - -
{{ $__t('Product') }}{{ $__t('Amount') }}{{ $__t('Consumed amount') . ' / ' . $__t('Notes') }}
- {{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }} - - {{ $currentStockEntry->amount }} {{ $__n($currentStockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural, true) }} - @if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif -
-
-
-
-@endforeach + @foreach ($locations as $location) +
+

+ + {{ $location->name }} + + {{ $__t('Print') . ' (' . $__t('this location') . ')' }} + +

+
+ {{ $__t('Time of printing') }}: + +
+
+
+ {{-- TODO: DataTables: dynamic data: stock --}} + + + + + + + + + + @php $currentStockEntriesForLocation = FindAllObjectsInArrayByPropertyValue($currentStockLocationContent, 'location_id', $location->id); @endphp + @foreach ($currentStockEntriesForLocation as $currentStockEntry) + + + + + + @endforeach + +
{{ $__t('Product') }}{{ $__t('Amount') }}{{ $__t('Consumed amount') . ' / ' . $__t('Notes') }}
+ {{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }} + + {{ $currentStockEntry->amount }} + {{ $__n($currentStockEntry->amount,FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name,FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural,true) }} + + @if ($currentStockEntry->amount_opened > 0) + {{ $__t('%s opened', $currentStockEntry->amount_opened) }} + @endif + +
+
+
+
+ @endforeach @stop diff --git a/views/locations.blade.php b/views/locations.blade.php index 3a088465..757472a4 100644 --- a/views/locations.blade.php +++ b/views/locations.blade.php @@ -5,122 +5,108 @@ @section('viewJsName', 'locations') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: locations --}} +
- {{ $__t('Name') }}{{ $__t('Description') }}
+ + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) - - - - @foreach($locations as $location) - - - - + + + + @foreach ($locations as $location) + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $location->id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $location->id + ), + ]) - - @endforeach - -
+ {{ $__t('Name') }}{{ $__t('Description') }}
- - - - - - - - {{ $location->name }} - - {{ $location->description }} -
+ + + + + + + + {{ $location->name }} + + {{ $location->description }} +
-
-
+ + @endforeach + + +
+
@stop diff --git a/views/manageapikeys.blade.php b/views/manageapikeys.blade.php index 5cc45604..bcd7f3e1 100644 --- a/views/manageapikeys.blade.php +++ b/views/manageapikeys.blade.php @@ -5,140 +5,120 @@ @section('viewJsName', 'manageapikeys') @push('pageScripts') - + @endpush @push('pageStyles') - + @endpush @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - - - - - - - - - @foreach($apiKeys as $apiKey) - - - - - - - - - - @endforeach - -
- {{ $__t('API key') }}{{ $__t('User') }}{{ $__t('Expires') }}{{ $__t('Last used') }}{{ $__t('Created') }}{{ $__t('Key type') }}
- - - - - - - - {{ $apiKey->api_key }} - - {{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $apiKey->user_id)) }} - - {{ $apiKey->expires }} - - - @if(empty($apiKey->last_used)){{ $__t('never') }}@else{{ $apiKey->last_used }}@endif - - - {{ $apiKey->row_created_timestamp }} - - - {{ $apiKey->key_type }} -
-
-
+
+
+ {{-- TODO: DataTables: dynamic data: API keys --}} + + + + + + + + + + + + + + @foreach ($apiKeys as $apiKey) + + + + + + + + + + @endforeach + +
+ {{ $__t('API key') }}{{ $__t('User') }}{{ $__t('Expires') }}{{ $__t('Last used') }}{{ $__t('Created') }}{{ $__t('Key type') }}
+ + + + + + + + {{ $apiKey->api_key }} + + {{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $apiKey->user_id)) }} + + {{ $apiKey->expires }} + + + @if (empty($apiKey->last_used)) + {{ $__t('never') }}@else{{ $apiKey->last_used }} + @endif + + + {{ $apiKey->row_created_timestamp }} + + + {{ $apiKey->key_type }} +
+
+
@stop diff --git a/views/mealplan.blade.php b/views/mealplan.blade.php index 8853f146..1a13dc21 100644 --- a/views/mealplan.blade.php +++ b/views/mealplan.blade.php @@ -5,365 +5,311 @@ @section('viewJsName', 'mealplan') @push('pageScripts') - -@if(!empty($__t('fullcalendar_locale') && $__t('fullcalendar_locale') != 'x'))@endif + + @if (!empty($__t('fullcalendar_locale') && $__t('fullcalendar_locale') != 'x')) + + @endif @endpush @push('pageStyles') - + - + @endpush @section('content') - + Grocy.MealPlanFirstDayOfWeek = '{{ GROCY_MEAL_PLAN_FIRST_DAY_OF_WEEK }}'; + -
- -
+
+ +
-
+
-@foreach($usedMealplanSections as $mealplanSection) -
-
-
last doesn't work however, is always null... - --}} - data-last-section="{{ BoolToString(array_values(array_slice($usedMealplanSections->fetchAll(), -1))[0]->id == $mealplanSection->id) }}"> -
-
-
-@endforeach + @foreach ($usedMealplanSections as $mealplanSection) +
+
+
last doesn't work however, is always null... --}} + data-last-section="{{ BoolToString(array_values(array_slice($usedMealplanSections->fetchAll(), -1))[0]->id == $mealplanSection->id) }}"> +
+
+
+ @endforeach -{{-- Default empty calendar/section when no single meal plan entry is in the given date range --}} -@if($usedMealplanSections->count() === 0) -
-
-
-
-
-
-@endif + {{-- Default empty calendar/section when no single meal plan entry is in the given date range --}} + @if ($usedMealplanSections->count() === 0) +
+
+
+
+
+
+ @endif - - - - - + @stop diff --git a/views/mealplansections.blade.php b/views/mealplansections.blade.php index 693f99e4..2ef74d20 100644 --- a/views/mealplansections.blade.php +++ b/views/mealplansections.blade.php @@ -5,111 +5,94 @@ @section('viewJsName', 'mealplansections') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - - - - - - @foreach($mealplanSections as $mealplanSection) - - - - - - - @endforeach - -
- {{ $__t('Name') }}{{ $__t('Sort number') }}{{ $__t('Time') }}
- - - - - - - - {{ $mealplanSection->name }} - - {{ $mealplanSection->sort_number }} - - {{ $mealplanSection->time_info }} -
-
-
+
+
+ {{-- TODO: DataTables: dynamic data: meal_plan_sections --}} + + + + + + + + + + + @foreach ($mealplanSections as $mealplanSection) + + + + + + + @endforeach + +
+ {{ $__t('Name') }}{{ $__t('Sort number') }}{{ $__t('Time') }}
+ + + + + + + + {{ $mealplanSection->name }} + + {{ $mealplanSection->sort_number }} + + {{ $mealplanSection->time_info }} +
+
+
@stop diff --git a/views/productbarcodeform.blade.php b/views/productbarcodeform.blade.php index 2ac5dbf2..1b2ccbdd 100644 --- a/views/productbarcodeform.blade.php +++ b/views/productbarcodeform.blade.php @@ -1,113 +1,104 @@ @extends('layout.default') -@if($mode == 'edit') -@section('title', $__t('Edit Barcode')) +@if ($mode == 'edit') + @section('title', $__t('Edit Barcode')) @else -@section('title', $__t('Create Barcode')) + @section('title', $__t('Create Barcode')) @endif @section('viewJsName', 'productbarcodeform') @section('content') - + -
-
- -
-
+
+
+ +
+
-
+
-
-
+
+
- + - @if($mode == 'edit') - - @endif + @if ($mode == 'edit') + + @endif -
+ - + -
- -
- - @include('components.barcodescanner') -
-
+
+ +
+ + @include('components.barcodescanner') +
+
- @php if($mode == 'edit') { $value = $barcode->amount; } else { $value = ''; } @endphp - @include('components.productamountpicker', array( - 'value' => $value, - 'isRequired' => false - )) + @php + if ($mode == 'edit') { + $value = $barcode->amount; + } else { + $value = ''; + } + @endphp + @include('components.productamountpicker', [ + 'value' => $value, + 'isRequired' => false, + ]) - @if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) -
- - -
- @else - - @endif + @if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) +
+ + {{-- TODO: Select2: dynamic data: shopping_locations --}} + +
+ @else + + @endif -
- - -
+
+ + +
- @include('components.userfieldsform', array( - 'userfields' => $userfields, - 'entity' => 'product_barcodes' - )) + @include('components.userfieldsform', [ + 'userfields' => $userfields, + 'entity' => 'product_barcodes', + ]) - + -
-
-
+ +
+
@stop diff --git a/views/productform.blade.php b/views/productform.blade.php index a86662b8..26208d1b 100644 --- a/views/productform.blade.php +++ b/views/productform.blade.php @@ -1,792 +1,794 @@ @extends('layout.default') -@if($mode == 'edit') -@section('title', $__t('Edit product')) +@if ($mode == 'edit') + @section('title', $__t('Edit product')) @else -@section('title', $__t('Create product')) + @section('title', $__t('Create product')) @endif @section('viewJsName', 'productform') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
- +
+
+ - @if($mode == 'edit') - + @if ($mode == 'edit') + - @if(!empty($product->picture_file_name)) - - @endif - @endif + @if (!empty($product->picture_file_name)) + + @endif + @endif - + -
+
-
+
-
-
- +
+
+ -
+
- - - - - - - - - - + {{-- TODO: DataTables: dynamic data: barcodes --}} +
- {{ $__t('Barcode') }}{{ $__t('Store') }}{{ $__t('Quantity unit') }}{{ $__t('Amount') }}{{ $__t('Last price') }}{{ $__t('Note') }}
+ + + + + + + + + - @include('components.userfields_thead', array( - 'userfields' => $productBarcodeUserfields - )) - - - - @if($mode == "edit") - @foreach($barcodes as $barcode) - @if($barcode->product_id == $product->id || $barcode->product_id == null) - - - - - - - - + @include('components.userfields_thead', [ + 'userfields' => $productBarcodeUserfields, + ]) + + + + @if ($mode == 'edit') + @foreach ($barcodes as $barcode) + @if ($barcode->product_id == $product->id || $barcode->product_id == null) + + + + + + + + - @include('components.userfields_tbody', array( - 'userfields' => $productBarcodeUserfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($productBarcodeUserfieldValues, 'object_id', $barcode->id) - )) - - @endif - @endforeach - @endif - -
+ {{ $__t('Barcode') }} + {{ $__t('Store') }}{{ $__t('Quantity unit') }}{{ $__t('Amount') }}{{ $__t('Last price') }} + {{ $__t('Note') }}
- - - - - - - - {{ $barcode->barcode }} - - @if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $barcode->shopping_location_id) !== null) - {{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $barcode->shopping_location_id)->name }} - @endif - - @if(!empty($barcode->qu_id)) - {{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $barcode->qu_id)->name }} - @endif - - @if(!empty($barcode->amount)) - {{ $barcode->amount }} - @endif - - {{ $barcode->last_price }} - - {{ $barcode->note }} -
+ + + + + + + + {{ $barcode->barcode }} + + @if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $barcode->shopping_location_id) !== null) + {{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $barcode->shopping_location_id)->name }} + @endif + + @if (!empty($barcode->qu_id)) + {{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $barcode->qu_id)->name }} + @endif + + @if (!empty($barcode->amount)) + {{ $barcode->amount }} + @endif + + {{ $barcode->last_price }} + + {{ $barcode->note }} +
-
-
+ @include('components.userfields_tbody', [ + 'userfields' => $productBarcodeUserfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $productBarcodeUserfieldValues, + 'object_id', + $barcode->id + ), + ]) + + @endif + @endforeach + @endif + + +
+
-
-
- -
-
+
+
+ +
+
-
-
- +
+
+ -
+
- - - - - - - - - - - - - @if($mode == "edit") - @foreach($quConversions as $quConversion) - @if($quConversion->product_id == $product->id || $quConversion->product_id == null && ($quConversion->product_id != null || $quConversion->from_qu_id == $product->qu_id_purchase || $quConversion->from_qu_id == $product->qu_id_stock || $quConversion->to_qu_id == $product->qu_id_purchase || $quConversion->to_qu_id == $product->qu_id_stock)) - - - - - - - - - @endif - @endforeach - @endif - -
- {{ $__t('Quantity unit from') }}{{ $__t('Quantity unit to') }}{{ $__t('Factor') }}{{ $__t('Group')}}
- - - - - - - - {{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->from_qu_id)->name }} - - {{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name }} - - {{ $quConversion->factor }} - - @if($quConversion->product_id != null) - {{ $__t('Product overrides') }} - @else - {{ $__t('Default conversions') }} - @endif - - {!! $__t('This means 1 %1$s is the same as %2$s %3$s', FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->from_qu_id)->name, '' . $quConversion->factor . '', $__n($quConversion->factor, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name_plural, true)) !!} -
-
-
+ {{-- TODO: DataTables: dynamic data: quantity_unit_conversions --}} + + + + + + + + + + + + + @if ($mode == 'edit') + @foreach ($quConversions as $quConversion) + @if ($quConversion->product_id == $product->id || ($quConversion->product_id == null && ($quConversion->product_id != null || $quConversion->from_qu_id == $product->qu_id_purchase || $quConversion->from_qu_id == $product->qu_id_stock || $quConversion->to_qu_id == $product->qu_id_purchase || $quConversion->to_qu_id == $product->qu_id_stock))) + + + + + + + + + @endif + @endforeach + @endif + +
+ {{ $__t('Quantity unit from') }}{{ $__t('Quantity unit to') }}{{ $__t('Factor') }}{{ $__t('Group') }}
+ + + + + + + + {{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->from_qu_id)->name }} + + {{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name }} + + {{ $quConversion->factor }} + + @if ($quConversion->product_id != null) + {{ $__t('Product overrides') }} + @else + {{ $__t('Default conversions') }} + @endif + + {!! $__t('This means 1 %1$s is the same as %2$s %3$s', FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->from_qu_id)->name, '' . $quConversion->factor . '', $__n($quConversion->factor, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name_plural, true)) !!} +
+
+
-
-
- - @if($mode == "edit" && !empty($product->picture_file_name)) - -

{{ $__t('The current picture will be deleted on save') }}

- @else -

{{ $__t('No picture available') }}

- @endif -
-
-
-
+
+
+ + @if ($mode == 'edit' && !empty($product->picture_file_name)) + +

+ {{ $__t('The current picture will be deleted on save') }}

+ @else +

+ {{ $__t('No picture available') }}

+ @endif +
+
+
+
@stop diff --git a/views/productgroups.blade.php b/views/productgroups.blade.php index 33085998..66c1f7e6 100644 --- a/views/productgroups.blade.php +++ b/views/productgroups.blade.php @@ -5,129 +5,116 @@ @section('viewJsName', 'productgroups') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: product_groups --}} +
- {{ $__t('Name') }}{{ $__t('Description') }}{{ $__t('Product count') }}
+ + + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) - - - - @foreach($productGroups as $productGroup) - - - - - + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) + + + + @foreach ($productGroups as $productGroup) + + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $productGroup->id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $productGroup->id + ), + ]) - - @endforeach - -
+ {{ $__t('Name') }}{{ $__t('Description') }}{{ $__t('Product count') }}
- - - - - - - - {{ $productGroup->name }} - - {{ $productGroup->description }} - - {{ count(FindAllObjectsInArrayByPropertyValue($products, 'product_group_id', $productGroup->id)) }} - - - -
+ + + + + + + + {{ $productGroup->name }} + + {{ $productGroup->description }} + + {{ count(FindAllObjectsInArrayByPropertyValue($products, 'product_group_id', $productGroup->id)) }} + + + +
-
-
+ + @endforeach + + +
+
@stop diff --git a/views/products.blade.php b/views/products.blade.php index 9ebfe269..1f93923a 100644 --- a/views/products.blade.php +++ b/views/products.blade.php @@ -5,268 +5,148 @@ @section('viewJsName', 'products') @section('content') - + -
+
-
-
-
-
- -
- -
-
-
-
-
-  {{ $__t('Product group') }} -
- -
-
-
-
- - -
-
-
-
- - -
-
- -
+
+
+
+
+ +
+ +
+
+
+
+
+  {{ $__t('Product group') }} +
+ {{-- TODO: Select2: dynamic data: product_groups --}} + +
+
+
+
+ + +
+
+
+
+ + +
+
+ +
-
-
- - - - - - - - - - - +
+
+
- {{ $__t('Name') }}{{ $__t('Location') }}{{ $__t('Min. stock amount') }}{{ $__t('Default quantity unit purchase') }}{{ $__t('Quantity unit stock') }}{{ $__t('Product group') }}{{ $__t('Default store') }}
+ + + + + + + + + + + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) + + + +
+ {{ $__t('Name') }}{{ $__t('Location') }} + {{ $__t('Min. stock amount') }}{{ $__t('Default quantity unit purchase') }}{{ $__t('Quantity unit stock') }}{{ $__t('Product group') }} + {{ $__t('Default store') }}
+
+
- @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + - - - - @foreach($products as $product) - - - - - - - - - - - - {{ $product->name }} - @if(!empty($product->picture_file_name)) - - @endif - - - @php - $location = FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id); - @endphp - @if($location != null) - {{ $location->name }} - @endif - - - {{ $product->min_stock_amount }} - - - {{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_purchase)->name }} - - - {{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_stock)->name }} - - - @if(!empty($product->product_group_id)) {{ FindObjectInArrayByPropertyValue($productGroups, 'id', $product->product_group_id)->name }} @endif - - - @php - $store = FindObjectInArrayByPropertyValue($shoppingLocations, 'id', $product->shopping_location_id); - @endphp - @if($store != null) - {{ $store->name }} - @endif - - - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $product->id) - )) - - - @endforeach - - -
- - - + @stop diff --git a/views/purchase.blade.php b/views/purchase.blade.php index 18b352a1..b7fe667f 100644 --- a/views/purchase.blade.php +++ b/views/purchase.blade.php @@ -53,62 +53,61 @@ novalidate> @include('components.productpicker', array( - 'products' => $products, - 'barcodes' => $barcodes, - 'nextInputSelector' => '#display_amount' + 'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase', + 'nextInputSelector' => '#display_amount' )) @include('components.productamountpicker', array( - 'value' => 1, - 'additionalHtmlContextHelp' => '
' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '
' + 'value' => 1, + 'additionalHtmlContextHelp' => '
' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '
' )) @if(boolval($userSettings['show_purchased_date_on_purchase'])) @include('components.datetimepicker2', array( - 'id' => 'purchased_date', - 'label' => 'Purchased date', - 'format' => 'YYYY-MM-DD', - 'initWithNow' => true, - 'limitEndToNow' => false, - 'limitStartToNow' => false, - 'invalidFeedback' => $__t('A purchased date is required'), - 'nextInputSelector' => '#best_before_date', - 'additionalCssClasses' => 'date-only-datetimepicker2', - 'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD + 'id' => 'purchased_date', + 'label' => 'Purchased date', + 'format' => 'YYYY-MM-DD', + 'initWithNow' => true, + 'limitEndToNow' => false, + 'limitStartToNow' => false, + 'invalidFeedback' => $__t('A purchased date is required'), + 'nextInputSelector' => '#best_before_date', + 'additionalCssClasses' => 'date-only-datetimepicker2', + 'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD )) @endif @if(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) @include('components.datetimepicker', array( - 'id' => 'best_before_date', - 'label' => 'Due date', - 'format' => 'YYYY-MM-DD', - 'initWithNow' => false, - 'limitEndToNow' => false, - 'limitStartToNow' => false, - 'invalidFeedback' => $__t('A due date is required'), - 'nextInputSelector' => '#price', - 'additionalCssClasses' => 'date-only-datetimepicker', - 'shortcutValue' => '2999-12-31', - 'shortcutLabel' => 'Never overdue', - 'earlierThanInfoLimit' => date('Y-m-d'), - 'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'), - 'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD + 'id' => 'best_before_date', + 'label' => 'Due date', + 'format' => 'YYYY-MM-DD', + 'initWithNow' => false, + 'limitEndToNow' => false, + 'limitStartToNow' => false, + 'invalidFeedback' => $__t('A due date is required'), + 'nextInputSelector' => '#price', + 'additionalCssClasses' => 'date-only-datetimepicker', + 'shortcutValue' => '2999-12-31', + 'shortcutLabel' => 'Never overdue', + 'earlierThanInfoLimit' => date('Y-m-d'), + 'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'), + 'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD )) @endif @if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) @include('components.numberpicker', array( - 'id' => 'price', - 'label' => 'Price', - 'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_prices']), - 'decimals' => $userSettings['stock_decimal_places_prices'], - 'value' => '', - 'contextInfoId' => 'price-hint', - 'isRequired' => false, - 'additionalGroupCssClasses' => 'mb-1', - 'additionalCssClasses' => 'locale-number-input locale-number-currency' + 'id' => 'price', + 'label' => 'Price', + 'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_prices']), + 'decimals' => $userSettings['stock_decimal_places_prices'], + 'value' => '', + 'contextInfoId' => 'price-hint', + 'isRequired' => false, + 'additionalGroupCssClasses' => 'mb-1', + 'additionalCssClasses' => 'locale-number-input locale-number-currency' ))
@@ -131,8 +130,8 @@ for="price-type-total-price">{{ $__t('Total price') }}
@include('components.shoppinglocationpicker', array( - 'label' => 'Store', - 'shoppinglocations' => $shoppinglocations + 'label' => 'Store', + 'shoppinglocations' => $shoppinglocations )) @else $locations, - 'isRequired' => false + 'locations' => $locations, + 'isRequired' => false )) @endif diff --git a/views/quantityunitconversionform.blade.php b/views/quantityunitconversionform.blade.php index 025c2886..47385deb 100644 --- a/views/quantityunitconversionform.blade.php +++ b/views/quantityunitconversionform.blade.php @@ -1,122 +1,116 @@ @extends('layout.default') -@if($mode == 'edit') -@section('title', $__t('Edit QU conversion')) +@if ($mode == 'edit') + @section('title', $__t('Edit QU conversion')) @else -@section('title', $__t('Create QU conversion')) + @section('title', $__t('Create QU conversion')) @endif @section('viewJsName', 'quantityunitconversionform') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
+
+
- + - @if($mode == 'edit') - - @endif + @if ($mode == 'edit') + + @endif -
+ - @if($product != null) - - @endif + @if ($product != null) + + @endif -
- - -
{{ $__t('A quantity unit is required') }}
-
+
+ + {{-- TODO: Select2: dynamic data: quantity_units --}} + +
{{ $__t('A quantity unit is required') }}
+
-
- - -
{{ $__t('A quantity unit is required') }}
-
+
+ + {{-- TODO: Select2: dynamic data: quantity_units --}} + +
{{ $__t('A quantity unit is required') }}
+
- @php if($mode == 'edit') { $value = $quConversion->factor; } else { $value = 1; } @endphp - @include('components.numberpicker', array( - 'id' => 'factor', - 'label' => 'Factor', - 'min' => $DEFAULT_MIN_AMOUNT, - 'decimals' => $userSettings['stock_decimal_places_amounts'], - 'value' => $value, - 'additionalHtmlElements' => '

', - 'additionalCssClasses' => 'input-group-qu locale-number-input locale-number-quantity-amount' - )) + @php + if ($mode == 'edit') { + $value = $quConversion->factor; + } else { + $value = 1; + } + @endphp + @include('components.numberpicker', [ + 'id' => 'factor', + 'label' => 'Factor', + 'min' => $DEFAULT_MIN_AMOUNT, + 'decimals' => $userSettings['stock_decimal_places_amounts'], + 'value' => $value, + 'additionalHtmlElements' => '

', + 'additionalCssClasses' => 'input-group-qu locale-number-input locale-number-quantity-amount', + ]) -
-
- - -
- -
+
+
+ + +
+ +
- @include('components.userfieldsform', array( - 'userfields' => $userfields, - 'entity' => 'quantity_unit_conversions' - )) + @include('components.userfieldsform', [ + 'userfields' => $userfields, + 'entity' => 'quantity_unit_conversions', + ]) - + -
-
-
+ +
+
@stop diff --git a/views/quantityunitform.blade.php b/views/quantityunitform.blade.php index e30c8492..ee26f4cb 100644 --- a/views/quantityunitform.blade.php +++ b/views/quantityunitform.blade.php @@ -1,170 +1,161 @@ @extends('layout.default') -@if($mode == 'edit') -@section('title', $__t('Edit quantity unit')) +@if ($mode == 'edit') + @section('title', $__t('Edit quantity unit')) @else -@section('title', $__t('Create quantity unit')) + @section('title', $__t('Create quantity unit')) @endif @section('viewJsName', 'quantityunitform') @section('content') -
-
-

@yield('title')

-
-
+
+
+

@yield('title')

+
+
-
+
-
-
- +
+
+ - @if($mode == 'edit') - - @endif + @if ($mode == 'edit') + + @endif -
+ -
- - -
{{ $__t('A name is required') }}
-
+
+ + +
{{ $__t('A name is required') }}
+
-
- - -
+
+ + +
- @if($pluralCount > 2) -
- - -
- @endif + @if ($pluralCount > 2) +
+ + +
+ @endif -
- - -
+
+ + +
- @include('components.userfieldsform', array( - 'userfields' => $userfields, - 'entity' => 'quantity_units' - )) + @include('components.userfieldsform', [ + 'userfields' => $userfields, + 'entity' => 'quantity_units', + ]) - {{ $__t('Save & continue to add conversions') }} + {{ $__t('Save & continue to add conversions') }} - - + + - @if(intval($pluralCount) > 2) - - @endif + @if (intval($pluralCount) > 2) + + @endif -
-
+ +
-
-
-
- +
+
+
+ - - - - - - - - - - @if($mode == "edit") - @foreach($defaultQuConversions as $defaultQuConversion) - - - - - - @endforeach - @endif - -
- {{ $__t('Factor') }}{{ $__t('Unit') }}
- - - - - - - - {{ $defaultQuConversion->factor }} - - {{ FindObjectInArrayByPropertyValue($quantityUnits, 'id', $defaultQuConversion->to_qu_id)->name }} -
-
-
-
-
+ {{-- TODO: DataTables: dynamic data: quantity_unit_conversions --}} + + + + + + + + + + @if ($mode == 'edit') + @foreach ($defaultQuConversions as $defaultQuConversion) + + + + + + @endforeach + @endif + +
+ {{ $__t('Factor') }}{{ $__t('Unit') }}
+ + + + + + + + {{ $defaultQuConversion->factor }} + + {{ FindObjectInArrayByPropertyValue($quantityUnits, 'id', $defaultQuConversion->to_qu_id)->name }} +
+
+
+
+
@stop diff --git a/views/quantityunitpluraltesting.blade.php b/views/quantityunitpluraltesting.blade.php index 9112729d..45ba2648 100644 --- a/views/quantityunitpluraltesting.blade.php +++ b/views/quantityunitpluraltesting.blade.php @@ -5,51 +5,47 @@ @section('viewJsName', 'quantityunitpluraltesting') @push('pageStyles') - + @endpush @section('content') -
-
-

@yield('title')

-
-
+
+
+

@yield('title')

+
+
-
+
-
-
-
+
+
+ -
- - -
+
+ + {{-- TODO: Select2: dynamic data: quantity_units --}} + +
- @include('components.numberpicker', array( - 'id' => 'amount', - 'label' => 'Amount', - 'min' => 0, - 'decimals' => $userSettings['stock_decimal_places_amounts'], - 'isRequired' => false, - 'value' => 1, - 'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount' - )) + @include('components.numberpicker', [ + 'id' => 'amount', + 'label' => 'Amount', + 'min' => 0, + 'decimals' => $userSettings['stock_decimal_places_amounts'], + 'isRequired' => false, + 'value' => 1, + 'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount', + ]) - + -

{{ $__t('Result') }}:

-
-
+

{{ $__t('Result') }}:

+
+
@stop diff --git a/views/quantityunits.blade.php b/views/quantityunits.blade.php index 8f676110..685224bc 100644 --- a/views/quantityunits.blade.php +++ b/views/quantityunits.blade.php @@ -5,121 +5,107 @@ @section('viewJsName', 'quantityunits') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: quantity_units --}} +
- {{ $__t('Name') }}{{ $__t('Description') }}
+ + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) - - - - @foreach($quantityunits as $quantityunit) - - - - + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) + + + + @foreach ($quantityunits as $quantityunit) + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $quantityunit->id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $quantityunit->id + ), + ]) - - @endforeach - -
+ {{ $__t('Name') }}{{ $__t('Description') }}
- - - - - - - - {{ $quantityunit->name }} - - {{ $quantityunit->description }} -
+ + + + + + + + {{ $quantityunit->name }} + + {{ $quantityunit->description }} +
-
-
+ + @endforeach + + + + @stop diff --git a/views/recipeform.blade.php b/views/recipeform.blade.php index e20968e4..3fc7a01b 100644 --- a/views/recipeform.blade.php +++ b/views/recipeform.blade.php @@ -1,414 +1,388 @@ @extends('layout.default') -@if($mode == 'edit') -@section('title', $__t('Edit recipe')) +@if ($mode == 'edit') + @section('title', $__t('Edit recipe')) @else -@section('title', $__t('Create recipe')) + @section('title', $__t('Create recipe')) @endif @section('viewJsName', 'recipeform') @section('content') -
-
-

@yield('title')

+
+
+

@yield('title')

- + - @if($mode == 'edit') - + @if ($mode == 'edit') + - @if(!empty($recipe->picture_file_name)) - - @endif - @endif -
-
+ @if (!empty($recipe->picture_file_name)) + + @endif + @endif +
+
-
+
-
-
-
+
+
+ -
- - -
{{ $__t('A name is required') }}
-
+
+ + +
{{ $__t('A name is required') }}
+
- @php if($mode == 'edit') { $value = $recipe->base_servings; } else { $value = 1; } @endphp - @include('components.numberpicker', array( - 'id' => 'base_servings', - 'label' => 'Servings', - 'min' => $DEFAULT_MIN_AMOUNT, - 'decimals' => $userSettings['stock_decimal_places_amounts'], - 'value' => $value, - 'hint' => $__t('The ingredients listed here result in this amount of servings'), - 'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount' - )) + @php + if ($mode == 'edit') { + $value = $recipe->base_servings; + } else { + $value = 1; + } + @endphp + @include('components.numberpicker', [ + 'id' => 'base_servings', + 'label' => 'Servings', + 'min' => $DEFAULT_MIN_AMOUNT, + 'decimals' => $userSettings['stock_decimal_places_amounts'], + 'value' => $value, + 'hint' => $__t('The ingredients listed here result in this amount of servings'), + 'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount', + ]) -
-
- not_check_shoppinglist == 1) checked @endif class="form-check-input custom-control-input" type="checkbox" id="not_check_shoppinglist" name="not_check_shoppinglist" value="1"> - -
-
+
+
+ not_check_shoppinglist == 1) checked @endif + class="form-check-input custom-control-input" type="checkbox" id="not_check_shoppinglist" + name="not_check_shoppinglist" value="1"> + +
+
- @include('components.productpicker', array( - 'products' => $products, - 'isRequired' => false, - 'label' => 'Produces product', - 'prefillById' => $mode == 'edit' ? $recipe->product_id : '', - 'hint' => $__t('When a product is selected, one unit (per serving in stock quantity unit) will be added to stock on consuming this recipe'), - 'disallowAllProductWorkflows' => true, - )) + @include('components.productpicker', [ + 'productsQuery' => 'order=name%3Acollate%20nocase', + 'isRequired' => false, + 'label' => 'Produces product', + 'prefillById' => $mode == 'edit' ? $recipe->product_id : '', + 'hint' => $__t( + 'When a product is selected, one unit (per serving in stock quantity unit) will be added to stock on consuming this recipe' + ), + 'disallowAllProductWorkflows' => true, + ]) - @include('components.userfieldsform', array( - 'userfields' => $userfields, - 'entity' => 'recipes' - )) + @include('components.userfieldsform', [ + 'userfields' => $userfields, + 'entity' => 'recipes', + ]) -
- - -
+
+ + +
- {{ $__t('Save & continue to add ingredients and included recipes') }} + {{ $__t('Save & continue to add ingredients and included recipes') }} - - + + - -
+ +
-
-
-
- +
+
+
+ - - - - - - - - - - - - @if($mode == "edit") - @foreach($recipePositions as $recipePosition) - - - - + + + + @endforeach + @endif + +
- {{ $__t('Product') }}{{ $__t('Amount') }}{{ $__t('Note') }}{{ $__t('Ingredient group') }}
- - - - - - - - {{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }} - - @php - // The amount can't be non-numeric when using the frontend, - // but some users decide to edit the database manually and - // enter something like "4 or 5" in the amount column (brilliant) - // => So at least don't crash this view by just assuming 0 if that's the case - if (!is_numeric($recipePosition->amount)) - { - $recipePosition->amount = 0; - } - - $product = FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id); - $productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id); - $productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock); - $productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $recipePosition->qu_id); - if ($productQuConversion && $recipePosition->only_check_single_unit_in_stock == 0) - { - $recipePosition->amount = $recipePosition->amount * $productQuConversion->factor; - } - @endphp - @if(!empty($recipePosition->variable_amount)) - {{ $recipePosition->variable_amount }} - @else - @if($recipePosition->amount == round($recipePosition->amount)){{ round($recipePosition->amount) }}@else{{ $recipePosition->amount }}@endif - @endif - {{ $__n($recipePosition->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name_plural, true) }} + {{-- TODO: DataTables: dynamic data: recipes_pos --}} + + + + + + + + + + + + @if ($mode == 'edit') + @foreach ($recipePositions as $recipePosition) + + + + - - - - @endforeach - @endif - -
+ {{ $__t('Product') }}{{ $__t('Amount') }}{{ $__t('Note') }}{{ $__t('Ingredient group') }}
+ + + + + + + + {{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }} + + @php + // The amount can't be non-numeric when using the frontend, + // but some users decide to edit the database manually and + // enter something like "4 or 5" in the amount column (brilliant) + // => So at least don't crash this view by just assuming 0 if that's the case + if (!is_numeric($recipePosition->amount)) { + $recipePosition->amount = 0; + } + + $product = FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id); + $productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id); + $productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock); + $productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $recipePosition->qu_id); + if ($productQuConversion && $recipePosition->only_check_single_unit_in_stock == 0) { + $recipePosition->amount = $recipePosition->amount * $productQuConversion->factor; + } + @endphp + @if (!empty($recipePosition->variable_amount)) + {{ $recipePosition->variable_amount }} + @else + + @if ($recipePosition->amount == round($recipePosition->amount)) + {{ round($recipePosition->amount) }}@else{{ $recipePosition->amount }} + @endif + + @endif + {{ $__n($recipePosition->amount,FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name,FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name_plural,true) }} - @if(!empty($recipePosition->variable_amount)) -
{{ $__t('Variable amount') }}
- @endif -
- - - - - {{ $recipePosition->ingredient_group }} -
- - + @if (!empty($recipePosition->variable_amount)) +
{{ $__t('Variable amount') }} +
+ @endif +
+ + + + + {{ $recipePosition->ingredient_group }} +
+
+
-
-
- - - - - - - - - - - @if($mode == "edit") - @foreach($recipeNestings as $recipeNesting) - - - - - - @endforeach - @endif - -
- {{ $__t('Recipe') }}{{ $__t('Servings') }}
- - - - - - - - {{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }} - - {{ $recipeNesting->servings }} -
-
-
+
+
+ + {{-- TODO: DataTables: dynamic data: recipes_nestings_resolved --}} + + + + + + + + + + @if ($mode == 'edit') + @foreach ($recipeNestings as $recipeNesting) + + + + + + @endforeach + @endif + +
+ {{ $__t('Recipe') }}{{ $__t('Servings') }}
+ + + + + + + + {{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }} + + {{ $recipeNesting->servings }} +
+
+
-
-
- - @if(!empty($recipe->picture_file_name)) - -

{{ $__t('The current picture will be deleted on save') }}

- @else -

{{ $__t('No picture available') }}

- @endif -
-
- -
-
- -
-
-
+
+
+ + @if (!empty($recipe->picture_file_name)) + +

+ {{ $__t('The current picture will be deleted on save') }}

+ @else +

+ {{ $__t('No picture available') }}

+ @endif +
+
-
+
+
+ +
+
+
- +
@stop diff --git a/views/recipeposform.blade.php b/views/recipeposform.blade.php index a535628f..4cd5a137 100644 --- a/views/recipeposform.blade.php +++ b/views/recipeposform.blade.php @@ -46,8 +46,8 @@ novalidate> @include('components.productpicker', array( - 'products' => $products, - 'nextInputSelector' => '#amount' + 'productsQuery' => ($recipePosId === 'new' ? 'query%5B%5D=active%3D1&' : '') . 'order=name%3Acollate%20nocase', + 'nextInputSelector' => '#amount' ))
@@ -66,9 +66,9 @@ @php if($mode == 'edit') { $value = $recipePos->amount; } else { $value = 1; } @endphp @php if($mode == 'edit') { $initialQuId = $recipePos->qu_id; } else { $initialQuId = ''; } @endphp @include('components.productamountpicker', array( - 'value' => $value, - 'initialQuId' => $initialQuId, - 'additionalGroupCssClasses' => 'mb-2' + 'value' => $value, + 'initialQuId' => $initialQuId, + 'additionalGroupCssClasses' => 'mb-2' ))
@@ -116,15 +116,15 @@ @if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) @php if($mode == 'edit') { $value = $recipePos->price_factor; } else { $value = 1; } @endphp @include('components.numberpicker', array( - 'id' => 'price_factor', - 'label' => 'Price factor', - 'min' => $DEFAULT_MIN_AMOUNT, - 'decimals' => $userSettings['stock_decimal_places_amounts'], - 'value' => '', - 'hint' => $__t('The resulting price of this ingredient will be multiplied by this factor'), - 'isRequired' => true, - 'value' => $value, - 'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount' + 'id' => 'price_factor', + 'label' => 'Price factor', + 'min' => $DEFAULT_MIN_AMOUNT, + 'decimals' => $userSettings['stock_decimal_places_amounts'], + 'value' => '', + 'hint' => $__t('The resulting price of this ingredient will be multiplied by this factor'), + 'isRequired' => true, + 'value' => $value, + 'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount' )) @else - .card-img-top { - max-height: 250px !important; - object-fit: cover !important; - } + + @endpush @section('content') - + -
-
- +
+
+ -
-
-
-
- -
- -
-
+
+
+
+
+ +
+ +
+
-
-
-
-  {{ $__t('Status') }} -
- -
-
+
+
+
+  {{ $__t('Status') }} +
+ +
+
- -
+ +
- + -
-
- - - - - - - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: recipes --}} +
- {{ $__t('Name') }}{{ $__t('Desired servings') }}{{ $__t('Requirements fulfilled') }}Hidden status for sorting of "Requirements fulfilled" columnHidden status for filtering by statusHidden recipe ingredient product namesHidden status for grouping by status
+ + + + + + + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) - - - - @foreach($recipes as $recipe) - - - - - - - - - + + + + @foreach ($recipes as $recipe) + + + + + + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $recipe->id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $recipe->id + ), + ]) - - @endforeach - -
+ {{ $__t('Name') }}{{ $__t('Desired servings') }} + {{ $__t('Requirements fulfilled') }}Hidden status for sorting of "Requirements fulfilled" columnHidden status for filtering by statusHidden recipe ingredient product namesHidden status for grouping by status
- - - - - - {{ $recipe->name }} - - {{ $recipe->desired_servings }} - - @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1)@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)@else@endif - @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1){{ $__t('Enough in stock') }}@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1){{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count, 'Not enough in stock, %s ingredient missing but already on the shopping list', 'Not enough in stock, %s ingredients missing but already on the shopping list') }}@else{{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count, 'Not enough in stock, %s ingredient missing', 'Not enough in stock, %s ingredients missing') }}@endif - - {{ FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count }} - - @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1) Xenoughinstock @elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) enoughinstockwithshoppinglist @else notenoughinstock @endif - - @foreach(FindAllObjectsInArrayByPropertyValue($recipePositionsResolved, 'recipe_id', $recipe->id) as $recipePos) - {{ FindObjectInArrayByPropertyValue($products, 'id', $recipePos->product_id)->name . ' ' }} - @endforeach - - @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1) {{ $__t('Enough in stock') }} @elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) {{ $__t('Not enough in stock, but already on the shopping list') }} @else {{ $__t('Not enough in stock') }} @endif -
+ + + + + + {{ $recipe->name }} + + {{ $recipe->desired_servings }} + + @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1) + + @elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) + @else + @endif + + @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1) + {{ $__t('Enough in stock') }} + @elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) + {{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count,'Not enough in stock, %s ingredient missing but already on the shopping list','Not enough in stock, %s ingredients missing but already on the shopping list') }}@else{{ $__n(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count,'Not enough in stock, %s ingredient missing','Not enough in stock, %s ingredients missing') }} + @endif + + + {{ FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count }} + + @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1) + Xenoughinstock + @elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) + enoughinstockwithshoppinglist + @else + notenoughinstock + @endif + + @foreach (FindAllObjectsInArrayByPropertyValue($recipePositionsResolved, 'recipe_id', $recipe->id) as $recipePos) + {{ FindObjectInArrayByPropertyValue($products, 'id', $recipePos->product_id)->name . ' ' }} + @endforeach + + @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1) + {{ $__t('Enough in stock') }} + @elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) + {{ $__t('Not enough in stock, but already on the shopping list') }} + @else + {{ $__t('Not enough in stock') }} + @endif +
-
+ + @endforeach + + +
- -
-
+ +
+
- @if($selectedRecipe !== null && (boolval($userSettings['recipes_show_list_side_by_side']) || $embedded)) - @php - $allRecipes = $selectedRecipeSubRecipes; - array_unshift($allRecipes, $selectedRecipe); - @endphp - +
+ @endif +
@stop diff --git a/views/shoppinglist.blade.php b/views/shoppinglist.blade.php index 8b896d5e..03be1951 100644 --- a/views/shoppinglist.blade.php +++ b/views/shoppinglist.blade.php @@ -5,427 +5,433 @@ @section('viewJsName', 'shoppinglist') @push('pageScripts') - - + + @endpush @push('pageStyles') - + @endpush @section('content') -
-
- -
-
{{count($missingProducts)}} {{ $__n(count($missingProducts), '%s product is below defined min. stock amount', '%s products are below defined min. stock amount') }}
- -
-
-
+
+
+ +
+
+ {{ count($missingProducts) }} {{ $__n(count($missingProducts),'%s product is below defined min. stock amount','%s products are below defined min. stock amount') }} +
+ +
+
+
-
-
-
-
- -
- -
-
-
-
-
-  {{ $__t('Status') }} -
- -
-
- -
+
+
+
+
+ +
+ +
+
+
+
+
+  {{ $__t('Status') }} +
+ +
+
+ +
-
-
- - - - - - - - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: shopping_lists --}} +
- {{ $__t('Product') }} / {{ $__t('Note') }}{{ $__t('Amount') }}{{ $__t('Product group') }}Hidden status{{ $__t('Last price (Unit)') }}{{ $__t('Last price (Total)') }}{{ $__t('Default store') }}{{ $__t('Barcodes') }}
+ + + + + + + + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) - @include('components.userfields_thead', array( - 'userfields' => $productUserfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) + @include('components.userfields_thead', [ + 'userfields' => $productUserfields, + ]) - - - - @foreach($listItems as $listItem) - - - - @if(!empty($listItem->product_id)) - @php - $listItem->amount_origin_qu = $listItem->amount; - $product = FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id); - $productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id); - $productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock); - $productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $listItem->qu_id); - if ($productQuConversion) - { - $listItem->amount = $listItem->amount * $productQuConversion->factor; - } - @endphp - @endif - - - - - - - + + + + @foreach ($listItems as $listItem) + + + + @if (!empty($listItem->product_id)) + @php + $listItem->amount_origin_qu = $listItem->amount; + $product = FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id); + $productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id); + $productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock); + $productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $listItem->qu_id); + if ($productQuConversion) { + $listItem->amount = $listItem->amount * $productQuConversion->factor; + } + @endphp + @endif + + + + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $listItem->id) - )) - @include('components.userfields_tbody', array( - 'userfields' => $productUserfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($productUserfieldValues, 'object_id', $listItem->product_id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $listItem->id + ), + ]) + @include('components.userfields_tbody', [ + 'userfields' => $productUserfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $productUserfieldValues, + 'object_id', + $listItem->product_id + ), + ]) - - @endforeach - -
+ {{ $__t('Product') }} / {{ $__t('Note') }}{{ $__t('Amount') }}{{ $__t('Product group') }}Hidden status{{ $__t('Last price (Unit)') }}{{ $__t('Last price (Total)') }} + + {{ $__t('Default store') }}{{ $__t('Barcodes') }}
- - - - - - - - - - product_id)) data-toggle="tooltip" title="{{ $__t('Add this item to stock') }}" @endif> - - - amount }}> - {{ $listItem->amount }} @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}@endif - - @if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else {{ $__t('Ungrouped') }} @endif - - @if(FindObjectInArrayByPropertyValue($missingProducts, 'id', $listItem->product_id) !== null) belowminstockamount @endif - @if($listItem->done == 1) xxDONExx @else xxUNDONExx @endif - - {{ $listItem->last_price_unit }} - - {{ $listItem->last_price_total }} - - {{ $listItem->default_shopping_location_name }} - - @foreach(explode(',', $listItem->product_barcodes) as $barcode) - @if(!empty($barcode)) - - @endif - @endforeach -
+ + + + + + + + + + product_id)) data-toggle="tooltip" title="{{ $__t('Add this item to stock') }}" @endif> + + + amount }}> + {{ $listItem->amount }} + @if (!empty($listItem->product_id)) + {{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }} + @endif + + @if (!empty($listItem->product_group_name)) + {{ $listItem->product_group_name }} + @else + {{ $__t('Ungrouped') }} + @endif + + @if (FindObjectInArrayByPropertyValue($missingProducts, 'id', $listItem->product_id) !== null) + belowminstockamount + @endif + @if ($listItem->done == 1) + xxDONExx + @else + xxUNDONExx + @endif + + {{ $listItem->last_price_unit }} + + {{ $listItem->last_price_total }} + + {{ $listItem->default_shopping_location_name }} + + @foreach (explode(',', $listItem->product_barcodes) as $barcode) + @if (!empty($barcode)) + + @endif + @endforeach +
-
+ + @endforeach + + +
- @if(boolval($userSettings['shopping_list_show_calendar'])) -
- @include('components.calendarcard') -
- @endif + @if (boolval($userSettings['shopping_list_show_calendar'])) +
+ @include('components.calendarcard') +
+ @endif -
-
- - {{ $__t('Save') }} - {{ $__t('Clear') }} - -
-
-
+
+
+ + {{ $__t('Save') }} + {{ $__t('Clear') }} + +
+
+
- + -
- - - -
-
-
{{ $__t('Notes') }}
-

-
-
-
- + + @endforeach + + + + + +
+
+
{{ $__t('Notes') }}
+

+
+
+ + @stop diff --git a/views/shoppinglistitemform.blade.php b/views/shoppinglistitemform.blade.php index 8d84b32d..cc06fc01 100644 --- a/views/shoppinglistitemform.blade.php +++ b/views/shoppinglistitemform.blade.php @@ -1,101 +1,112 @@ @extends('layout.default') -@if($mode == 'edit') -@section('title', $__t('Edit shopping list item')) +@if ($mode == 'edit') + @section('title', $__t('Edit shopping list item')) @else -@section('title', $__t('Create shopping list item')) + @section('title', $__t('Create shopping list item')) @endif @section('viewJsName', 'shoppinglistitemform') @section('content') - + -
-
-

@yield('title')

-
-
+
+
+

@yield('title')

+
+
-
+
-
-
- +
+
+ - @if($mode == 'edit') - - @endif + @if ($mode == 'edit') + + @endif -
+ - @if(GROCY_FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS) -
- - -
- @else - - @endif + @if (GROCY_FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS) +
+ + {{-- TODO: Select2: dynamic data: shopping_lists --}} + +
+ @else + + @endif -
- @php if($mode == 'edit') { $productId = $listItem->product_id; } else { $productId = ''; } @endphp - @include('components.productpicker', array( - 'products' => $products, - 'nextInputSelector' => '#amount', - 'isRequired' => true, - 'prefillById' => $productId, - 'validationMessage' => 'A product or a note is required' - )) -
+
+ @php + if ($mode == 'edit') { + $productId = $listItem->product_id; + } else { + $productId = ''; + } + @endphp + @include('components.productpicker', [ + 'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase', + 'nextInputSelector' => '#amount', + 'isRequired' => true, + 'prefillById' => $productId, + 'validationMessage' => 'A product or a note is required', + ]) +
- @php if($mode == 'edit') { $value = $listItem->amount; } else { $value = 1; } @endphp - @php if($mode == 'edit') { $initialQuId = $listItem->qu_id; } else { $initialQuId = ''; } @endphp - @include('components.productamountpicker', array( - 'value' => $value, - 'initialQuId' => $initialQuId, - 'min' => $DEFAULT_MIN_AMOUNT, - 'isRequired' => false - )) + @php + if ($mode == 'edit') { + $value = $listItem->amount; + } else { + $value = 1; + } + @endphp + @php + if ($mode == 'edit') { + $initialQuId = $listItem->qu_id; + } else { + $initialQuId = ''; + } + @endphp + @include('components.productamountpicker', [ + 'value' => $value, + 'initialQuId' => $initialQuId, + 'min' => $DEFAULT_MIN_AMOUNT, + 'isRequired' => false, + ]) -
- - -
{{ $__t('A product or a note is required') }}
-
+
+ + +
{{ $__t('A product or a note is required') }}
+
- @include('components.userfieldsform', array( - 'userfields' => $userfields, - 'entity' => 'shopping_list' - )) + @include('components.userfieldsform', [ + 'userfields' => $userfields, + 'entity' => 'shopping_list', + ]) - + -
-
-
+ +
+
@stop diff --git a/views/shoppinglocations.blade.php b/views/shoppinglocations.blade.php index 24084285..ce5e2efe 100644 --- a/views/shoppinglocations.blade.php +++ b/views/shoppinglocations.blade.php @@ -5,122 +5,109 @@ @section('viewJsName', 'shoppinglocations') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: shopping_locations --}} +
- {{ $__t('Name') }}{{ $__t('Description') }}
+ + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) - - - - @foreach($shoppinglocations as $shoppinglocation) - - - - + + + + @foreach ($shoppinglocations as $shoppinglocation) + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $shoppinglocation->id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $shoppinglocation->id + ), + ]) - - @endforeach - -
+ {{ $__t('Name') }}{{ $__t('Description') }}
- - - - - - - - {{ $shoppinglocation->name }} - - {{ $shoppinglocation->description }} -
+ + + + + + + + {{ $shoppinglocation->name }} + + {{ $shoppinglocation->description }} +
-
-
+ + @endforeach + + + + @stop diff --git a/views/stockentries.blade.php b/views/stockentries.blade.php index 095aca29..d4becd4a 100644 --- a/views/stockentries.blade.php +++ b/views/stockentries.blade.php @@ -4,303 +4,273 @@ @section('viewJsName', 'stockentries') @push('pageStyles') - + @endpush @push('pageScripts') - + @endpush @section('content') -
-
-

@yield('title')

-
- -
-
-
+
+
+

@yield('title')

+
+ +
+
+
-
+
-
-
- @include('components.productpicker', array( - 'products' => $products, - 'disallowAllProductWorkflows' => true, - 'isRequired' => false - )) -
- -
+
+
+ @include('components.productpicker', [ + 'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase', + 'disallowAllProductWorkflows' => true, + 'isRequired' => false, + ]) +
+ +
-
-
- - - - - - - - - - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: stock --}} +
- Hidden product_id {{ $__t('Product') }}{{ $__t('Amount') }}{{ $__t('Due date') }}{{ $__t('Location') }}{{ $__t('Store') }}{{ $__t('Price') }}{{ $__t('Purchased date') }}Hidden purchased_date{{ $__t('Timestamp') }}
+ + + + + + + + + + + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) - - - - @foreach($stockEntries as $stockEntry) - - - - - - - - - - - - + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) + + + + @foreach ($stockEntries as $stockEntry) + + + + + + + + + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $stockEntry->product_id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $stockEntry->product_id + ), + ]) - - @endforeach - -
+ Hidden product_id{{ $__t('Product') }}{{ $__t('Amount') }}{{ $__t('Due date') }} + {{ $__t('Location') }} + {{ $__t('Store') }} + {{ $__t('Price') }}{{ $__t('Purchased date') }}Hidden purchased_date{{ $__t('Timestamp') }}
- - - - @if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) - - - - @endif - - - - - - {{ $stockEntry->product_id }} - - {{ $stockEntry->amount }} {{ $__n($stockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name_plural, true) }} - @if($stockEntry->open == 1){{ $__t('Opened') }}@endif - - {{ $stockEntry->best_before_date }} - - - {{ FindObjectInArrayByPropertyValue($locations, 'id', $stockEntry->location_id)->name }} - - @if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id) !== null) - {{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id)->name }} - @endif - - {{ $stockEntry->price }} - - {{ $stockEntry->purchased_date }} - - {{ $stockEntry->purchased_date }} - {{ $stockEntry->row_created_timestamp }} - -
+ + + + @if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) + + + + @endif + + + + + + {{ $stockEntry->product_id }} + + {{ $stockEntry->amount }} + {{ $__n($stockEntry->amount,FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name,FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name_plural,true) }} + + @if ($stockEntry->open == 1) + {{ $__t('Opened') }}@endif + + + {{ $stockEntry->best_before_date }} + + + {{ FindObjectInArrayByPropertyValue($locations, 'id', $stockEntry->location_id)->name }} + + @if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id) !== null) + {{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id)->name }} + @endif + + {{ $stockEntry->price }} + + {{ $stockEntry->purchased_date }} + + {{ $stockEntry->purchased_date }} + {{ $stockEntry->row_created_timestamp }} + +
-
-
+ + @endforeach + + + + - + @stop diff --git a/views/stockjournal.blade.php b/views/stockjournal.blade.php index c65c0df1..2f2fb87e 100644 --- a/views/stockjournal.blade.php +++ b/views/stockjournal.blade.php @@ -5,198 +5,180 @@ @section('viewJsName', 'stockjournal') @section('content') - + -
+
-
-
-
-
- -
- -
-
-
-
-
-  {{ $__t('Product') }} -
- -
-
-
-
-
-  {{ $__t('Transaction type') }} -
- -
-
-
-
-
-  {{ $__t('Location') }} -
- -
-
-
-
-
-  {{ $__t('User') }} -
- -
-
-
-
-
-  {{ $__t('Date range') }} -
- -
-
- -
+
+
+
+
+ +
+ +
+
+
+
+
+  {{ $__t('Product') }} +
+ +
+
+
+
+
+  {{ $__t('Transaction type') }} +
+ {{-- TODO: Select2: static data --}} + +
+
+
+
+
+  {{ $__t('Location') }} +
+ {{-- TODO: Select2: dynamic data: locations --}} + +
+
+
+
+
+  {{ $__t('User') }} +
+ {{-- TODO: Select2: dynamic data: users --}} + +
+
+
+
+
+  {{ $__t('Date range') }} +
+ +
+
+ +
-
-
- - - - - - - - - - - - - - @foreach($stockLog as $stockLogEntry) - - - - - - - - - - @endforeach - -
- {{ $__t('Product') }}{{ $__t('Amount') }}{{ $__t('Transaction time') }}{{ $__t('Transaction type') }}{{ $__t('Location') }}{{ $__t('Done by') }}
- - - - - {{ $stockLogEntry->product_name }} - @if($stockLogEntry->undone == 1) -
- {{ $__t('Undone on') . ' ' . $stockLogEntry->undone_timestamp }} - - @endif -
- {{ $stockLogEntry->amount }} {{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural, true) }} - - {{ $stockLogEntry->row_created_timestamp }} - - - {{ $__t($stockLogEntry->transaction_type) }} - @if ($stockLogEntry->spoiled == 1) - {{ $__t('Spoiled') }} - @endif - - {{ $stockLogEntry->location_name }} - - {{ $stockLogEntry->user_display_name }} -
-
-
+
+
+ {{-- TODO: DataTables: dynamic data: uihelper_stock_journal --}} + + + + + + + + + + + + + + @foreach ($stockLog as $stockLogEntry) + + + + + + + + + + @endforeach + +
+ {{ $__t('Product') }}{{ $__t('Amount') }}{{ $__t('Transaction time') }}{{ $__t('Transaction type') }}{{ $__t('Location') }} + {{ $__t('Done by') }}
+ + + + + {{ $stockLogEntry->product_name }} + @if ($stockLogEntry->undone == 1) +
+ {{ $__t('Undone on') . ' ' . $stockLogEntry->undone_timestamp }} + + @endif +
+ {{ $stockLogEntry->amount }} + {{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural, true) }} + + {{ $stockLogEntry->row_created_timestamp }} + + + {{ $__t($stockLogEntry->transaction_type) }} + @if ($stockLogEntry->spoiled == 1) + {{ $__t('Spoiled') }} + @endif + + {{ $stockLogEntry->location_name }} + + {{ $stockLogEntry->user_display_name }} +
+
+
@stop diff --git a/views/stockjournalsummary.blade.php b/views/stockjournalsummary.blade.php index 51ca7661..4f2f18c8 100644 --- a/views/stockjournalsummary.blade.php +++ b/views/stockjournalsummary.blade.php @@ -5,127 +5,117 @@ @section('viewJsName', 'stockjournalsummary') @section('content') -
-
-

@yield('title')

-
- -
-
-
+
+
+

@yield('title')

+
+ +
+
+
-
+
-
-
-
-
- -
- -
-
-
-
-
-  {{ $__t('Product') }} -
- -
-
-
-
-
-  {{ $__t('Transaction type') }} -
- -
-
-
-
-
-  {{ $__t('User') }} -
- -
-
- -
+
+
+
+
+ +
+ +
+
+
+
+
+  {{ $__t('Product') }} +
+ {{-- TODO: Select2: dynamic data: products --}} + +
+
+
+
+
+  {{ $__t('Transaction type') }} +
+ {{-- TODO: Select2: static data --}} + +
+
+
+
+
+  {{ $__t('User') }} +
+ {{-- TODO: Select2: dynamic data: users --}} + +
+
+ +
-
-
- - - - - - - - - - - - @foreach($entries as $journalEntry) - - - - - - - - @endforeach - -
- {{ $__t('Product') }}{{ $__t('Transaction type') }}{{ $__t('User') }}{{ $__t('Amount') }}
- {{ $journalEntry->product_name }} - - {{ $__t($journalEntry->transaction_type) }} - - {{ $journalEntry->user_display_name }} - - {{ $journalEntry->amount }} {{ $__n($journalEntry->amount, $journalEntry->qu_name, $journalEntry->qu_name_plural, true) }} -
-
-
+
+
+ {{-- TODO: DataTables: dynamic data: uihelper_stock_journal_summary --}} + + + + + + + + + + + + @foreach ($entries as $journalEntry) + + + + + + + + @endforeach + +
+ {{ $__t('Product') }}{{ $__t('Transaction type') }}{{ $__t('User') }}{{ $__t('Amount') }}
+ {{ $journalEntry->product_name }} + + {{ $__t($journalEntry->transaction_type) }} + + {{ $journalEntry->user_display_name }} + + {{ $journalEntry->amount }} + {{ $__n($journalEntry->amount, $journalEntry->qu_name, $journalEntry->qu_name_plural, true) }} +
+
+
@stop diff --git a/views/stockoverview.blade.php b/views/stockoverview.blade.php index ccda18bb..468515a3 100755 --- a/views/stockoverview.blade.php +++ b/views/stockoverview.blade.php @@ -5,446 +5,438 @@ @section('viewJsName', 'stockoverview') @push('pageStyles') - + @endpush @push('pageScripts') - + @endpush @section('content') -
-
- -
- @if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) -
-
-
- @endif -
- -
-
-
-
-
-
-
- -
- -
-
- @if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) -
-
-
-  {{ $__t('Location') }} -
- -
-
- @endif -
-
-
-  {{ $__t('Product group') }} -
- -
-
-
-
-
-  {{ $__t('Status') }} -
- -
-
-
+
+
+ +
+ @if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) +
+
+
+ @endif +
+ +
+
+
+
+
+
+
+ +
+ +
+
+ @if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) +
+
+
+  {{ $__t('Location') }} +
+ {{-- TODO: Select2: dynamic data: locations --}} + +
+
+ @endif +
+
+
+  {{ $__t('Product group') }} +
+ {{-- TODO: Select2: dynamic data: product_groups --}} + +
+
+
+
+
+  {{ $__t('Status') }} +
+ +
+
+
-
-
- - - - - - - - - - - - - - - - - - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: uihelper_stock_current_overview --}} +
- {{ $__t('Product') }}{{ $__t('Product group') }}{{ $__t('Amount') }}{{ $__t('Value') }}{{ $__t('Next due date') }}Hidden locationHidden statusHidden product group{{ $__t('Calories') }} ({{ $__t('Per stock quantity unit') }}){{ $__t('Calories') }}{{ $__t('Last purchased') }}{{ $__t('Last price') }}{{ $__t('Min. stock amount') }}{{ $__t('Product description') }}{{ $__t('Parent product') }}{{ $__t('Default location') }}{{ $__t('Product picture') }}{{ $__t('Average price') }}
+ + + + + + + + + + + + + + + + + + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) - - - - @foreach($currentStock as $currentStockEntry) - - - - - - - - - + + + @foreach ($currentStock as $currentStockEntry) + + + + + + + + + - - - - - - - - - - - + strtotime('+' . $nextXDays . ' days'), + ) && $currentStockEntry->amount > 0) + duesoon + @endif + @if ($currentStockEntry->amount_aggregated > 0) instockX @endif + @if ($currentStockEntry->product_missing) belowminstockamount + @endif + + + + + + + + + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $currentStockEntry->product_id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $currentStockEntry->product_id + ), + ]) - - @endforeach - -
+ {{ $__t('Product') }}{{ $__t('Product group') }}{{ $__t('Amount') }}{{ $__t('Value') }} + {{ $__t('Next due date') }}Hidden locationHidden statusHidden product group{{ $__t('Calories') }} ({{ $__t('Per stock quantity unit') }}){{ $__t('Calories') }}{{ $__t('Last purchased') }}{{ $__t('Last price') }}{{ $__t('Min. stock amount') }}{{ $__t('Product description') }}{{ $__t('Parent product') }}{{ $__t('Default location') }}{{ $__t('Product picture') }}{{ $__t('Average price') }}
- - {{ $currentStockEntry->quick_consume_amount }} - - - {{ $__t('All') }} - - @if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) - - {{ $currentStockEntry->quick_consume_amount }} - - @endif - - - @if($currentStockEntry->product_group_name !== null){{ $currentStockEntry->product_group_name }}@endif - - {{ $currentStockEntry->amount }} {{ $__n($currentStockEntry->amount, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural) }} - @if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif - @if($currentStockEntry->is_aggregated_amount == 1) - - {{ $currentStockEntry->amount_aggregated }} {{ $__n($currentStockEntry->amount_aggregated, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural, true) }} - @if($currentStockEntry->amount_opened_aggregated > 0){{ $__t('%s opened', $currentStockEntry->amount_opened_aggregated) }}@endif - - @endif - @if(boolval($userSettings['show_icon_on_stock_overview_page_when_product_is_on_shopping_list'])) - @if($currentStockEntry->on_shopping_list) - - - - @endif - @endif - - {{ $currentStockEntry->value }} - - {{ $currentStockEntry->best_before_date }} - - - @foreach(FindAllObjectsInArrayByPropertyValue($currentStockLocations, 'product_id', $currentStockEntry->product_id) as $locationsForProduct) - xx{{ FindObjectInArrayByPropertyValue($locations, 'id', $locationsForProduct->location_id)->name }}xx - @endforeach - - @if($currentStockEntry->best_before_date < date('Y-m-d +
+ + {{ $currentStockEntry->quick_consume_amount }} + + + {{ $__t('All') }} + + @if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) + + {{ $currentStockEntry->quick_consume_amount }} + + @endif + + + @if ($currentStockEntry->product_group_name !== null) + {{ $currentStockEntry->product_group_name }}@endif + + {{ $currentStockEntry->amount }} + {{ $__n($currentStockEntry->amount, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural) }} + + @if ($currentStockEntry->amount_opened > 0) + {{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif + + @if ($currentStockEntry->is_aggregated_amount == 1) + + {{ $currentStockEntry->amount_aggregated }} + {{ $__n($currentStockEntry->amount_aggregated,$currentStockEntry->qu_unit_name,$currentStockEntry->qu_unit_name_plural,true) }} + @if ($currentStockEntry->amount_opened_aggregated > 0){{ $__t('%s opened', $currentStockEntry->amount_opened_aggregated) }} + @endif + + @endif + @if (boolval($userSettings['show_icon_on_stock_overview_page_when_product_is_on_shopping_list'])) + @if ($currentStockEntry->on_shopping_list) + + + + @endif + @endif + + {{ $currentStockEntry->value }} + + {{ $currentStockEntry->best_before_date }} + + + @foreach (FindAllObjectsInArrayByPropertyValue($currentStockLocations, 'product_id', $currentStockEntry->product_id) as $locationsForProduct) + xx{{ FindObjectInArrayByPropertyValue($locations, 'id', $locationsForProduct->location_id)->name }}xx + @endforeach + + @if ($currentStockEntry->best_before_date < + date( + 'Y-m-d 23:59:59', - strtotime('-' - . '1' - . ' days' - )) - && - $currentStockEntry->amount > 0) @if($currentStockEntry->due_type == 1) overdue @else expired @endif @elseif($currentStockEntry->best_before_date < date('Y-m-d + strtotime('-' . '1' . ' days'), + ) && $currentStockEntry->amount > 0) + @if ($currentStockEntry->due_type == 1) overdue + @else + expired @endif + @elseif($currentStockEntry->best_before_date < + date( + 'Y-m-d 23:59:59', - strtotime('+' - . - $nextXDays - . ' days' - )) - && - $currentStockEntry->amount > 0) duesoon @endif - @if($currentStockEntry->amount_aggregated > 0) instockX @endif - @if ($currentStockEntry->product_missing) belowminstockamount @endif - - xx{{ $currentStockEntry->product_group_name }}xx - - {{ $currentStockEntry->product_calories }} - - {{ $currentStockEntry->calories }} - - {{ $currentStockEntry->last_purchased }} - - - {{ $currentStockEntry->last_price }} - - {{ $currentStockEntry->min_stock_amount }} - - {!! $currentStockEntry->product_description !!} - - {{ $currentStockEntry->product_default_location_name }} - - @if(!empty($currentStockEntry->product_picture_file_name)) - - @endif - - {{ $currentStockEntry->average_price }} - + xx{{ $currentStockEntry->product_group_name }}xx + + {{ $currentStockEntry->product_calories }} + + {{ $currentStockEntry->calories }} + + {{ $currentStockEntry->last_purchased }} + + + {{ $currentStockEntry->last_price }} + + {{ $currentStockEntry->min_stock_amount }} + + {!! $currentStockEntry->product_description !!} + + {{ $currentStockEntry->product_default_location_name }} + + @if (!empty($currentStockEntry->product_picture_file_name)) + + @endif + + {{ $currentStockEntry->average_price }} +
-
-
+ + @endforeach + + + + - + @stop diff --git a/views/stocksettings.blade.php b/views/stocksettings.blade.php index d2e6380e..f479f7a4 100644 --- a/views/stocksettings.blade.php +++ b/views/stocksettings.blade.php @@ -5,202 +5,189 @@ @section('viewJsName', 'stocksettings') @section('content') -
-
-

@yield('title')

-
-
+
+
+

@yield('title')

+
+
-
+
-
-
-
-

{{ $__t('Presets for new products') }}

+
+
+
+

{{ $__t('Presets for new products') }}

- @if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) -
- - -
- @endif + @if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) +
+ + {{-- TODO: Select2: dynamic data: locations --}} + +
+ @endif -
- - -
+
+ + {{-- TODO: Select2: dynamic data: product_groups --}} + +
-
- - -
+
+ + {{-- TODO: Select2: dynamic data: quantity_units --}} + +
- @include('components.numberpicker', array( - 'id' => 'product_presets_default_due_days', - 'additionalAttributes' => 'data-setting-key="product_presets_default_due_days"', - 'label' => 'Default due days', - 'min' => -1, - 'additionalCssClasses' => 'user-setting-control' - )) + @include('components.numberpicker', [ + 'id' => 'product_presets_default_due_days', + 'additionalAttributes' => 'data-setting-key="product_presets_default_due_days"', + 'label' => 'Default due days', + 'min' => -1, + 'additionalCssClasses' => 'user-setting-control', + ]) - @if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) -
-
- - -
-
- @endif -
+ @if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) +
+
+ + +
+
+ @endif +
-

{{ $__t('Stock overview') }}

- @include('components.numberpicker', array( - 'id' => 'stock_due_soon_days', - 'additionalAttributes' => 'data-setting-key="stock_due_soon_days"', - 'label' => 'Due soon days', - 'min' => 1, - 'additionalCssClasses' => 'user-setting-control' - )) +

{{ $__t('Stock overview') }}

+ @include('components.numberpicker', [ + 'id' => 'stock_due_soon_days', + 'additionalAttributes' => 'data-setting-key="stock_due_soon_days"', + 'label' => 'Due soon days', + 'min' => 1, + 'additionalCssClasses' => 'user-setting-control', + ]) -
-
- - -
-
+
+
+ + +
+
-

{{ $__t('Purchase') }}

- @include('components.numberpicker', array( - 'id' => 'stock_default_purchase_amount', - 'additionalAttributes' => 'data-setting-key="stock_default_purchase_amount"', - 'label' => 'Default amount for purchase', - 'min' => '0.', - 'decimals' => $userSettings['stock_decimal_places_amounts'], - 'additionalCssClasses' => 'user-setting-control locale-number-input locale-number-quantity-amount', - )) +

{{ $__t('Purchase') }}

+ @include('components.numberpicker', [ + 'id' => 'stock_default_purchase_amount', + 'additionalAttributes' => 'data-setting-key="stock_default_purchase_amount"', + 'label' => 'Default amount for purchase', + 'min' => '0.', + 'decimals' => $userSettings['stock_decimal_places_amounts'], + 'additionalCssClasses' => 'user-setting-control locale-number-input locale-number-quantity-amount', + ]) -
-
- - -
-
+
+
+ + +
+
-
-
- - -
-
+
+
+ + +
+
-

{{ $__t('Consume') }}

- @include('components.numberpicker', array( - 'id' => 'stock_default_consume_amount', - 'additionalAttributes' => 'data-setting-key="stock_default_consume_amount"', - 'label' => 'Default amount for consume', - 'min' => 0, - 'decimals' => $userSettings['stock_decimal_places_amounts'], - 'additionalCssClasses' => 'user-setting-control locale-number-input locale-number-quantity-amount', - 'additionalGroupCssClasses' => 'mb-0' - )) +

{{ $__t('Consume') }}

+ @include('components.numberpicker', [ + 'id' => 'stock_default_consume_amount', + 'additionalAttributes' => 'data-setting-key="stock_default_consume_amount"', + 'label' => 'Default amount for consume', + 'min' => 0, + 'decimals' => $userSettings['stock_decimal_places_amounts'], + 'additionalCssClasses' => 'user-setting-control locale-number-input locale-number-quantity-amount', + 'additionalGroupCssClasses' => 'mb-0', + ]) -
-
- - -
-
+
+
+ + +
+
-

{{ $__t('Common') }}

+

{{ $__t('Common') }}

- @include('components.numberpicker', array( - 'id' => 'stock_decimal_places_amounts', - 'additionalAttributes' => 'data-setting-key="stock_decimal_places_amounts"', - 'label' => 'Decimal places allowed for amounts', - 'min' => 0, - 'additionalCssClasses' => 'user-setting-control' - )) + @include('components.numberpicker', [ + 'id' => 'stock_decimal_places_amounts', + 'additionalAttributes' => 'data-setting-key="stock_decimal_places_amounts"', + 'label' => 'Decimal places allowed for amounts', + 'min' => 0, + 'additionalCssClasses' => 'user-setting-control', + ]) - @if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) - @include('components.numberpicker', array( - 'id' => 'stock_decimal_places_prices', - 'additionalAttributes' => 'data-setting-key="stock_decimal_places_prices"', - 'label' => 'Decimal places allowed for prices', - 'min' => 0, - 'additionalCssClasses' => 'user-setting-control' - )) + @if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) + @include('components.numberpicker', [ + 'id' => 'stock_decimal_places_prices', + 'additionalAttributes' => 'data-setting-key="stock_decimal_places_prices"', + 'label' => 'Decimal places allowed for prices', + 'min' => 0, + 'additionalCssClasses' => 'user-setting-control', + ]) -
-
- - -
-
- @endif +
+
+ + +
+
+ @endif - {{ $__t('OK') }} -
-
+ {{ $__t('OK') }} +
+
@stop diff --git a/views/taskcategories.blade.php b/views/taskcategories.blade.php index af31c9f0..8c92e26c 100644 --- a/views/taskcategories.blade.php +++ b/views/taskcategories.blade.php @@ -5,122 +5,108 @@ @section('viewJsName', 'taskcategories') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: task_categories --}} +
- {{ $__t('Name') }}{{ $__t('Description') }}
+ + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) - - - - @foreach($taskCategories as $taskCategory) - - - - + + + + @foreach ($taskCategories as $taskCategory) + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $taskCategory->id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $taskCategory->id + ), + ]) - - @endforeach - -
+ {{ $__t('Name') }}{{ $__t('Description') }}
- - - - - - - - {{ $taskCategory->name }} - - {{ $taskCategory->description }} -
+ + + + + + + + {{ $taskCategory->name }} + + {{ $taskCategory->description }} +
-
-
+ + @endforeach + + + + @stop diff --git a/views/taskform.blade.php b/views/taskform.blade.php index db56ad2f..d6791521 100644 --- a/views/taskform.blade.php +++ b/views/taskform.blade.php @@ -1,116 +1,109 @@ @extends('layout.default') -@if($mode == 'edit') -@section('title', $__t('Edit task')) +@if ($mode == 'edit') + @section('title', $__t('Edit task')) @else -@section('title', $__t('Create task')) + @section('title', $__t('Create task')) @endif @section('viewJsName', 'taskform') @section('content') -
-
-

@yield('title')

-
-
+
+
+

@yield('title')

+
+
-
+
-
-
- +
+
+ - @if($mode == 'edit') - - @endif + @if ($mode == 'edit') + + @endif -
+ -
- - -
{{ $__t('A name is required') }}
-
+
+ + +
{{ $__t('A name is required') }}
+
-
- - -
+
+ + +
- @php - $initialDueDate = null; - if ($mode == 'edit' && !empty($task->due_date)) - { - $initialDueDate = date('Y-m-d', strtotime($task->due_date)); - } - @endphp - @include('components.datetimepicker', array( - 'id' => 'due_date', - 'label' => 'Due', - 'format' => 'YYYY-MM-DD', - 'initWithNow' => false, - 'initialValue' => $initialDueDate, - 'limitEndToNow' => false, - 'limitStartToNow' => false, - 'invalidFeedback' => $__t('A due date is required'), - 'nextInputSelector' => 'category_id', - 'additionalGroupCssClasses' => 'date-only-datetimepicker', - 'isRequired' => false - )) + @php + $initialDueDate = null; + if ($mode == 'edit' && !empty($task->due_date)) { + $initialDueDate = date('Y-m-d', strtotime($task->due_date)); + } + @endphp + @include('components.datetimepicker', [ + 'id' => 'due_date', + 'label' => 'Due', + 'format' => 'YYYY-MM-DD', + 'initWithNow' => false, + 'initialValue' => $initialDueDate, + 'limitEndToNow' => false, + 'limitStartToNow' => false, + 'invalidFeedback' => $__t('A due date is required'), + 'nextInputSelector' => 'category_id', + 'additionalGroupCssClasses' => 'date-only-datetimepicker', + 'isRequired' => false, + ]) -
- - -
+
+ + {{-- TODO: Select2: dynamic data: task_categories --}} + +
- @php - $initUserId = GROCY_USER_ID; - if ($mode == 'edit') - { - $initUserId = $task->assigned_to_user_id; - } - @endphp - @include('components.userpicker', array( - 'label' => 'Assigned to', - 'users' => $users, - 'prefillByUserId' => $initUserId - )) + @php + $initUserId = GROCY_USER_ID; + if ($mode == 'edit') { + $initUserId = $task->assigned_to_user_id; + } + @endphp + @include('components.userpicker', [ + 'label' => 'Assigned to', + 'users' => $users, + 'prefillByUserId' => $initUserId, + ]) - @include('components.userfieldsform', array( - 'userfields' => $userfields, - 'entity' => 'tasks' - )) + @include('components.userfieldsform', [ + 'userfields' => $userfields, + 'entity' => 'tasks', + ]) - @if($mode == 'edit') - - @else - - - @endif -
-
-
+ @if ($mode == 'edit') + + @else + + + @endif + +
+
@stop diff --git a/views/tasks.blade.php b/views/tasks.blade.php index 06847d73..a352df51 100644 --- a/views/tasks.blade.php +++ b/views/tasks.blade.php @@ -5,200 +5,178 @@ @section('viewJsName', 'tasks') @push('pageStyles') - + @endpush @section('content') -
-
- - -
-
+
+
+ + +
+
-
-
-
-
- -
- -
-
-
-
-
-  {{ $__t('Status') }} -
- -
-
-
-
- - -
-
-
+
+
+
+
+ +
+ +
+
+
+
+
+  {{ $__t('Status') }} +
+ +
+
+
+
+ + +
+
+
-
-
- - - - - - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: tasks --}} +
- {{ $__t('Task') }}{{ $__t('Due') }}{{ $__t('Category') }}{{ $__t('Assigned to') }}Hidden statusHidden category_id
+ + + + + + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) - - - - @foreach($tasks as $task) - - - - - - - - - @include('components.userfields_tbody', - array( 'userfields'=> $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $task->id) - )) + + + + @foreach ($tasks as $task) + + + + + + + + + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $task->id + ), + ]) - - @endforeach - -
+ {{ $__t('Task') }}{{ $__t('Due') }}{{ $__t('Category') }}{{ $__t('Assigned to') }}Hidden statusHidden category_id
- @if($task->done == 0) - - - - @else - - - - @endif - - - - - - - - {{ $task->name }} - - {{ $task->due_date }} - - - @if($task->category_id != null) {{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }} @else {{ $__t('Uncategorized') }}@endif - - @if($task->assigned_to_user_id != null) {{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $task->assigned_to_user_id)) }} @endif - - {{ $task->due_type }} - @if($task->due_type == 'duetoday') - duesoon - @endif - - @if($task->category_id != null) {{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }} @else {{ $__t('Uncategorized') }} @endif -
+ @if ($task->done == 0) + + + + @else + + + + @endif + + + + + + + + {{ $task->name }} + + {{ $task->due_date }} + + + @if ($task->category_id != null) + {{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }} + @else + {{ $__t('Uncategorized') }} + @endif + + @if ($task->assigned_to_user_id != null) + {{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $task->assigned_to_user_id)) }} + @endif + + {{ $task->due_type }} + @if ($task->due_type == 'duetoday') + duesoon + @endif + + @if ($task->category_id != null) + {{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }} + @else + {{ $__t('Uncategorized') }} + @endif +
-
-
+ + @endforeach + + + + @stop diff --git a/views/transfer.blade.php b/views/transfer.blade.php index 5744d7ee..cedfd23e 100644 --- a/views/transfer.blade.php +++ b/views/transfer.blade.php @@ -5,94 +5,88 @@ @section('viewJsName', 'transfer') @section('content') - + -
-
-

@yield('title')

+
+
+

@yield('title')

-
+
-
+ - @include('components.productpicker', array( - 'products' => $products, - 'barcodes' => $barcodes, - 'nextInputSelector' => '#location_id_from', - 'disallowAddProductWorkflows' => true - )) + @include('components.productpicker', [ + 'productsQuery' => 'query%5B%5D=active%3D1&only_in_stock=1&order=name%3Acollate%20nocase', + 'nextInputSelector' => '#location_id_from', + 'disallowAddProductWorkflows' => true, + ]) -
- - -
{{ $__t('A location is required') }}
-
+
+ + {{-- TODO: Select2: dynamic data: locations --}} + +
{{ $__t('A location is required') }}
+
- @include('components.productamountpicker', array( - 'value' => 1, - 'additionalHtmlContextHelp' => '
' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '
' - )) + @include('components.productamountpicker', [ + 'value' => 1, + 'additionalHtmlContextHelp' => + '
' . + $__t( + 'Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated' + ) . + '
', + ]) -
- - -
{{ $__t('A location is required') }}
-
+
+ + {{-- TODO: Select2: dynamic data: locations --}} + +
{{ $__t('A location is required') }}
+
-
-
- - -
- -
+
+
+ + +
+ +
- + -
-
+ +
-
- @include('components.productcard') -
-
+
+ @include('components.productcard') +
+
@stop diff --git a/views/userentities.blade.php b/views/userentities.blade.php index 7cf3c81b..0f487ed4 100644 --- a/views/userentities.blade.php +++ b/views/userentities.blade.php @@ -5,111 +5,95 @@ @section('viewJsName', 'userentities') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - - - - - @foreach($userentities as $userentity) - - - - - - @endforeach - -
- {{ $__t('Name') }}{{ $__t('Caption') }}
- - - - - - - - {{ $__t('Configure fields') }} - - - {{ $userentity->name }} - - {{ $userentity->caption }} -
-
-
+
+
+ {{-- TODO: DataTables: dynamic data: userentities --}} + + + + + + + + + + @foreach ($userentities as $userentity) + + + + + + @endforeach + +
+ {{ $__t('Name') }}{{ $__t('Caption') }}
+ + + + + + + + {{ $__t('Configure fields') }} + + + {{ $userentity->name }} + + {{ $userentity->caption }} +
+
+
@stop diff --git a/views/userfieldform.blade.php b/views/userfieldform.blade.php index abbe8c3e..55fb95cf 100644 --- a/views/userfieldform.blade.php +++ b/views/userfieldform.blade.php @@ -1,153 +1,138 @@ @extends('layout.default') -@if($mode == 'edit') -@section('title', $__t('Edit userfield')) +@if ($mode == 'edit') + @section('title', $__t('Edit userfield')) @else -@section('title', $__t('Create userfield')) + @section('title', $__t('Create userfield')) @endif @section('viewJsName', 'userfieldform') @section('content') -
-
-

@yield('title')

-
-
+
+
+

@yield('title')

+
+
-
+
-
-
- +
+
+ - @if($mode == 'edit') - - @endif + @if ($mode == 'edit') + + @endif -
+ -
- - -
{{ $__t('A entity is required') }}
-
+
+ + {{-- TODO: Select2: dynamic data: userentities --}} + +
{{ $__t('A entity is required') }}
+
-
- - -
{{ $__t('This is required and can only contain letters and numbers') }}
-
+
+ + +
{{ $__t('This is required and can only contain letters and numbers') }} +
+
-
- - -
{{ $__t('A caption is required') }}
-
+
+ + +
{{ $__t('A caption is required') }}
+
- @php if($mode == 'edit' && !empty($userfield->sort_number)) { $value = $userfield->sort_number; } else { $value = ''; } @endphp - @include('components.numberpicker', array( - 'id' => 'sort_number', - 'label' => 'Sort number', - 'min' => 0, - 'value' => $value, - 'isRequired' => false, - 'hint' => $__t('Multiple Userfields will be ordered by that number on the input form') - )) + @php + if ($mode == 'edit' && !empty($userfield->sort_number)) { + $value = $userfield->sort_number; + } else { + $value = ''; + } + @endphp + @include('components.numberpicker', [ + 'id' => 'sort_number', + 'label' => 'Sort number', + 'min' => 0, + 'value' => $value, + 'isRequired' => false, + 'hint' => $__t('Multiple Userfields will be ordered by that number on the input form'), + ]) -
- - -
{{ $__t('A type is required') }}
-
+
+ + {{-- TODO: Select2: static data --}} + +
{{ $__t('A type is required') }}
+
-
- - -
+
+ + +
-
-
- show_as_column_in_tables == 1) checked @endif class="form-check-input custom-control-input" type="checkbox" id="show_as_column_in_tables" name="show_as_column_in_tables" value="1"> - -
-
+
+
+ show_as_column_in_tables == 1) checked @endif + class="form-check-input custom-control-input" type="checkbox" id="show_as_column_in_tables" + name="show_as_column_in_tables" value="1"> + +
+
-
-
- input_required == 1) checked @endif class="form-check-input custom-control-input" type="checkbox" id="input_required" name="input_required" value="1"> - -
-
+
+
+ input_required == 1) checked @endif + class="form-check-input custom-control-input" type="checkbox" id="input_required" + name="input_required" value="1"> + +
+
- + -
-
-
+ +
+
@stop diff --git a/views/userfields.blade.php b/views/userfields.blade.php index 652439de..20aa992b 100644 --- a/views/userfields.blade.php +++ b/views/userfields.blade.php @@ -5,134 +5,117 @@ @section('viewJsName', 'userfields') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
-
-
-
-  {{ $__t('Entity') }} -
- -
-
- -
+
+
+
+
+ +
+ +
+
+
+
+
+  {{ $__t('Entity') }} +
+ {{-- TODO: Select2: dynamic data: userfields --}} + +
+
+ +
-
-
- - - - - - - - - - - - - @foreach($userfields as $userfield) - - - - - - - - - @endforeach - -
- {{ $__t('Entity') }}{{ $__t('Name') }}{{ $__t('Caption') }}{{ $__t('Type') }}{{ $__t('Sort number') }}
- - - - - - - - {{ $userfield->entity }} - - {{ $userfield->name }} - - {{ $userfield->caption }} - - {{ $__t($userfield->type) }} - - {{ $userfield->sort_number }} -
-
-
+
+
+ {{-- TODO: DataTables: dynamic data: userfields --}} + + + + + + + + + + + + + @foreach ($userfields as $userfield) + + + + + + + + + @endforeach + +
+ {{ $__t('Entity') }}{{ $__t('Name') }}{{ $__t('Caption') }}{{ $__t('Type') }}{{ $__t('Sort number') }}
+ + + + + + + + {{ $userfield->entity }} + + {{ $userfield->name }} + + {{ $userfield->caption }} + + {{ $__t($userfield->type) }} + + {{ $userfield->sort_number }} +
+
+
@stop diff --git a/views/userobjects.blade.php b/views/userobjects.blade.php index df6593e1..9c202deb 100644 --- a/views/userobjects.blade.php +++ b/views/userobjects.blade.php @@ -5,112 +5,103 @@ @section('viewJsName', 'userobjects') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - +
+
+ {{-- TODO: DataTables: dynamic data: userobjects --}} +
+ + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) - - - - @foreach($userobjects as $userobject) - - + + + + @foreach ($userobjects as $userobject) + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $userobject->id) - )) + @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $userobject->id + ), + ]) - - @endforeach - -
- - - - - - -
+ + + + + + +
-
-
+ + @endforeach + + + + @stop diff --git a/views/users.blade.php b/views/users.blade.php index 761fcfed..f873b4e1 100644 --- a/views/users.blade.php +++ b/views/users.blade.php @@ -5,130 +5,114 @@ @section('viewJsName', 'users') @section('content') -
-
- -
-
+
+
+ +
+
-
+
-
-
-
-
- -
- -
-
- -
+
+
+
+
+ +
+ +
+
+ +
-
-
- - - - - - - +
+
+ {{-- TODO: DataTables: dynamic data: users --}} +
- {{ $__t('Username') }}{{ $__t('First name') }}{{ $__t('Last name') }}
+ + + + + + - @include('components.userfields_thead', array( - 'userfields' => $userfields - )) - - - - @foreach($users as $user) - - - - - + @include('components.userfields_thead', [ + 'userfields' => $userfields, + ]) + + + + @foreach ($users as $user) + + + + + - @include('components.userfields_tbody', array( - 'userfields' => $userfields, - 'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $user->id) - )) - - @endforeach - -
+ {{ $__t('Username') }}{{ $__t('First name') }}{{ $__t('Last name') }}
- - - - - - - - - - - {{ $user->username }} - - {{ $user->first_name }} - - {{ $user->last_name }} -
+ + + + + + + + + + + {{ $user->username }} + + {{ $user->first_name }} + + {{ $user->last_name }} +
-
-
+ @include('components.userfields_tbody', [ + 'userfields' => $userfields, + 'userfieldValues' => FindAllObjectsInArrayByPropertyValue( + $userfieldValues, + 'object_id', + $user->id + ), + ]) + + @endforeach + + + + @stop diff --git a/yarn.lock b/yarn.lock index 73d35cbc..275431e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -238,7 +238,7 @@ datatables.net-bs4@1.10.16: datatables.net "1.10.16" jquery ">=1.7" -datatables.net-bs4@>=1.11.3, datatables.net-bs4@^1.10.22: +datatables.net-bs4@>=1.11.3: version "1.11.4" resolved "https://registry.yarnpkg.com/datatables.net-bs4/-/datatables.net-bs4-1.11.4.tgz#caa82ab1a989bf1462f075b91213df865060d1ec" integrity sha512-4V2uSxFloX1jRIsy4eAt1INyp5M5Pq5SV017/naq3zpVKraaFwqFjLhtkx64UHGXqcPj7egvj27dVcdnNIKnNA== @@ -246,7 +246,15 @@ datatables.net-bs4@>=1.11.3, datatables.net-bs4@^1.10.22: datatables.net ">=1.11.3" jquery ">=1.7" -datatables.net-colreorder-bs4@^1.5.2: +datatables.net-bs4@^1.11.5: + version "1.11.5" + resolved "https://registry.yarnpkg.com/datatables.net-bs4/-/datatables.net-bs4-1.11.5.tgz#7767a27991c75716ce7fef1aa6a41d01bfeaefbd" + integrity sha512-tYE9MnyWIW4P8nm41yQnCqW4dUPK3M7qsuxQY5rViFFKDEU0bUUNAnE9+69P5/4Exe4uyXaY05xFkD00niPZUA== + dependencies: + datatables.net ">=1.11.3" + jquery ">=1.7" + +datatables.net-colreorder-bs4@^1.5.5: version "1.5.5" resolved "https://registry.yarnpkg.com/datatables.net-colreorder-bs4/-/datatables.net-colreorder-bs4-1.5.5.tgz#52ca2f95148572583ad619d6c9cdb44f1952d355" integrity sha512-MGAJ/k/FeSK2Kccio5k0oBRacBpmaIKP2wXYfC64ONZFjOFxKBSmFevfg7yPdipYdYDwoQqDnmw0MpdIL7UUug== @@ -255,7 +263,7 @@ datatables.net-colreorder-bs4@^1.5.2: datatables.net-colreorder ">=1.5.4" jquery ">=1.7" -datatables.net-colreorder@>=1.5.4, datatables.net-colreorder@^1.5.2: +datatables.net-colreorder@>=1.5.4, datatables.net-colreorder@^1.5.5: version "1.5.5" resolved "https://registry.yarnpkg.com/datatables.net-colreorder/-/datatables.net-colreorder-1.5.5.tgz#0de93e460cba5eb0167c0c491a2da0c76a2e3b12" integrity sha512-AUwv5A/87I4hg7GY/WbhRrDhqng9b019jLvvKutHibSPCEtMDWqyNtuP0q8zYoquqU9UQ1/nqXLW/ld8TzIDYQ== @@ -263,12 +271,12 @@ datatables.net-colreorder@>=1.5.4, datatables.net-colreorder@^1.5.2: datatables.net ">=1.11.3" jquery ">=1.7" -datatables.net-plugins@^1.10.20: - version "1.11.4" - resolved "https://registry.yarnpkg.com/datatables.net-plugins/-/datatables.net-plugins-1.11.4.tgz#8eb7915cd9f43ba8ba256b89e06917aa24d1ac41" - integrity sha512-39yyyoCCavagE0mO1BFsrRPeak5BwOlbtSACdGpPNf3jG5Lm7D6vEUPPcpGy6eLxjCiG/orMxlAqb8E5lSZtoA== +datatables.net-plugins@^1.11.5: + version "1.11.5" + resolved "https://registry.yarnpkg.com/datatables.net-plugins/-/datatables.net-plugins-1.11.5.tgz#c53ebbd0ab3473a08c6ae36eb1990a66de599b89" + integrity sha512-+Rsf/fyLG8GyFqp7Bvd1ElqWGQO3NPsx2VADn9X8QaZbctshGVW0sqvR5V7iHHgY6OY1LR0+t6qIMhan9BM4gA== -datatables.net-rowgroup-bs4@^1.1.2: +datatables.net-rowgroup-bs4@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/datatables.net-rowgroup-bs4/-/datatables.net-rowgroup-bs4-1.1.4.tgz#dd4fad888edea895acd06fe8cf66816809d78eec" integrity sha512-D0+LxraRjvV1RpPNtXJuW9Z4Jn90Sykb7ytJC/5eJsEYc9WnLUvxWEok7fqPpl3dWphQKg5ZbWpKG55Gd1IIXA== @@ -277,7 +285,7 @@ datatables.net-rowgroup-bs4@^1.1.2: datatables.net-rowgroup ">=1.1.3" jquery ">=1.7" -datatables.net-rowgroup@>=1.1.3, datatables.net-rowgroup@^1.1.2: +datatables.net-rowgroup@>=1.1.3, datatables.net-rowgroup@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/datatables.net-rowgroup/-/datatables.net-rowgroup-1.1.4.tgz#3eea91951d46f6c207d2e0c03cb3d635b7b09689" integrity sha512-Oe9mL3X8RXLOQZblJVWTYD0melyw3xoPeQ3T2x1k2guTFxob8/2caKuzn95oFJau6tvbhsvY/QneTaCzHRKnnQ== @@ -285,7 +293,7 @@ datatables.net-rowgroup@>=1.1.3, datatables.net-rowgroup@^1.1.2: datatables.net ">=1.11.3" jquery ">=1.7" -datatables.net-select-bs4@^1.3.1: +datatables.net-select-bs4@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/datatables.net-select-bs4/-/datatables.net-select-bs4-1.3.4.tgz#07336260be0aa7741a61b82188350f4d1e422a02" integrity sha512-hXxxTwR9Mx8xwD55g8hNiLt035afguKZ9Ejsdm5/mo3wmm9ml7gs8QG5fJuMRwtrdP9EKcnjc54+zVoHymEcgw== @@ -294,7 +302,7 @@ datatables.net-select-bs4@^1.3.1: datatables.net-select ">=1.3.3" jquery ">=1.7" -datatables.net-select@>=1.3.3, datatables.net-select@^1.3.1: +datatables.net-select@>=1.3.3, datatables.net-select@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/datatables.net-select/-/datatables.net-select-1.3.4.tgz#7970587a8d8db8ba70a4cccb89b8519bb518116d" integrity sha512-iQ/dBHIWkhfCBxzNdtef79seCNO1ZsA5zU0Uiw3R2mlwmjcJM1xn6pFNajke6SX7VnlzndGDHGqzzEljSqz4pA== @@ -309,13 +317,20 @@ datatables.net@1.10.16: dependencies: jquery ">=1.7" -datatables.net@>=1.11.3, datatables.net@^1.10.22: +datatables.net@>=1.11.3: version "1.11.4" resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.11.4.tgz#5f3e1ec134fa532e794fbd47c13f8333d7a5c455" integrity sha512-z9LG4O0VYOYzp+rnArLExvnUWV8ikyWBcHYZEKDfVuz7BKxQdEq4a/tpO0Trbm+FL1+RY7UEIh+UcYNY/hwGxA== dependencies: jquery ">=1.7" +datatables.net@^1.11.5: + version "1.11.5" + resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.11.5.tgz#858a69953a01e1d5b18786769802117b04b8e3c9" + integrity sha512-nlFst2xfwSWaQgaOg5sXVG3cxYC0tH8E8d65289w9ROgF2TmLULOOpcdMpyxxUim/qEwVSEem42RjkTWEpr3eA== + dependencies: + jquery ">=1.7" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -686,6 +701,16 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +select2-theme-bootstrap4@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/select2-theme-bootstrap4/-/select2-theme-bootstrap4-1.0.1.tgz#aa476930988cb61b05c77d1173a937688d2bb4be" + integrity sha512-gn9zN+ZppzsjRCQzHMfhDyizcCNlzbsB059qAXjyEaFYx7OA3677LYEIbYiGmliuF6y9Dbuae8X8Rk/Z4SBleQ== + +select2@^4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/select2/-/select2-4.0.13.tgz#0dbe377df3f96167c4c1626033e924372d8ef44d" + integrity sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw== + sprintf-js@^1.0.3, sprintf-js@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"