mirror of
https://github.com/grocy/grocy.git
synced 2026-04-10 14:36:16 +02:00
Implement async loading of products, add TODOs
This commit is contained in:
parent
7532626123
commit
94b6bf8eef
|
|
@ -6,7 +6,7 @@ use LessQL\Result;
|
||||||
|
|
||||||
class BaseApiController extends BaseController
|
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 = '!?(=|~|<|>|(>=)|(<=)|(§))';
|
const PATTERN_OPERATOR = '!?(=|~|<|>|(>=)|(<=)|(§))';
|
||||||
|
|
||||||
|
|
@ -16,8 +16,7 @@ class BaseApiController extends BaseController
|
||||||
|
|
||||||
protected function ApiResponse(\Psr\Http\Message\ResponseInterface $response, $data, $cache = false)
|
protected function ApiResponse(\Psr\Http\Message\ResponseInterface $response, $data, $cache = false)
|
||||||
{
|
{
|
||||||
if ($cache)
|
if ($cache) {
|
||||||
{
|
|
||||||
$response = $response->withHeader('Cache-Control', 'max-age=2592000');
|
$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)
|
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);
|
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']);
|
$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));
|
$data = $data->limit(intval($query['limit']), intval($query['offset'] ?? 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($query['order']))
|
return $data;
|
||||||
{
|
|
||||||
$parts = explode(':', $query['order']);
|
|
||||||
|
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $data->orderBy($parts[0], $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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,8 +133,7 @@ class BaseApiController extends BaseController
|
||||||
|
|
||||||
protected function filter(Result $data, array $query): Result
|
protected function filter(Result $data, array $query): Result
|
||||||
{
|
{
|
||||||
foreach ($query as $q)
|
foreach ($query as $q) {
|
||||||
{
|
|
||||||
$matches = [];
|
$matches = [];
|
||||||
preg_match(
|
preg_match(
|
||||||
'/(?P<field>' . self::PATTERN_FIELD . ')'
|
'/(?P<field>' . self::PATTERN_FIELD . ')'
|
||||||
|
|
@ -90,47 +143,63 @@ class BaseApiController extends BaseController
|
||||||
$matches
|
$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');
|
throw new \Exception('Invalid query');
|
||||||
}
|
}
|
||||||
|
list('field' => $field, 'op' => $op, 'value' => $value) = $matches;
|
||||||
|
|
||||||
$sqlOrNull = '';
|
$params = match ($op) {
|
||||||
if (strtolower($matches['value']) == 'null')
|
'=' => [$value],
|
||||||
{
|
'!=' => [$value],
|
||||||
$sqlOrNull = ' OR ' . $matches['field'] . ' IS NULL';
|
'~' => ['%' . $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']) {
|
$field_escaped = '`' . str_replace('`', '``', $field) . '`';
|
||||||
case '=':
|
$where = match ($op) {
|
||||||
$data = $data->where($matches['field'] . ' = ?' . $sqlOrNull, $matches['value']);
|
'=' => $field_escaped . ' = ?' . (strtolower($value) === 'null' ? ' OR ' . $field_escaped . ' IS NULL' : ''),
|
||||||
break;
|
'!=' => $field_escaped . ' != ?' . (strtolower($value) === 'null' ? ' OR ' . $field_escaped . ' IS NULL' : ''),
|
||||||
case '!=':
|
'~' => $field_escaped . ' LIKE ?',
|
||||||
$data = $data->where($matches['field'] . ' != ?' . $sqlOrNull, $matches['value']);
|
'!~' => $field_escaped . ' NOT LIKE ?',
|
||||||
break;
|
'<' => $field_escaped . ' < ?',
|
||||||
case '~':
|
'>' => $field_escaped . ' > ?',
|
||||||
$data = $data->where($matches['field'] . ' LIKE ?', '%' . $matches['value'] . '%');
|
'>=' => $field_escaped . ' >= ?',
|
||||||
break;
|
'<=' => $field_escaped . ' <= ?',
|
||||||
case '!~':
|
'§' => $field_escaped . ' REGEXP ?',
|
||||||
$data = $data->where($matches['field'] . ' NOT LIKE ?', '%' . $matches['value'] . '%');
|
default => '',
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
$data = $data->where($where_prefix . $where . $where_suffix, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|
@ -138,8 +207,7 @@ class BaseApiController extends BaseController
|
||||||
|
|
||||||
protected function getOpenApispec()
|
protected function getOpenApispec()
|
||||||
{
|
{
|
||||||
if ($this->OpenApiSpec == null)
|
if ($this->OpenApiSpec == null) {
|
||||||
{
|
|
||||||
$this->OpenApiSpec = json_decode(file_get_contents(__DIR__ . '/../grocy.openapi.json'));
|
$this->OpenApiSpec = json_decode(file_get_contents(__DIR__ . '/../grocy.openapi.json'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,15 @@ class ChoresController extends BaseController
|
||||||
$usersService = $this->getUsersService();
|
$usersService = $this->getUsersService();
|
||||||
$users = $usersService->GetUsersAsDto();
|
$users = $usersService->GetUsersAsDto();
|
||||||
|
|
||||||
if ($args['choreId'] == 'new')
|
if ($args['choreId'] == 'new') {
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'choreform', [
|
return $this->renderPage($response, 'choreform', [
|
||||||
'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_PERIOD_TYPE_'),
|
'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_PERIOD_TYPE_'),
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('chores'),
|
'userfields' => $this->getUserfieldsService()->GetFields('chores'),
|
||||||
'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'),
|
'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'),
|
||||||
'users' => $users,
|
'users' => $users,
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE')
|
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'choreform', [
|
return $this->renderPage($response, 'choreform', [
|
||||||
'chore' => $this->getDatabase()->chores($args['choreId']),
|
'chore' => $this->getDatabase()->chores($args['choreId']),
|
||||||
'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_PERIOD_TYPE_'),
|
'periodTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_PERIOD_TYPE_'),
|
||||||
|
|
@ -33,19 +29,15 @@ class ChoresController extends BaseController
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('chores'),
|
'userfields' => $this->getUserfieldsService()->GetFields('chores'),
|
||||||
'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'),
|
'assignmentTypes' => GetClassConstants('\Grocy\Services\ChoresService', 'CHORE_ASSIGNMENT_TYPE_'),
|
||||||
'users' => $users,
|
'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)
|
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');
|
$chores = $this->getDatabase()->chores()->orderBy('name', 'COLLATE NOCASE');
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$chores = $this->getDatabase()->chores()->where('active = 1')->orderBy('name', 'COLLATE NOCASE');
|
$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)
|
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'];
|
$months = $request->getQueryParams()['months'];
|
||||||
$where = "tracked_time > DATE(DATE('now', 'localtime'), '-$months months')";
|
$where = "tracked_time > DATE(DATE('now', 'localtime'), '-$months months')";
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Default 1 year
|
// Default 1 year
|
||||||
$where = "tracked_time > DATE(DATE('now', 'localtime'), '-12 months')";
|
$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'];
|
$choreId = $request->getQueryParams()['chore'];
|
||||||
$where .= " AND chore_id = $choreId";
|
$where .= " AND chore_id = $choreId";
|
||||||
}
|
}
|
||||||
|
|
@ -96,20 +84,13 @@ class ChoresController extends BaseController
|
||||||
|
|
||||||
$chores = $this->getDatabase()->chores()->orderBy('name', 'COLLATE NOCASE');
|
$chores = $this->getDatabase()->chores()->orderBy('name', 'COLLATE NOCASE');
|
||||||
$currentChores = $this->getChoresService()->GetCurrent();
|
$currentChores = $this->getChoresService()->GetCurrent();
|
||||||
foreach ($currentChores as $currentChore)
|
foreach ($currentChores as $currentChore) {
|
||||||
{
|
if (FindObjectInArrayByPropertyValue($chores, 'id', $currentChore->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY) {
|
||||||
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')) {
|
||||||
{
|
|
||||||
if ($currentChore->next_estimated_execution_time < date('Y-m-d H:i:s'))
|
|
||||||
{
|
|
||||||
$currentChore->due_type = 'overdue';
|
$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';
|
$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';
|
$currentChore->due_type = 'duesoon';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
namespace Grocy\Controllers;
|
namespace Grocy\Controllers;
|
||||||
|
|
||||||
use Grocy\Controllers\Users\User;
|
use Grocy\Controllers\Users\User;
|
||||||
use Slim\Exception\HttpBadRequestException;
|
use LessQL\Row;
|
||||||
|
|
||||||
class GenericEntityApiController extends BaseApiController
|
class GenericEntityApiController extends BaseApiController
|
||||||
{
|
{
|
||||||
|
|
@ -11,37 +11,28 @@ class GenericEntityApiController extends BaseApiController
|
||||||
{
|
{
|
||||||
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
||||||
|
|
||||||
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoEdit($args['entity']))
|
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoEdit($args['entity'])) {
|
||||||
{
|
if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) {
|
||||||
if ($this->IsEntityWithEditRequiresAdmin($args['entity']))
|
|
||||||
{
|
|
||||||
User::checkPermission($request, User::PERMISSION_ADMIN);
|
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
$requestBody = $this->GetParsedAndFilteredRequestBody($request);
|
$requestBody = $this->GetParsedAndFilteredRequestBody($request);
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
if ($requestBody === null) {
|
||||||
if ($requestBody === null)
|
|
||||||
{
|
|
||||||
throw new \Exception('Request body could not be parsed (probably invalid JSON format or missing/wrong Content-Type header)');
|
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 = $this->getDatabase()->{$args['entity']}()->createRow($requestBody);
|
||||||
$newRow->save();
|
$newRow->save();
|
||||||
$success = $newRow->isClean();
|
|
||||||
|
|
||||||
return $this->ApiResponse($response, [
|
return $this->ApiResponse($response, [
|
||||||
'created_object_id' => $this->getDatabase()->lastInsertId()
|
'created_object_id' => $this->getDatabase()->lastInsertId()
|
||||||
]);
|
]);
|
||||||
}
|
} catch (\Exception $ex) {
|
||||||
catch (\Exception $ex)
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed');
|
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);
|
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
||||||
|
|
||||||
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoDelete($args['entity']))
|
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoDelete($args['entity'])) {
|
||||||
{
|
if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) {
|
||||||
if ($this->IsEntityWithEditRequiresAdmin($args['entity']))
|
|
||||||
{
|
|
||||||
User::checkPermission($request, User::PERMISSION_ADMIN);
|
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
$row = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
$row = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
||||||
if ($row == null)
|
if ($row == null) {
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, 'Object not found', 400);
|
return $this->GenericErrorResponse($response, 'Object not found', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
$row->delete();
|
$row->delete();
|
||||||
$success = $row->isClean();
|
|
||||||
|
|
||||||
return $this->EmptyApiResponse($response);
|
return $this->EmptyApiResponse($response);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, 'Invalid entity');
|
return $this->GenericErrorResponse($response, 'Invalid entity');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -78,102 +63,78 @@ class GenericEntityApiController extends BaseApiController
|
||||||
{
|
{
|
||||||
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
User::checkPermission($request, User::PERMISSION_MASTER_DATA_EDIT);
|
||||||
|
|
||||||
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoEdit($args['entity']))
|
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoEdit($args['entity'])) {
|
||||||
{
|
if ($this->IsEntityWithEditRequiresAdmin($args['entity'])) {
|
||||||
if ($this->IsEntityWithEditRequiresAdmin($args['entity']))
|
|
||||||
{
|
|
||||||
User::checkPermission($request, User::PERMISSION_ADMIN);
|
User::checkPermission($request, User::PERMISSION_ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
$requestBody = $this->GetParsedAndFilteredRequestBody($request);
|
$requestBody = $this->GetParsedAndFilteredRequestBody($request);
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
if ($requestBody === null) {
|
||||||
if ($requestBody === null)
|
|
||||||
{
|
|
||||||
throw new \Exception('Request body could not be parsed (probably invalid JSON format or missing/wrong Content-Type header)');
|
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']);
|
$row = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
||||||
if ($row == null)
|
if ($row == null) {
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, 'Object not found', 400);
|
return $this->GenericErrorResponse($response, 'Object not found', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
$row->update($requestBody);
|
$row->update($requestBody);
|
||||||
$success = $row->isClean();
|
|
||||||
|
|
||||||
return $this->EmptyApiResponse($response);
|
return $this->EmptyApiResponse($response);
|
||||||
}
|
} catch (\Exception $ex) {
|
||||||
catch (\Exception $ex)
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed');
|
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)
|
public function GetObject(\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'])) {
|
||||||
{
|
|
||||||
$userfields = $this->getUserfieldsService()->GetValues($args['entity'], $args['objectId']);
|
|
||||||
if (count($userfields) === 0)
|
|
||||||
{
|
|
||||||
$userfields = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$object = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
$object = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
||||||
if ($object == null)
|
if ($object == null) {
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, 'Object not found', 404);
|
return $this->GenericErrorResponse($response, 'Object not found', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$object['userfields'] = $userfields;
|
$this->addUserfieldsAndJoinsToRow($object, $args);
|
||||||
|
|
||||||
return $this->ApiResponse($response, $object);
|
return $this->ApiResponse($response, $object);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed');
|
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)
|
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');
|
return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed');
|
||||||
}
|
}
|
||||||
|
|
||||||
$objects = $this->queryData($this->getDatabase()->{$args['entity']}(), $request->getQueryParams());
|
$query = $request->getQueryParams();
|
||||||
$userfields = $this->getUserfieldsService()->GetFields($args['entity']);
|
|
||||||
|
|
||||||
if (count($userfields) > 0)
|
// get result and total row count
|
||||||
{
|
$objects = $this->getDatabase()->{$args['entity']}();
|
||||||
$allUserfieldValues = $this->getUserfieldsService()->GetAllValues($args['entity']);
|
$response = $response->withHeader('x-rowcount-total', $objects->count());
|
||||||
|
|
||||||
foreach ($objects as $object)
|
// apply filter, get filtered row count
|
||||||
{
|
$objects = $this->applyQuery($objects, $query);
|
||||||
$userfieldKeyValuePairs = null;
|
$response = $response->withHeader('x-rowcount-filtered', $objects->count());
|
||||||
foreach ($userfields as $userfield)
|
|
||||||
{
|
// apply limit/order
|
||||||
$value = FindObjectInArrayByPropertyValue(FindAllObjectsInArrayByPropertyValue($allUserfieldValues, 'object_id', $object->id), 'name', $userfield->name);
|
$objects = $this->applyLimit($objects, $query);
|
||||||
if ($value)
|
$objects = $this->applyOrder($objects, $query);
|
||||||
{
|
|
||||||
$userfieldKeyValuePairs[$userfield->name] = $value->value;
|
// add entity-specific queries
|
||||||
}
|
if ($args['entity'] === 'products' && isset($query['only_in_stock'])) {
|
||||||
else
|
$objects = $objects->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)');
|
||||||
{
|
|
||||||
$userfieldKeyValuePairs[$userfield->name] = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$object->userfields = $userfieldKeyValuePairs;
|
// add userfields and joins to objects
|
||||||
}
|
foreach ($objects as $object) {
|
||||||
|
$this->addUserfieldsAndJoinsToRow($object, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->ApiResponse($response, $objects);
|
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)
|
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']));
|
return $this->ApiResponse($response, $this->getUserfieldsService()->GetValues($args['entity'], $args['objectId']));
|
||||||
}
|
} catch (\Exception $ex) {
|
||||||
catch (\Exception $ex)
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -197,22 +155,40 @@ class GenericEntityApiController extends BaseApiController
|
||||||
|
|
||||||
$requestBody = $this->GetParsedAndFilteredRequestBody($request);
|
$requestBody = $this->GetParsedAndFilteredRequestBody($request);
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
if ($requestBody === null) {
|
||||||
if ($requestBody === null)
|
|
||||||
{
|
|
||||||
throw new \Exception('Request body could not be parsed (probably invalid JSON format or missing/wrong Content-Type header)');
|
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);
|
$this->getUserfieldsService()->SetValues($args['entity'], $args['objectId'], $requestBody);
|
||||||
return $this->EmptyApiResponse($response);
|
return $this->EmptyApiResponse($response);
|
||||||
}
|
} catch (\Exception $ex) {
|
||||||
catch (\Exception $ex)
|
|
||||||
{
|
|
||||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
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)
|
private function IsEntityWithEditRequiresAdmin($entity)
|
||||||
{
|
{
|
||||||
return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntityEditRequiresAdmin->enum);
|
return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntityEditRequiresAdmin->enum);
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,12 @@ class RecipesController extends BaseController
|
||||||
public function MealPlan(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function MealPlan(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
$start = date('Y-m-d');
|
$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'];
|
$start = $request->getQueryParams()['start'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$days = 6;
|
$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'];
|
$days = $request->getQueryParams()['days'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,19 +25,16 @@ class RecipesController extends BaseController
|
||||||
|
|
||||||
$recipes = $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll();
|
$recipes = $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll();
|
||||||
$events = [];
|
$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']);
|
$recipe = FindObjectInArrayByPropertyValue($recipes, 'id', $mealPlanEntry['recipe_id']);
|
||||||
$title = '';
|
$title = '';
|
||||||
|
|
||||||
if ($recipe !== null)
|
if ($recipe !== null) {
|
||||||
{
|
|
||||||
$title = $recipe->name;
|
$title = $recipe->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
$productDetails = null;
|
$productDetails = null;
|
||||||
if ($mealPlanEntry['product_id'] !== null)
|
if ($mealPlanEntry['product_id'] !== null) {
|
||||||
{
|
|
||||||
$productDetails = $this->getStockService()->GetProductDetails($mealPlanEntry['product_id']);
|
$productDetails = $this->getStockService()->GetProductDetails($mealPlanEntry['product_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,7 +55,6 @@ class RecipesController extends BaseController
|
||||||
'recipes' => $recipes,
|
'recipes' => $recipes,
|
||||||
'internalRecipes' => $this->getDatabase()->recipes()->where("id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan)")->fetchAll(),
|
'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)"),
|
'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'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
||||||
'mealplanSections' => $this->getDatabase()->meal_plan_sections()->orderBy('sort_number'),
|
'mealplanSections' => $this->getDatabase()->meal_plan_sections()->orderBy('sort_number'),
|
||||||
|
|
@ -74,14 +68,10 @@ class RecipesController extends BaseController
|
||||||
$recipesResolved = $this->getRecipesService()->GetRecipesResolved('recipe_id > 0');
|
$recipesResolved = $this->getRecipesService()->GetRecipesResolved('recipe_id > 0');
|
||||||
|
|
||||||
$selectedRecipe = null;
|
$selectedRecipe = null;
|
||||||
if (isset($request->getQueryParams()['recipe']))
|
if (isset($request->getQueryParams()['recipe'])) {
|
||||||
{
|
|
||||||
$selectedRecipe = $this->getDatabase()->recipes($request->getQueryParams()['recipe']);
|
$selectedRecipe = $this->getDatabase()->recipes($request->getQueryParams()['recipe']);
|
||||||
}
|
} else {
|
||||||
else
|
foreach ($recipes as $recipe) {
|
||||||
{
|
|
||||||
foreach ($recipes as $recipe)
|
|
||||||
{
|
|
||||||
$selectedRecipe = $recipe;
|
$selectedRecipe = $recipe;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -89,8 +79,7 @@ class RecipesController extends BaseController
|
||||||
|
|
||||||
$totalCosts = null;
|
$totalCosts = null;
|
||||||
$totalCalories = null;
|
$totalCalories = null;
|
||||||
if ($selectedRecipe)
|
if ($selectedRecipe) {
|
||||||
{
|
|
||||||
$totalCosts = FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->costs;
|
$totalCosts = FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->costs;
|
||||||
$totalCalories = FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->calories;
|
$totalCalories = FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->calories;
|
||||||
}
|
}
|
||||||
|
|
@ -109,27 +98,22 @@ class RecipesController extends BaseController
|
||||||
'selectedRecipeTotalCalories' => $totalCalories
|
'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();
|
$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 = [];
|
||||||
$includedRecipeIdsAbsolute[] = $selectedRecipe->id;
|
$includedRecipeIdsAbsolute[] = $selectedRecipe->id;
|
||||||
foreach ($selectedRecipeSubRecipes as $subRecipe)
|
foreach ($selectedRecipeSubRecipes as $subRecipe) {
|
||||||
{
|
|
||||||
$includedRecipeIdsAbsolute[] = $subRecipe->id;
|
$includedRecipeIdsAbsolute[] = $subRecipe->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Why not directly use recipes_pos_resolved for all recipe positions here (parent and child)?
|
// TODO: Why not directly use recipes_pos_resolved for all recipe positions here (parent and child)?
|
||||||
// This view already correctly recolves child recipe amounts...
|
// This view already correctly recolves child recipe amounts...
|
||||||
$allRecipePositions = [];
|
$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');
|
$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)
|
foreach ($allRecipePositions[$id] as $pos) {
|
||||||
{
|
if ($id != $selectedRecipe->id) {
|
||||||
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();
|
$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->recipe_amount = $pos2->recipe_amount;
|
||||||
$pos->missing_amount = $pos2->missing_amount;
|
$pos->missing_amount = $pos2->missing_amount;
|
||||||
|
|
@ -153,6 +137,7 @@ class RecipesController extends BaseController
|
||||||
'recipe' => $this->getDatabase()->recipes($recipeId),
|
'recipe' => $this->getDatabase()->recipes($recipeId),
|
||||||
'recipePositions' => $this->getDatabase()->recipes_pos()->where('recipe_id', $recipeId),
|
'recipePositions' => $this->getDatabase()->recipes_pos()->where('recipe_id', $recipeId),
|
||||||
'mode' => $recipeId == 'new' ? 'create' : 'edit',
|
'mode' => $recipeId == 'new' ? 'create' : 'edit',
|
||||||
|
// TODO: remove 'products' after converting DataTable
|
||||||
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'),
|
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units(),
|
'quantityunits' => $this->getDatabase()->quantity_units(),
|
||||||
'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'),
|
'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)
|
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', [
|
return $this->renderPage($response, 'recipeposform', [
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
||||||
'recipePos' => new \stdClass(),
|
'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'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'recipeposform', [
|
return $this->renderPage($response, 'recipeposform', [
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
||||||
'recipePos' => $this->getDatabase()->recipes_pos($args['recipePosId']),
|
'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'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'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)
|
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', [
|
return $this->renderPage($response, 'mealplansectionform', [
|
||||||
'mode' => 'create'
|
'mode' => 'create'
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'mealplansectionform', [
|
return $this->renderPage($response, 'mealplansectionform', [
|
||||||
'mealplanSection' => $this->getDatabase()->meal_plan_sections($args['sectionId']),
|
'mealplanSection' => $this->getDatabase()->meal_plan_sections($args['sectionId']),
|
||||||
'mode' => 'edit'
|
'mode' => 'edit'
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ class StockController extends BaseController
|
||||||
public function Consume(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
public function Consume(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'consume', [
|
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'),
|
'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->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)
|
public function Inventory(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'inventory', [
|
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'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->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)
|
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'];
|
$months = $request->getQueryParams()['months'];
|
||||||
$where = "row_created_timestamp > DATE(DATE('now', 'localtime'), '-$months months')";
|
$where = "row_created_timestamp > DATE(DATE('now', 'localtime'), '-$months months')";
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Default 6 months
|
// Default 6 months
|
||||||
$where = "row_created_timestamp > DATE(DATE('now', 'localtime'), '-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'];
|
$productId = $request->getQueryParams()['product'];
|
||||||
$where .= " AND product_id = $productId";
|
$where .= " AND product_id = $productId";
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +48,6 @@ class StockController extends BaseController
|
||||||
|
|
||||||
return $this->renderPage($response, 'stockjournal', [
|
return $this->renderPage($response, 'stockjournal', [
|
||||||
'stockLog' => $this->getDatabase()->uihelper_stock_journal()->where($where)->orderBy('row_created_timestamp', 'DESC'),
|
'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'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'users' => $usersService->GetUsersAsDto(),
|
'users' => $usersService->GetUsersAsDto(),
|
||||||
'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_')
|
'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)
|
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', [
|
return $this->renderPage($response, 'locationform', [
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('locations')
|
'userfields' => $this->getUserfieldsService()->GetFields('locations')
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'locationform', [
|
return $this->renderPage($response, 'locationform', [
|
||||||
'location' => $this->getDatabase()->locations($args['locationId']),
|
'location' => $this->getDatabase()->locations($args['locationId']),
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
|
|
@ -121,13 +109,11 @@ class StockController extends BaseController
|
||||||
{
|
{
|
||||||
$product = null;
|
$product = null;
|
||||||
|
|
||||||
if (isset($request->getQueryParams()['product']))
|
if (isset($request->getQueryParams()['product'])) {
|
||||||
{
|
|
||||||
$product = $this->getDatabase()->products($request->getQueryParams()['product']);
|
$product = $this->getDatabase()->products($request->getQueryParams()['product']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($args['productBarcodeId'] == 'new')
|
if ($args['productBarcodeId'] == 'new') {
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'productbarcodeform', [
|
return $this->renderPage($response, 'productbarcodeform', [
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||||
|
|
@ -137,9 +123,7 @@ class StockController extends BaseController
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('product_barcodes')
|
'userfields' => $this->getUserfieldsService()->GetFields('product_barcodes')
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'productbarcodeform', [
|
return $this->renderPage($response, 'productbarcodeform', [
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
'barcode' => $this->getDatabase()->product_barcodes($args['productBarcodeId']),
|
'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)
|
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', [
|
return $this->renderPage($response, 'productform', [
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name'),
|
||||||
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
'barcodes' => $this->getDatabase()->product_barcodes()->orderBy('barcode'),
|
||||||
|
|
@ -163,13 +146,10 @@ class StockController extends BaseController
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name', 'COLLATE NOCASE'),
|
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
||||||
'products' => $this->getDatabase()->products()->where('parent_product_id IS NULL and active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
|
||||||
'isSubProductOfOthers' => false,
|
'isSubProductOfOthers' => false,
|
||||||
'mode' => 'create'
|
'mode' => 'create'
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$product = $this->getDatabase()->products($args['productId']);
|
$product = $this->getDatabase()->products($args['productId']);
|
||||||
|
|
||||||
return $this->renderPage($response, 'productform', [
|
return $this->renderPage($response, 'productform', [
|
||||||
|
|
@ -180,7 +160,6 @@ class StockController extends BaseController
|
||||||
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name', 'COLLATE NOCASE'),
|
'productgroups' => $this->getDatabase()->product_groups()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('products'),
|
'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,
|
'isSubProductOfOthers' => $this->getDatabase()->products()->where('parent_product_id = :1', $product->id)->count() !== 0,
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
'quConversions' => $this->getDatabase()->quantity_unit_conversions(),
|
'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)
|
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', [
|
return $this->renderPage($response, 'productgroupform', [
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('product_groups')
|
'userfields' => $this->getUserfieldsService()->GetFields('product_groups')
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'productgroupform', [
|
return $this->renderPage($response, 'productgroupform', [
|
||||||
'group' => $this->getDatabase()->product_groups($args['productGroupId']),
|
'group' => $this->getDatabase()->product_groups($args['productGroupId']),
|
||||||
'mode' => 'edit',
|
'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)
|
public function ProductsList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
$products = $this->getDatabase()->products();
|
// $products = $this->getDatabase()->products();
|
||||||
if (!isset($request->getQueryParams()['include_disabled']))
|
// if (!isset($request->getQueryParams()['include_disabled']))
|
||||||
{
|
// {
|
||||||
$products = $products->where('active = 1');
|
// $products = $products->where('active = 1');
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (isset($request->getQueryParams()['only_in_stock']))
|
// if (isset($request->getQueryParams()['only_in_stock']))
|
||||||
{
|
// {
|
||||||
$products = $products->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)');
|
// $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', [
|
return $this->renderPage($response, 'products', [
|
||||||
'products' => $products,
|
// 'products' => $products,
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'productGroups' => $this->getDatabase()->product_groups()->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)
|
public function Purchase(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'purchase', [
|
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'),
|
'shoppinglocations' => $this->getDatabase()->shopping_locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
|
|
@ -267,20 +241,17 @@ class StockController extends BaseController
|
||||||
{
|
{
|
||||||
$product = null;
|
$product = null;
|
||||||
|
|
||||||
if (isset($request->getQueryParams()['product']))
|
if (isset($request->getQueryParams()['product'])) {
|
||||||
{
|
|
||||||
$product = $this->getDatabase()->products($request->getQueryParams()['product']);
|
$product = $this->getDatabase()->products($request->getQueryParams()['product']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$defaultQuUnit = null;
|
$defaultQuUnit = null;
|
||||||
|
|
||||||
if (isset($request->getQueryParams()['qu-unit']))
|
if (isset($request->getQueryParams()['qu-unit'])) {
|
||||||
{
|
|
||||||
$defaultQuUnit = $this->getDatabase()->quantity_units($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', [
|
return $this->renderPage($response, 'quantityunitconversionform', [
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('quantity_unit_conversions'),
|
'userfields' => $this->getUserfieldsService()->GetFields('quantity_unit_conversions'),
|
||||||
|
|
@ -288,9 +259,7 @@ class StockController extends BaseController
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'defaultQuUnit' => $defaultQuUnit
|
'defaultQuUnit' => $defaultQuUnit
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'quantityunitconversionform', [
|
return $this->renderPage($response, 'quantityunitconversionform', [
|
||||||
'quConversion' => $this->getDatabase()->quantity_unit_conversions($args['quConversionId']),
|
'quConversion' => $this->getDatabase()->quantity_unit_conversions($args['quConversionId']),
|
||||||
'mode' => 'edit',
|
'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)
|
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', [
|
return $this->renderPage($response, 'quantityunitform', [
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('quantity_units'),
|
'userfields' => $this->getUserfieldsService()->GetFields('quantity_units'),
|
||||||
'pluralCount' => $this->getLocalizationService()->GetPluralCount(),
|
'pluralCount' => $this->getLocalizationService()->GetPluralCount(),
|
||||||
'pluralRule' => $this->getLocalizationService()->GetPluralDefinition()
|
'pluralRule' => $this->getLocalizationService()->GetPluralDefinition()
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$quantityUnit = $this->getDatabase()->quantity_units($args['quantityunitId']);
|
$quantityUnit = $this->getDatabase()->quantity_units($args['quantityunitId']);
|
||||||
|
|
||||||
return $this->renderPage($response, 'quantityunitform', [
|
return $this->renderPage($response, 'quantityunitform', [
|
||||||
|
|
@ -349,8 +315,7 @@ class StockController extends BaseController
|
||||||
{
|
{
|
||||||
$listId = 1;
|
$listId = 1;
|
||||||
|
|
||||||
if (isset($request->getQueryParams()['list']))
|
if (isset($request->getQueryParams()['list'])) {
|
||||||
{
|
|
||||||
$listId = $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)
|
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', [
|
return $this->renderPage($response, 'shoppinglistform', [
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('shopping_lists')
|
'userfields' => $this->getUserfieldsService()->GetFields('shopping_lists')
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'shoppinglistform', [
|
return $this->renderPage($response, 'shoppinglistform', [
|
||||||
'shoppingList' => $this->getDatabase()->shopping_lists($args['listId']),
|
'shoppingList' => $this->getDatabase()->shopping_lists($args['listId']),
|
||||||
'mode' => 'edit',
|
'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)
|
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', [
|
return $this->renderPage($response, 'shoppinglistitemform', [
|
||||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'shoppingLists' => $this->getDatabase()->shopping_lists()->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(),
|
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('shopping_list')
|
'userfields' => $this->getUserfieldsService()->GetFields('shopping_list')
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'shoppinglistitemform', [
|
return $this->renderPage($response, 'shoppinglistitemform', [
|
||||||
'listItem' => $this->getDatabase()->shopping_list($args['itemId']),
|
'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'),
|
'shoppingLists' => $this->getDatabase()->shopping_lists()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'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)
|
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', [
|
return $this->renderPage($response, 'shoppinglocationform', [
|
||||||
'mode' => 'create',
|
'mode' => 'create',
|
||||||
'userfields' => $this->getUserfieldsService()->GetFields('shopping_locations')
|
'userfields' => $this->getUserfieldsService()->GetFields('shopping_locations')
|
||||||
]);
|
]);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->renderPage($response, 'shoppinglocationform', [
|
return $this->renderPage($response, 'shoppinglocationform', [
|
||||||
'shoppinglocation' => $this->getDatabase()->shopping_locations($args['shoppingLocationId']),
|
'shoppinglocation' => $this->getDatabase()->shopping_locations($args['shoppingLocationId']),
|
||||||
'mode' => 'edit',
|
'mode' => 'edit',
|
||||||
|
|
@ -489,6 +444,7 @@ class StockController extends BaseController
|
||||||
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_due_soon_days'];
|
$nextXDays = $usersService->GetUserSettings(GROCY_USER_ID)['stock_due_soon_days'];
|
||||||
|
|
||||||
return $this->renderPage($response, 'stockentries', [
|
return $this->renderPage($response, 'stockentries', [
|
||||||
|
// TODO: remove 'products' after converting DataTable
|
||||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'locations' => $this->getDatabase()->locations()->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)
|
public function Transfer(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
return $this->renderPage($response, 'transfer', [
|
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'),
|
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
'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)
|
public function JournalSummary(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
{
|
{
|
||||||
$entries = $this->getDatabase()->uihelper_stock_journal_summary();
|
$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']);
|
$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']);
|
$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']);
|
$entries = $entries->where('transaction_type', $request->getQueryParams()['transaction_type']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$usersService = $this->getUsersService();
|
$usersService = $this->getUsersService();
|
||||||
return $this->renderPage($response, 'stockjournalsummary', [
|
return $this->renderPage($response, 'stockjournalsummary', [
|
||||||
'entries' => $entries,
|
'entries' => $entries,
|
||||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
|
||||||
'users' => $usersService->GetUsersAsDto(),
|
'users' => $usersService->GetUsersAsDto(),
|
||||||
'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_')
|
'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_')
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -2308,3 +2308,18 @@ msgstr ""
|
||||||
|
|
||||||
msgid "Average execution frequency"
|
msgid "Average execution frequency"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Pakke"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Del"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Boks"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bunt"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Flaske"
|
||||||
|
msgstr ""
|
||||||
|
|
|
||||||
20
package.json
20
package.json
|
|
@ -12,15 +12,15 @@
|
||||||
"bootstrap-select": "^1.13.18",
|
"bootstrap-select": "^1.13.18",
|
||||||
"bwip-js": "^3.0.1",
|
"bwip-js": "^3.0.1",
|
||||||
"chart.js": "^2.8.0",
|
"chart.js": "^2.8.0",
|
||||||
"datatables.net": "^1.10.22",
|
"datatables.net": "^1.11.5",
|
||||||
"datatables.net-bs4": "^1.10.22",
|
"datatables.net-bs4": "^1.11.5",
|
||||||
"datatables.net-colreorder": "^1.5.2",
|
"datatables.net-colreorder": "^1.5.5",
|
||||||
"datatables.net-colreorder-bs4": "^1.5.2",
|
"datatables.net-colreorder-bs4": "^1.5.5",
|
||||||
"datatables.net-plugins": "^1.10.20",
|
"datatables.net-plugins": "^1.11.5",
|
||||||
"datatables.net-rowgroup": "^1.1.2",
|
"datatables.net-rowgroup": "^1.1.4",
|
||||||
"datatables.net-rowgroup-bs4": "^1.1.2",
|
"datatables.net-rowgroup-bs4": "^1.1.4",
|
||||||
"datatables.net-select": "^1.3.1",
|
"datatables.net-select": "^1.3.4",
|
||||||
"datatables.net-select-bs4": "^1.3.1",
|
"datatables.net-select-bs4": "^1.3.4",
|
||||||
"fullcalendar": "^3.10.1",
|
"fullcalendar": "^3.10.1",
|
||||||
"gettext-translator": "2.1.0",
|
"gettext-translator": "2.1.0",
|
||||||
"jquery": "3.5.1",
|
"jquery": "3.5.1",
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
"jquery-serializejson": "^2.9.0",
|
"jquery-serializejson": "^2.9.0",
|
||||||
"moment": "^2.27.0",
|
"moment": "^2.27.0",
|
||||||
"nosleep.js": "^0.12.0",
|
"nosleep.js": "^0.12.0",
|
||||||
|
"select2": "^4.0.13",
|
||||||
|
"select2-theme-bootstrap4": "^1.0.1",
|
||||||
"sprintf-js": "^1.1.2",
|
"sprintf-js": "^1.1.2",
|
||||||
"startbootstrap-sb-admin": "4.0.0",
|
"startbootstrap-sb-admin": "4.0.0",
|
||||||
"summernote": "^0.8.18",
|
"summernote": "^0.8.18",
|
||||||
|
|
|
||||||
|
|
@ -94,10 +94,10 @@ body.fullscreen-card {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-check-input.is-valid ~ .form-check-label,
|
.form-check-input.is-valid~.form-check-label,
|
||||||
.was-validated .form-check-input:valid ~ .form-check-label,
|
.was-validated .form-check-input:valid~.form-check-label,
|
||||||
.custom-control-input.is-valid ~ .custom-control-label,
|
.custom-control-input.is-valid~.custom-control-label,
|
||||||
.was-validated .custom-control-input:valid ~ .custom-control-label {
|
.was-validated .custom-control-input:valid~.custom-control-label {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,20 +192,20 @@ form.has-sticky-form-footer .form-group:nth-last-child(2) {
|
||||||
border-color: #d6d6d6 !important;
|
border-color: #d6d6d6 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-sidenav > li,
|
.navbar-sidenav>li,
|
||||||
.sidenav-second-level > li {
|
.sidenav-second-level>li {
|
||||||
transition: all 0.3s !important;
|
transition: all 0.3s !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-sidenav > li:hover,
|
.navbar-sidenav>li:hover,
|
||||||
.sidenav-second-level > li:hover,
|
.sidenav-second-level>li:hover,
|
||||||
.navbar-nav .dropdown-item:hover {
|
.navbar-nav .dropdown-item:hover {
|
||||||
box-shadow: inset 5px 0 0 #337ab7 !important;
|
box-shadow: inset 5px 0 0 #337ab7 !important;
|
||||||
background-color: #d6d6d6 !important;
|
background-color: #d6d6d6 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-sidenav > li > a:focus,
|
.navbar-sidenav>li>a:focus,
|
||||||
.sidenav-second-level > li > a:focus,
|
.sidenav-second-level>li>a:focus,
|
||||||
.navbar-nav .dropdown-item:focus {
|
.navbar-nav .dropdown-item:focus {
|
||||||
box-shadow: inset 5px 0 0 #ab2230 !important;
|
box-shadow: inset 5px 0 0 #ab2230 !important;
|
||||||
background-color: #d6d6d6 !important;
|
background-color: #d6d6d6 !important;
|
||||||
|
|
@ -228,7 +228,8 @@ form.has-sticky-form-footer .form-group:nth-last-child(2) {
|
||||||
cursor: wait;
|
cursor: wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expandable-text .collapse, .module .collapsing {
|
.expandable-text .collapse,
|
||||||
|
.module .collapsing {
|
||||||
height: 2.4rem;
|
height: 2.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,7 +256,8 @@ form.has-sticky-form-footer .form-group:nth-last-child(2) {
|
||||||
.table-inline-menu.dropdown-menu {
|
.table-inline-menu.dropdown-menu {
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
padding-right: 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]) {
|
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;
|
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 */
|
/* There is a little too much padding on form inputs */
|
||||||
.form-control {
|
.form-control {
|
||||||
padding-right: 0.75rem !important;
|
padding-right: 0.75rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-group-xs > .btn, .btn-xs {
|
.btn-group-xs>.btn,
|
||||||
|
.btn-xs {
|
||||||
padding: 0.25rem 0.4rem;
|
padding: 0.25rem 0.4rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 0.5;
|
line-height: 0.5;
|
||||||
|
|
@ -346,7 +375,7 @@ a:not([href]) {
|
||||||
font-size: 125%;
|
font-size: 125%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group > .form-control:focus {
|
.input-group>.form-control:focus {
|
||||||
z-index: inherit;
|
z-index: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,7 +413,7 @@ tr.dtrg-group {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Third party component customizations - toastr */
|
/* Third party component customizations - toastr */
|
||||||
#toast-container > div {
|
#toast-container>div {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
filter: alpha(opacity=100);
|
filter: alpha(opacity=100);
|
||||||
}
|
}
|
||||||
|
|
@ -397,7 +426,7 @@ tr.dtrg-group {
|
||||||
background-color: #dc3545;
|
background-color: #dc3545;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toast-container > div {
|
#toast-container>div {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -408,19 +437,19 @@ tr.dtrg-group {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Third party component customizations - SB Admin 2 */
|
/* 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 {
|
#mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse:after {
|
||||||
font-family: 'Font Awesome 5 Free';
|
font-family: 'Font Awesome 5 Free';
|
||||||
font-weight: 900;
|
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 {
|
#mainNav .navbar-collapse .navbar-sidenav .nav-link-collapse.py-0:after {
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mainNav .navbar-collapse .navbar-sidenav > .nav-item > .nav-link,
|
#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 .sidenav-second-level>li>a {
|
||||||
padding: 0.75em;
|
padding: 0.75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -460,7 +489,7 @@ html {
|
||||||
margin-left: -0.15em !important;
|
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;
|
padding-right: 1.25em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -603,7 +632,7 @@ canvas.drawingBuffer {
|
||||||
margin-bottom: -.65rem;
|
margin-bottom: -.65rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grocy-tabs.tab-content > .active {
|
.grocy-tabs.tab-content>.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
@ -615,7 +644,7 @@ canvas.drawingBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
.grocy-tabs.print.tab-content > .tab-pane {
|
.grocy-tabs.print.tab-content>.tab-pane {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
flex-direction: column !important;
|
flex-direction: column !important;
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
|
|
@ -625,7 +654,7 @@ canvas.drawingBuffer {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grocy-tabs.break > .tab-pane {
|
.grocy-tabs.break>.tab-pane {
|
||||||
page-break-after: always;
|
page-break-after: always;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -656,3 +685,9 @@ canvas.drawingBuffer {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.5;
|
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%;
|
||||||
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,72 +1,60 @@
|
||||||
$('#save-chore-button').on('click', function(e)
|
$('#save-chore-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonData = $('#chore-form').serializeJSON();
|
var jsonData = $('#chore-form').serializeJSON();
|
||||||
jsonData.start_date = Grocy.Components.DateTimePicker.GetValue();
|
jsonData.start_date = Grocy.Components.DateTimePicker.GetValue();
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS) {
|
||||||
{
|
|
||||||
jsonData.assignment_config = $("#assignment_config").val().join(",");
|
jsonData.assignment_config = $("#assignment_config").val().join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.BeginUiBusy("chore-form");
|
Grocy.FrontendHelpers.BeginUiBusy("chore-form");
|
||||||
|
|
||||||
if (Grocy.EditMode === 'create')
|
if (Grocy.EditMode === 'create') {
|
||||||
{
|
|
||||||
Grocy.Api.Post('objects/chores', jsonData,
|
Grocy.Api.Post('objects/chores', jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
Grocy.EditObjectId = result.created_object_id;
|
Grocy.EditObjectId = result.created_object_id;
|
||||||
Grocy.Components.UserfieldsForm.Save(function()
|
Grocy.Components.UserfieldsForm.Save(function() {
|
||||||
{
|
Grocy.Api.Post('chores/executions/calculate-next-assignments', {
|
||||||
Grocy.Api.Post('chores/executions/calculate-next-assignments', { "chore_id": Grocy.EditObjectId },
|
"chore_id": Grocy.EditObjectId
|
||||||
function(result)
|
},
|
||||||
{
|
function(result) {
|
||||||
window.location.href = U('/chores');
|
window.location.href = U('/chores');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("chore-form");
|
Grocy.FrontendHelpers.EndUiBusy("chore-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Api.Put('objects/chores/' + Grocy.EditObjectId, jsonData,
|
Grocy.Api.Put('objects/chores/' + Grocy.EditObjectId, jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
Grocy.Components.UserfieldsForm.Save(function() {
|
||||||
Grocy.Components.UserfieldsForm.Save(function()
|
Grocy.Api.Post('chores/executions/calculate-next-assignments', {
|
||||||
{
|
"chore_id": Grocy.EditObjectId
|
||||||
Grocy.Api.Post('chores/executions/calculate-next-assignments', { "chore_id": Grocy.EditObjectId },
|
},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
window.location.href = U('/chores');
|
window.location.href = U('/chores');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("chore-form");
|
Grocy.FrontendHelpers.EndUiBusy("chore-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||||
}
|
}
|
||||||
|
|
@ -74,13 +62,11 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#chore-form input').keyup(function(event)
|
$('#chore-form input').on('keyup', function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#chore-form input').keydown(function(event)
|
$('#chore-form input').on('keydown', function(event) {
|
||||||
{
|
|
||||||
if (event.keyCode === 13) //Enter
|
if (event.keyCode === 13) //Enter
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -88,58 +74,48 @@ $('#chore-form input').keydown(function(event)
|
||||||
if (document.getElementById('chore-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('chore-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#save-chore-button').click();
|
$('#save-chore-button').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var checkboxValues = $("#period_config").val().split(",");
|
var checkboxValues = $("#period_config").val().split(",");
|
||||||
for (var i = 0; i < checkboxValues.length; i++)
|
for (var i = 0; i < checkboxValues.length; i++) {
|
||||||
{
|
if (!checkboxValues[i].isEmpty()) {
|
||||||
if (!checkboxValues[i].isEmpty())
|
|
||||||
{
|
|
||||||
$("#" + checkboxValues[i]).prop('checked', true);
|
$("#" + checkboxValues[i]).prop('checked', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.UserfieldsForm.Load();
|
Grocy.Components.UserfieldsForm.Load();
|
||||||
$('#name').focus();
|
$('#name').trigger('focus');
|
||||||
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
||||||
|
|
||||||
if (Grocy.EditMode == "edit")
|
if (Grocy.EditMode == "edit") {
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/chores_log?limit=1&query[]=chore_id=' + Grocy.EditObjectId,
|
Grocy.Api.Get('objects/chores_log?limit=1&query[]=chore_id=' + Grocy.EditObjectId,
|
||||||
function(journalEntries)
|
function(journalEntries) {
|
||||||
{
|
if (journalEntries.length > 0) {
|
||||||
if (journalEntries.length > 0)
|
|
||||||
{
|
|
||||||
$(".datetimepicker-input").attr("disabled", "");
|
$(".datetimepicker-input").attr("disabled", "");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(function()
|
setTimeout(function() {
|
||||||
{
|
|
||||||
$(".input-group-chore-period-type").trigger("change");
|
$(".input-group-chore-period-type").trigger("change");
|
||||||
$(".input-group-chore-assignment-type").trigger("change");
|
$(".input-group-chore-assignment-type").trigger("change");
|
||||||
|
|
||||||
// Click twice to trigger on-click but not change the actual checked state
|
// Click twice to trigger on-click but not change the actual checked state
|
||||||
$("#consume_product_on_execution").click();
|
$("#consume_product_on_execution").trigger('click');
|
||||||
$("#consume_product_on_execution").click();
|
$("#consume_product_on_execution").trigger('click');
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
Grocy.Components.ProductPicker.Validate();
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
$('.input-group-chore-period-type').on('change keyup', function(e)
|
$('.input-group-chore-period-type').on('change keyup', function(e) {
|
||||||
{
|
|
||||||
var periodType = $('#period_type').val();
|
var periodType = $('#period_type').val();
|
||||||
var periodDays = $('#period_days').val();
|
var periodDays = $('#period_days').val();
|
||||||
var periodInterval = $('#period_interval').val();
|
var periodInterval = $('#period_interval').val();
|
||||||
|
|
@ -148,68 +124,49 @@ $('.input-group-chore-period-type').on('change keyup', function(e)
|
||||||
$(".period-type-" + periodType).removeClass("d-none");
|
$(".period-type-" + periodType).removeClass("d-none");
|
||||||
$("#period_config").val("");
|
$("#period_config").val("");
|
||||||
|
|
||||||
if (periodType === 'manually')
|
if (periodType === 'manually') {
|
||||||
{
|
|
||||||
$('#chore-schedule-info').text(__t('This means the next execution of this chore is not scheduled'));
|
$('#chore-schedule-info').text(__t('This means the next execution of this chore is not scheduled'));
|
||||||
}
|
} else if (periodType === 'hourly') {
|
||||||
else if (periodType === 'hourly')
|
|
||||||
{
|
|
||||||
$('#chore-schedule-info').text(__n(periodInterval, "This means the next execution of this chore is scheduled %s hour after the last execution", "This means the next execution of this chore is scheduled %s hours after the last execution"));
|
$('#chore-schedule-info').text(__n(periodInterval, "This means the next execution of this chore is scheduled %s hour after the last execution", "This means the next execution of this chore is scheduled %s hours after the last execution"));
|
||||||
}
|
} else if (periodType === 'daily') {
|
||||||
else if (periodType === 'daily')
|
|
||||||
{
|
|
||||||
$('#chore-schedule-info').text(__n(periodInterval, "This means the next execution of this chore is scheduled at the same time (based on the start date) every day", "This means the next execution of this chore is scheduled at the same time (based on the start date) every %s days"));
|
$('#chore-schedule-info').text(__n(periodInterval, "This means the next execution of this chore is scheduled at the same time (based on the start date) every day", "This means the next execution of this chore is scheduled at the same time (based on the start date) every %s days"));
|
||||||
}
|
} else if (periodType === 'weekly') {
|
||||||
else if (periodType === 'weekly')
|
|
||||||
{
|
|
||||||
$('#chore-schedule-info').text(__n(periodInterval, "This means the next execution of this chore is scheduled every week on the selected weekdays", "This means the next execution of this chore is scheduled every %s weeks on the selected weekdays"));
|
$('#chore-schedule-info').text(__n(periodInterval, "This means the next execution of this chore is scheduled every week on the selected weekdays", "This means the next execution of this chore is scheduled every %s weeks on the selected weekdays"));
|
||||||
$("#period_config").val($(".period-type-weekly input:checkbox:checked").map(function() { return this.value; }).get().join(","));
|
$("#period_config").val($(".period-type-weekly input:checkbox:checked").map(function() {
|
||||||
}
|
return this.value;
|
||||||
else if (periodType === 'monthly')
|
}).get().join(","));
|
||||||
{
|
} else if (periodType === 'monthly') {
|
||||||
$('#chore-schedule-info').text(__n(periodInterval, "This means the next execution of this chore is scheduled on the selected day every month", "This means the next execution of this chore is scheduled on the selected day every %s months"));
|
$('#chore-schedule-info').text(__n(periodInterval, "This means the next execution of this chore is scheduled on the selected day every month", "This means the next execution of this chore is scheduled on the selected day every %s months"));
|
||||||
$("label[for='period_days']").text(__t("Day of month"));
|
$("label[for='period_days']").text(__t("Day of month"));
|
||||||
$("#period_days").attr("min", "1");
|
$("#period_days").attr("min", "1");
|
||||||
$("#period_days").attr("max", "31");
|
$("#period_days").attr("max", "31");
|
||||||
}
|
} else if (periodType === 'yearly') {
|
||||||
else if (periodType === 'yearly')
|
|
||||||
{
|
|
||||||
$('#chore-schedule-info').text(__n(periodInterval, 'This means the next execution of this chore is scheduled every year on the same day (based on the start date)', 'This means the next execution of this chore is scheduled every %s years on the same day (based on the start date)'));
|
$('#chore-schedule-info').text(__n(periodInterval, 'This means the next execution of this chore is scheduled every year on the same day (based on the start date)', 'This means the next execution of this chore is scheduled every %s years on the same day (based on the start date)'));
|
||||||
}
|
} else if (periodType === 'adaptive') {
|
||||||
else if (periodType === 'adaptive')
|
|
||||||
{
|
|
||||||
$('#chore-schedule-info').text(__t('This means the next execution of this chore is scheduled dynamically based on the past average execution frequency'));
|
$('#chore-schedule-info').text(__t('This means the next execution of this chore is scheduled dynamically based on the past average execution frequency'));
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.input-group-chore-assignment-type').on('change', function(e)
|
$('.input-group-chore-assignment-type').on('change', function(e) {
|
||||||
{
|
|
||||||
var assignmentType = $('#assignment_type').val();
|
var assignmentType = $('#assignment_type').val();
|
||||||
|
|
||||||
$('#chore-period-assignment-info').text("");
|
$('#chore-period-assignment-info').text("");
|
||||||
$("#assignment_config").removeAttr("required");
|
$("#assignment_config").removeAttr("required");
|
||||||
$("#assignment_config").attr("disabled", "");
|
$("#assignment_config").attr("disabled", "");
|
||||||
|
|
||||||
if (assignmentType === 'no-assignment')
|
if (assignmentType === 'no-assignment') {
|
||||||
{
|
|
||||||
$('#chore-assignment-type-info').text(__t('This means the next execution of this chore will not be assigned to anyone'));
|
$('#chore-assignment-type-info').text(__t('This means the next execution of this chore will not be assigned to anyone'));
|
||||||
}
|
} else if (assignmentType === 'who-least-did-first') {
|
||||||
else if (assignmentType === 'who-least-did-first')
|
|
||||||
{
|
|
||||||
$('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned to the one who executed it least'));
|
$('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned to the one who executed it least'));
|
||||||
$("#assignment_config").attr("required", "");
|
$("#assignment_config").attr("required", "");
|
||||||
$("#assignment_config").removeAttr("disabled");
|
$("#assignment_config").removeAttr("disabled");
|
||||||
}
|
} else if (assignmentType === 'random') {
|
||||||
else if (assignmentType === 'random')
|
|
||||||
{
|
|
||||||
$('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned randomly'));
|
$('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned randomly'));
|
||||||
$("#assignment_config").attr("required", "");
|
$("#assignment_config").attr("required", "");
|
||||||
$("#assignment_config").removeAttr("disabled");
|
$("#assignment_config").removeAttr("disabled");
|
||||||
}
|
} else if (assignmentType === 'in-alphabetical-order') {
|
||||||
else if (assignmentType === 'in-alphabetical-order')
|
|
||||||
{
|
|
||||||
$('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned to the next one in alphabetical order'));
|
$('#chore-assignment-type-info').text(__t('This means the next execution of this chore will be assigned to the next one in alphabetical order'));
|
||||||
$("#assignment_config").attr("required", "");
|
$("#assignment_config").attr("required", "");
|
||||||
$("#assignment_config").removeAttr("disabled");
|
$("#assignment_config").removeAttr("disabled");
|
||||||
|
|
@ -218,15 +175,11 @@ $('.input-group-chore-assignment-type').on('change', function(e)
|
||||||
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
Grocy.FrontendHelpers.ValidateForm('chore-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#consume_product_on_execution").on("click", function()
|
$("#consume_product_on_execution").on("click", function() {
|
||||||
{
|
if (this.checked) {
|
||||||
if (this.checked)
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.Enable();
|
Grocy.Components.ProductPicker.Enable();
|
||||||
$("#product_amount").removeAttr("disabled");
|
$("#product_amount").removeAttr("disabled");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.Disable();
|
Grocy.Components.ProductPicker.Disable();
|
||||||
$("#product_amount").attr("disabled", "");
|
$("#product_amount").attr("disabled", "");
|
||||||
}
|
}
|
||||||
|
|
@ -234,35 +187,28 @@ $("#consume_product_on_execution").on("click", function()
|
||||||
Grocy.FrontendHelpers.ValidateForm("chore-form");
|
Grocy.FrontendHelpers.ValidateForm("chore-form");
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
{
|
|
||||||
var productId = $(e.target).val();
|
var productId = $(e.target).val();
|
||||||
|
|
||||||
if (productId)
|
if (productId) {
|
||||||
{
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
$('#amount_qu_unit').text(productDetails.quantity_unit_stock.name);
|
$('#amount_qu_unit').text(productDetails.quantity_unit_stock.name);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.chore-grocycode-label-print', function(e)
|
$(document).on('click', '.chore-grocycode-label-print', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
|
|
||||||
var choreId = $(e.currentTarget).attr('data-chore-id');
|
var choreId = $(e.currentTarget).attr('data-chore-id');
|
||||||
Grocy.Api.Get('chores/' + choreId + '/printlabel', function(labelData)
|
Grocy.Api.Get('chores/' + choreId + '/printlabel', function(labelData) {
|
||||||
{
|
if (Grocy.Webhooks.labelprinter !== undefined) {
|
||||||
if (Grocy.Webhooks.labelprinter !== undefined)
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, labelData);
|
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, labelData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,17 @@
|
||||||
Grocy.Components.BarcodeScanner = {};
|
Grocy.Components.BarcodeScanner = {};
|
||||||
|
|
||||||
Grocy.Components.BarcodeScanner.LiveVideoSizeAdjusted = false;
|
Grocy.Components.BarcodeScanner.LiveVideoSizeAdjusted = false;
|
||||||
Grocy.Components.BarcodeScanner.CheckCapabilities = async function()
|
Grocy.Components.BarcodeScanner.CheckCapabilities = async function() {
|
||||||
{
|
|
||||||
var track = Quagga.CameraAccess.getActiveTrack();
|
var track = Quagga.CameraAccess.getActiveTrack();
|
||||||
var capabilities = {};
|
var capabilities = {};
|
||||||
if (typeof track.getCapabilities === 'function')
|
if (typeof track.getCapabilities === 'function') {
|
||||||
{
|
|
||||||
capabilities = track.getCapabilities();
|
capabilities = track.getCapabilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is more than 1 camera, show the camera selection
|
// If there is more than 1 camera, show the camera selection
|
||||||
var cameras = await Quagga.CameraAccess.enumerateVideoDevices();
|
var cameras = await Quagga.CameraAccess.enumerateVideoDevices();
|
||||||
var cameraSelect = document.querySelector('.cameraSelect-wrapper');
|
var cameraSelect = document.querySelector('.cameraSelect-wrapper');
|
||||||
if (cameraSelect)
|
if (cameraSelect) {
|
||||||
{
|
|
||||||
cameraSelect.style.display = cameras.length > 1 ? 'inline-block' : 'none';
|
cameraSelect.style.display = cameras.length > 1 ? 'inline-block' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,29 +19,23 @@ Grocy.Components.BarcodeScanner.CheckCapabilities = async function()
|
||||||
var canTorch = typeof capabilities.torch === 'boolean' && capabilities.torch
|
var canTorch = typeof capabilities.torch === 'boolean' && capabilities.torch
|
||||||
// Remove the torch button, if either the device can not torch or AutoTorchOn is set.
|
// Remove the torch button, if either the device can not torch or AutoTorchOn is set.
|
||||||
var node = document.querySelector('.torch');
|
var node = document.querySelector('.torch');
|
||||||
if (node)
|
if (node) {
|
||||||
{
|
|
||||||
node.style.display = canTorch && !Grocy.FeatureFlags.GROCY_FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA ? 'inline-block' : 'none';
|
node.style.display = canTorch && !Grocy.FeatureFlags.GROCY_FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA ? 'inline-block' : 'none';
|
||||||
}
|
}
|
||||||
// If AutoTorchOn is set, turn on the torch.
|
// If AutoTorchOn is set, turn on the torch.
|
||||||
if (canTorch && Grocy.FeatureFlags.GROCY_FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA)
|
if (canTorch && Grocy.FeatureFlags.GROCY_FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA) {
|
||||||
{
|
|
||||||
Grocy.Components.BarcodeScanner.TorchOn(track);
|
Grocy.Components.BarcodeScanner.TorchOn(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce the height of the video, if it's higher than then the viewport
|
// Reduce the height of the video, if it's higher than then the viewport
|
||||||
if (!Grocy.Components.BarcodeScanner.LiveVideoSizeAdjusted)
|
if (!Grocy.Components.BarcodeScanner.LiveVideoSizeAdjusted) {
|
||||||
{
|
|
||||||
var bc = document.getElementById('barcodescanner-container');
|
var bc = document.getElementById('barcodescanner-container');
|
||||||
if (bc)
|
if (bc) {
|
||||||
{
|
|
||||||
var bcAspectRatio = bc.offsetWidth / bc.offsetHeight;
|
var bcAspectRatio = bc.offsetWidth / bc.offsetHeight;
|
||||||
var settings = track.getSettings();
|
var settings = track.getSettings();
|
||||||
if (bcAspectRatio > settings.aspectRatio)
|
if (bcAspectRatio > settings.aspectRatio) {
|
||||||
{
|
|
||||||
var v = document.querySelector('#barcodescanner-livestream video')
|
var v = document.querySelector('#barcodescanner-livestream video')
|
||||||
if (v)
|
if (v) {
|
||||||
{
|
|
||||||
var c = document.querySelector('#barcodescanner-livestream canvas')
|
var c = document.querySelector('#barcodescanner-livestream canvas')
|
||||||
var newWidth = v.clientWidth / bcAspectRatio * settings.aspectRatio + 'px';
|
var newWidth = v.clientWidth / bcAspectRatio * settings.aspectRatio + 'px';
|
||||||
v.style.width = newWidth;
|
v.style.width = newWidth;
|
||||||
|
|
@ -57,8 +48,7 @@ Grocy.Components.BarcodeScanner.CheckCapabilities = async function()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.BarcodeScanner.StartScanning = function()
|
Grocy.Components.BarcodeScanner.StartScanning = function() {
|
||||||
{
|
|
||||||
Grocy.Components.BarcodeScanner.DecodedCodesCount = 0;
|
Grocy.Components.BarcodeScanner.DecodedCodesCount = 0;
|
||||||
Grocy.Components.BarcodeScanner.DecodedCodesErrorCount = 0;
|
Grocy.Components.BarcodeScanner.DecodedCodesErrorCount = 0;
|
||||||
|
|
||||||
|
|
@ -69,7 +59,9 @@ Grocy.Components.BarcodeScanner.StartScanning = function()
|
||||||
target: document.querySelector("#barcodescanner-livestream"),
|
target: document.querySelector("#barcodescanner-livestream"),
|
||||||
constraints: {
|
constraints: {
|
||||||
facingMode: "environment",
|
facingMode: "environment",
|
||||||
...(window.localStorage.getItem('cameraId') && { deviceId: window.localStorage.getItem('cameraId') }) // If preferred cameraId is set, request to use that specific camera
|
...(window.localStorage.getItem('cameraId') && {
|
||||||
|
deviceId: window.localStorage.getItem('cameraId')
|
||||||
|
}) // If preferred cameraId is set, request to use that specific camera
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
locator: {
|
locator: {
|
||||||
|
|
@ -115,15 +107,12 @@ Grocy.Components.BarcodeScanner.StartScanning = function()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
locate: true
|
locate: true
|
||||||
}, function(error)
|
}, function(error) {
|
||||||
{
|
if (error) {
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ShowGenericError("Error while initializing the barcode scanning library", error.message);
|
Grocy.FrontendHelpers.ShowGenericError("Error while initializing the barcode scanning library", error.message);
|
||||||
toastr.info(__t("Camera access is only possible when supported and allowed by your browser and when grocy is served via a secure (https://) connection"));
|
toastr.info(__t("Camera access is only possible when supported and allowed by your browser and when grocy is served via a secure (https://) connection"));
|
||||||
window.localStorage.removeItem("cameraId");
|
window.localStorage.removeItem("cameraId");
|
||||||
setTimeout(function()
|
setTimeout(function() {
|
||||||
{
|
|
||||||
bootbox.hideAll();
|
bootbox.hideAll();
|
||||||
}, 500);
|
}, 500);
|
||||||
return;
|
return;
|
||||||
|
|
@ -135,8 +124,7 @@ Grocy.Components.BarcodeScanner.StartScanning = function()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.BarcodeScanner.StopScanning = function()
|
Grocy.Components.BarcodeScanner.StopScanning = function() {
|
||||||
{
|
|
||||||
Quagga.stop();
|
Quagga.stop();
|
||||||
|
|
||||||
Grocy.Components.BarcodeScanner.DecodedCodesCount = 0;
|
Grocy.Components.BarcodeScanner.DecodedCodesCount = 0;
|
||||||
|
|
@ -145,76 +133,77 @@ Grocy.Components.BarcodeScanner.StopScanning = function()
|
||||||
bootbox.hideAll();
|
bootbox.hideAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.BarcodeScanner.TorchOn = function(track)
|
Grocy.Components.BarcodeScanner.TorchOn = function(track) {
|
||||||
{
|
if (track) {
|
||||||
if (track)
|
|
||||||
{
|
|
||||||
track.applyConstraints({
|
track.applyConstraints({
|
||||||
advanced: [
|
advanced: [{
|
||||||
{
|
|
||||||
torch: true
|
torch: true
|
||||||
}
|
}]
|
||||||
]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Quagga.onDetected(function(result)
|
Quagga.onDetected(function(result) {
|
||||||
{
|
$.each(result.codeResult.decodedCodes, function(id, error) {
|
||||||
$.each(result.codeResult.decodedCodes, function(id, error)
|
if (error.error != undefined) {
|
||||||
{
|
|
||||||
if (error.error != undefined)
|
|
||||||
{
|
|
||||||
Grocy.Components.BarcodeScanner.DecodedCodesCount++;
|
Grocy.Components.BarcodeScanner.DecodedCodesCount++;
|
||||||
Grocy.Components.BarcodeScanner.DecodedCodesErrorCount += parseFloat(error.error);
|
Grocy.Components.BarcodeScanner.DecodedCodesErrorCount += parseFloat(error.error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if ((Grocy.Components.BarcodeScanner.DecodedCodesErrorCount / Grocy.Components.BarcodeScanner.DecodedCodesCount < 0.15) ||
|
if ((Grocy.Components.BarcodeScanner.DecodedCodesErrorCount / Grocy.Components.BarcodeScanner.DecodedCodesCount < 0.15) ||
|
||||||
(Grocy.Components.BarcodeScanner.DecodedCodesErrorCount == 0 && Grocy.Components.BarcodeScanner.DecodedCodesCount == 0 && result.codeResult.code.length != 0))
|
(Grocy.Components.BarcodeScanner.DecodedCodesErrorCount == 0 && Grocy.Components.BarcodeScanner.DecodedCodesCount == 0 && result.codeResult.code.length != 0)) {
|
||||||
{
|
|
||||||
Grocy.Components.BarcodeScanner.StopScanning();
|
Grocy.Components.BarcodeScanner.StopScanning();
|
||||||
$(document).trigger("Grocy.BarcodeScanned", [result.codeResult.code, Grocy.Components.BarcodeScanner.CurrentTarget]);
|
$(document).trigger("Grocy.BarcodeScanned", [result.codeResult.code, Grocy.Components.BarcodeScanner.CurrentTarget]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Quagga.onProcessed(function(result)
|
Quagga.onProcessed(function(result) {
|
||||||
{
|
|
||||||
var drawingCtx = Quagga.canvas.ctx.overlay;
|
var drawingCtx = Quagga.canvas.ctx.overlay;
|
||||||
var drawingCanvas = Quagga.canvas.dom.overlay;
|
var drawingCanvas = Quagga.canvas.dom.overlay;
|
||||||
|
|
||||||
if (result)
|
if (result) {
|
||||||
{
|
if (result.boxes) {
|
||||||
if (result.boxes)
|
|
||||||
{
|
|
||||||
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
|
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
|
||||||
result.boxes.filter(function(box)
|
result.boxes.filter(function(box) {
|
||||||
{
|
|
||||||
return box !== result.box;
|
return box !== result.box;
|
||||||
}).forEach(function(box)
|
}).forEach(function(box) {
|
||||||
{
|
Quagga.ImageDebug.drawPath(box, {
|
||||||
Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "yellow", lineWidth: 4 });
|
x: 0,
|
||||||
|
y: 1
|
||||||
|
}, drawingCtx, {
|
||||||
|
color: "yellow",
|
||||||
|
lineWidth: 4
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.box)
|
if (result.box) {
|
||||||
{
|
Quagga.ImageDebug.drawPath(result.box, {
|
||||||
Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 4 });
|
x: 0,
|
||||||
|
y: 1
|
||||||
|
}, drawingCtx, {
|
||||||
|
color: "green",
|
||||||
|
lineWidth: 4
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.codeResult && result.codeResult.code)
|
if (result.codeResult && result.codeResult.code) {
|
||||||
{
|
Quagga.ImageDebug.drawPath(result.line, {
|
||||||
Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: "red", lineWidth: 4 });
|
x: 'x',
|
||||||
|
y: 'y'
|
||||||
|
}, drawingCtx, {
|
||||||
|
color: "red",
|
||||||
|
lineWidth: 4
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("click", "#barcodescanner-start-button", async function(e)
|
$(document).on("click", "#barcodescanner-start-button", async function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var inputElement = $(e.currentTarget).prev();
|
var inputElement = $(e.currentTarget).prev();
|
||||||
if (inputElement.hasAttr("disabled"))
|
if (inputElement.hasAttr("disabled")) {
|
||||||
{
|
|
||||||
// Do nothing and disable the barcode scanner start button
|
// Do nothing and disable the barcode scanner start button
|
||||||
$(e.currentTarget).addClass("disabled");
|
$(e.currentTarget).addClass("disabled");
|
||||||
return;
|
return;
|
||||||
|
|
@ -225,8 +214,7 @@ $(document).on("click", "#barcodescanner-start-button", async function(e)
|
||||||
var dialog = bootbox.dialog({
|
var dialog = bootbox.dialog({
|
||||||
message: '<div id="barcodescanner-container" class="col"><div id="barcodescanner-livestream"></div></div>',
|
message: '<div id="barcodescanner-container" class="col"><div id="barcodescanner-livestream"></div></div>',
|
||||||
title: __t('Scan a barcode'),
|
title: __t('Scan a barcode'),
|
||||||
onEscape: function()
|
onEscape: function() {
|
||||||
{
|
|
||||||
Grocy.Components.BarcodeScanner.StopScanning();
|
Grocy.Components.BarcodeScanner.StopScanning();
|
||||||
},
|
},
|
||||||
size: 'big',
|
size: 'big',
|
||||||
|
|
@ -236,8 +224,7 @@ $(document).on("click", "#barcodescanner-start-button", async function(e)
|
||||||
torch: {
|
torch: {
|
||||||
label: '<i class="far fa-lightbulb"></i>',
|
label: '<i class="far fa-lightbulb"></i>',
|
||||||
className: 'btn-warning responsive-button torch',
|
className: 'btn-warning responsive-button torch',
|
||||||
callback: function()
|
callback: function() {
|
||||||
{
|
|
||||||
Grocy.Components.BarcodeScanner.TorchOn(Quagga.CameraAccess.getActiveTrack());
|
Grocy.Components.BarcodeScanner.TorchOn(Quagga.CameraAccess.getActiveTrack());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -245,8 +232,7 @@ $(document).on("click", "#barcodescanner-start-button", async function(e)
|
||||||
cancel: {
|
cancel: {
|
||||||
label: __t('Cancel'),
|
label: __t('Cancel'),
|
||||||
className: 'btn-secondary responsive-button',
|
className: 'btn-secondary responsive-button',
|
||||||
callback: function()
|
callback: function() {
|
||||||
{
|
|
||||||
Grocy.Components.BarcodeScanner.StopScanning();
|
Grocy.Components.BarcodeScanner.StopScanning();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,8 +244,7 @@ $(document).on("click", "#barcodescanner-start-button", async function(e)
|
||||||
var cameraSelect = document.querySelector('.cameraSelect');
|
var cameraSelect = document.querySelector('.cameraSelect');
|
||||||
|
|
||||||
var cameras = await Quagga.CameraAccess.enumerateVideoDevices();
|
var cameras = await Quagga.CameraAccess.enumerateVideoDevices();
|
||||||
cameras.forEach(camera =>
|
cameras.forEach(camera => {
|
||||||
{
|
|
||||||
var option = document.createElement("option");
|
var option = document.createElement("option");
|
||||||
option.text = camera.label ? camera.label : camera.deviceId; // Use camera label if it exists, else show device id
|
option.text = camera.label ? camera.label : camera.deviceId; // Use camera label if it exists, else show device id
|
||||||
option.value = camera.deviceId;
|
option.value = camera.deviceId;
|
||||||
|
|
@ -269,8 +254,7 @@ $(document).on("click", "#barcodescanner-start-button", async function(e)
|
||||||
// Set initial value to preferred camera if one exists - and if not, start out empty
|
// Set initial value to preferred camera if one exists - and if not, start out empty
|
||||||
cameraSelect.value = window.localStorage.getItem('cameraId');
|
cameraSelect.value = window.localStorage.getItem('cameraId');
|
||||||
|
|
||||||
cameraSelect.onchange = function()
|
cameraSelect.onchange = function() {
|
||||||
{
|
|
||||||
window.localStorage.setItem('cameraId', cameraSelect.value);
|
window.localStorage.setItem('cameraId', cameraSelect.value);
|
||||||
Quagga.stop();
|
Quagga.stop();
|
||||||
Grocy.Components.BarcodeScanner.StartScanning();
|
Grocy.Components.BarcodeScanner.StartScanning();
|
||||||
|
|
@ -280,29 +264,25 @@ $(document).on("click", "#barcodescanner-start-button", async function(e)
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.BarcodeScanner.InitDone = false;
|
Grocy.Components.BarcodeScanner.InitDone = false;
|
||||||
Grocy.Components.BarcodeScanner.Init = function()
|
Grocy.Components.BarcodeScanner.Init = function() {
|
||||||
{
|
if (Grocy.Components.BarcodeScanner.InitDone) {
|
||||||
if (Grocy.Components.BarcodeScanner.InitDone)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".barcodescanner-input:visible").each(function()
|
$(".barcodescanner-input:visible").each(function() {
|
||||||
{
|
var isSelect2 = $(this).hasClass('select2') && $(this).parent().hasClass('input-group');
|
||||||
if ($(this).hasAttr("disabled"))
|
var html = '<a id="barcodescanner-start-button" class="btn' + (isSelect2 ? '' : ' btn-sm') + ' btn-primary text-white' + ($(this).hasAttr("disabled") ? ' disabled' : '') + '" data-target="' + $(this).attr("data-target") + '"><i class="fas fa-camera"></i></a>';
|
||||||
{
|
if (isSelect2) {
|
||||||
$(this).after('<a id="barcodescanner-start-button" class="btn btn-sm btn-primary text-white disabled" data-target="' + $(this).attr("data-target") + '"><i class="fas fa-camera"></i></a>');
|
html = '<div class="input-group-prepend" id="barcodescanner-start-button-container">' + html + '</div>'
|
||||||
}
|
$(this).parent().prepend(html);
|
||||||
else
|
} else {
|
||||||
{
|
$(this).after(html);
|
||||||
$(this).after('<a id="barcodescanner-start-button" class="btn btn-sm btn-primary text-white" data-target="' + $(this).attr("data-target") + '"><i class="fas fa-camera"></i></a>');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.BarcodeScanner.InitDone = true;
|
Grocy.Components.BarcodeScanner.InitDone = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(function()
|
setTimeout(function() {
|
||||||
{
|
|
||||||
Grocy.Components.BarcodeScanner.Init();
|
Grocy.Components.BarcodeScanner.Init();
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
|
||||||
|
|
@ -1,195 +1,341 @@
|
||||||
Grocy.Components.ProductPicker = {};
|
Grocy.Components.ProductPicker = {};
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker = function()
|
Grocy.Components.ProductPicker.GetPicker = function() {
|
||||||
{
|
|
||||||
return $('#product_id');
|
return $('#product_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement = function()
|
Grocy.Components.ProductPicker.GetValue = function() {
|
||||||
{
|
return this.GetPicker().val();
|
||||||
return $('#product_id_text_input');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetValue = function()
|
Grocy.Components.ProductPicker.GetOption = function(key) {
|
||||||
{
|
return this.GetPicker().parents('.form-group').data(key);
|
||||||
return $('#product_id').val();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.SetValue = function(value)
|
Grocy.Components.ProductPicker.GetState = function(key) {
|
||||||
{
|
return this.GetPicker().data(key);
|
||||||
Grocy.Components.ProductPicker.GetInputElement().val(value);
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().trigger('change');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.SetId = function(value)
|
Grocy.Components.ProductPicker.SetState = function(key, value) {
|
||||||
{
|
this.GetPicker().data(key, value);
|
||||||
Grocy.Components.ProductPicker.GetPicker().val(value);
|
return this;
|
||||||
Grocy.Components.ProductPicker.GetPicker().data('combobox').refresh();
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().trigger('change');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.Clear = function()
|
Grocy.Components.ProductPicker.SetId = function(value, callback) {
|
||||||
{
|
if (this.GetPicker().find('option[value="' + value + '"]').length) {
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
this.GetPicker().val(value).trigger('change');
|
||||||
Grocy.Components.ProductPicker.SetId(null);
|
} else {
|
||||||
|
Grocy.Api.Get('objects/products/' + encodeURIComponent(value),
|
||||||
|
function(result) {
|
||||||
|
var option = new Option(result.name, value, true, true);
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
Grocy.Components.ProductPicker.GetPicker().one('change.select2', callback);
|
||||||
|
}
|
||||||
|
Grocy.Components.ProductPicker.GetPicker().append(option).trigger('change').select2('close');
|
||||||
|
},
|
||||||
|
function(xhr) {
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.InProductAddWorkflow = function()
|
Grocy.Components.ProductPicker.Clear = function() {
|
||||||
{
|
this.GetPicker().val(null).trigger('change');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.Components.ProductPicker.InProductAddWorkflow = function() {
|
||||||
return GetUriParam('flow') == "InplaceNewProductWithName";
|
return GetUriParam('flow') == "InplaceNewProductWithName";
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.InProductModifyWorkflow = function()
|
Grocy.Components.ProductPicker.InProductModifyWorkflow = function() {
|
||||||
{
|
|
||||||
return GetUriParam('flow') == "InplaceAddBarcodeToExistingProduct";
|
return GetUriParam('flow') == "InplaceAddBarcodeToExistingProduct";
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.InAnyFlow = function()
|
Grocy.Components.ProductPicker.InAnyFlow = function() {
|
||||||
{
|
return GetUriParam('flow') !== undefined;
|
||||||
return Grocy.Components.ProductPicker.InProductAddWorkflow() || Grocy.Components.ProductPicker.InProductModifyWorkflow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.FinishFlow = function()
|
Grocy.Components.ProductPicker.FinishFlow = function() {
|
||||||
{
|
|
||||||
RemoveUriParam("flow");
|
RemoveUriParam("flow");
|
||||||
RemoveUriParam("barcode");
|
RemoveUriParam("barcode");
|
||||||
RemoveUriParam("product-name");
|
RemoveUriParam("product-name");
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.ShowCustomError = function(text)
|
Grocy.Components.ProductPicker.ShowCustomError = function(text) {
|
||||||
{
|
|
||||||
var element = $("#custom-productpicker-error");
|
var element = $("#custom-productpicker-error");
|
||||||
element.text(text);
|
element.text(text);
|
||||||
element.removeClass("d-none");
|
element.removeClass("d-none");
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.HideCustomError = function()
|
Grocy.Components.ProductPicker.HideCustomError = function() {
|
||||||
{
|
|
||||||
$("#custom-productpicker-error").addClass("d-none");
|
$("#custom-productpicker-error").addClass("d-none");
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.Disable = function()
|
Grocy.Components.ProductPicker.Disable = function() {
|
||||||
{
|
this.GetPicker().prop("disabled", true);
|
||||||
Grocy.Components.ProductPicker.GetInputElement().attr("disabled", "");
|
|
||||||
$("#barcodescanner-start-button").attr("disabled", "");
|
$("#barcodescanner-start-button").attr("disabled", "");
|
||||||
$("#barcodescanner-start-button").addClass("disabled");
|
$("#barcodescanner-start-button").addClass("disabled");
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.Enable = function()
|
Grocy.Components.ProductPicker.Enable = function() {
|
||||||
{
|
this.GetPicker().prop("disabled", false);
|
||||||
Grocy.Components.ProductPicker.GetInputElement().removeAttr("disabled");
|
|
||||||
$("#barcodescanner-start-button").removeAttr("disabled");
|
$("#barcodescanner-start-button").removeAttr("disabled");
|
||||||
$("#barcodescanner-start-button").removeClass("disabled");
|
$("#barcodescanner-start-button").removeClass("disabled");
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.product-combobox').combobox({
|
Grocy.Components.ProductPicker.Require = function() {
|
||||||
appendId: '_text_input',
|
this.GetPicker().prop("required", true);
|
||||||
bsVersion: '4',
|
return this;
|
||||||
clearIfNoMatch: false
|
}
|
||||||
|
|
||||||
|
Grocy.Components.ProductPicker.Optional = function() {
|
||||||
|
this.GetPicker().prop("required", false);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.Components.ProductPicker.Focus = function() {
|
||||||
|
this.GetPicker().select2('open');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.Components.ProductPicker.Validate = function() {
|
||||||
|
this.GetPicker().trigger('change');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.Components.ProductPicker.OnChange = function(eventHandler) {
|
||||||
|
this.GetPicker().on('change', eventHandler);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.Components.ProductPicker.Search = function(term, callback) {
|
||||||
|
var $picker = this.GetPicker();
|
||||||
|
var doSearch = function() {
|
||||||
|
var $search = $picker.data('select2').dropdown.$search || $picker.data('select2').selection.$search;
|
||||||
|
$search.val(term).trigger('input');
|
||||||
|
// must wait for debounce before listening for 'results:all' event
|
||||||
|
setTimeout(function() {
|
||||||
|
$picker.one('Grocy.ResultsUpdated', function() {
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
$picker.one('select2:close', callback);
|
||||||
|
}
|
||||||
|
$picker.select2('close');
|
||||||
|
});
|
||||||
|
}, 150);
|
||||||
|
};
|
||||||
|
if ($picker.data('select2').isOpen()) {
|
||||||
|
doSearch();
|
||||||
|
} else {
|
||||||
|
$picker.one('select2:open', doSearch);
|
||||||
|
$picker.select2('open');
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.Components.ProductPicker.IsOpen = function() {
|
||||||
|
return this.GetPicker().parent().find('.select2-container').hasClass('select2-container--open');
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize Select2 product picker
|
||||||
|
var lastProductSearchTerm = '';
|
||||||
|
Grocy.Components.ProductPicker.GetPicker().select2({
|
||||||
|
selectOnClose: true,
|
||||||
|
ajax: {
|
||||||
|
delay: 150,
|
||||||
|
transport: function(params, success, failure) {
|
||||||
|
var results_per_page = 10;
|
||||||
|
var page = params.data.page || 1;
|
||||||
|
var term = params.data.term || "";
|
||||||
|
var termIsGrocycode = term.startsWith("grcy");
|
||||||
|
lastProductSearchTerm = term;
|
||||||
|
|
||||||
|
// reset grocycode/barcode state
|
||||||
|
Grocy.Components.ProductPicker.SetState('barcode', 'null');
|
||||||
|
Grocy.Components.ProductPicker.SetState('grocycode', false);
|
||||||
|
|
||||||
|
// build search queries
|
||||||
|
var baseQuery = Grocy.Components.ProductPicker.GetOption('products-query').split('&');
|
||||||
|
baseQuery.push('limit=' + encodeURIComponent(results_per_page));
|
||||||
|
baseQuery.push('offset=' + encodeURIComponent((page - 1) * results_per_page));
|
||||||
|
var queries = [];
|
||||||
|
if (term.length > 0) {
|
||||||
|
queries = [
|
||||||
|
// search product fields (name, etc.)
|
||||||
|
baseQuery.concat('search=' + encodeURIComponent(term)).join('&'),
|
||||||
|
];
|
||||||
|
// grocycode handling
|
||||||
|
if (termIsGrocycode) {
|
||||||
|
var gc = term.split(":");
|
||||||
|
if (gc[1] == "p") {
|
||||||
|
queries.push(baseQuery.concat('query%5B%5D=id%3D' + encodeURIComponent(gc[2])).join('&'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
queries = [baseQuery.join('&')];
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute all queries in parallel, return first non-empty response
|
||||||
|
var complete = 0;
|
||||||
|
var responded = false;
|
||||||
|
var xhrs = [];
|
||||||
|
var handleEmptyResponse = function() {
|
||||||
|
if (responded || complete < xhrs.length) return;
|
||||||
|
success({
|
||||||
|
results: [],
|
||||||
|
pagination: {
|
||||||
|
more: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var handleResponse = function(results, meta, cur_xhr) {
|
||||||
|
// track complete queries
|
||||||
|
complete++;
|
||||||
|
|
||||||
|
// abort if we already responded
|
||||||
|
if (responded) return;
|
||||||
|
|
||||||
|
// abort if no results
|
||||||
|
if (results.length === 0) {
|
||||||
|
handleEmptyResponse();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// track whether we have responded
|
||||||
|
responded = true;
|
||||||
|
|
||||||
|
// abort all other queries
|
||||||
|
xhrs.forEach(function(xhr) {
|
||||||
|
if (xhr !== cur_xhr) xhr.abort();
|
||||||
|
});
|
||||||
|
|
||||||
|
// update grocycode/barcode state
|
||||||
|
Grocy.Components.ProductPicker.SetState('grocycode', termIsGrocycode);
|
||||||
|
Grocy.Components.ProductPicker.SetState('barcode', term);
|
||||||
|
|
||||||
|
success({
|
||||||
|
results: results.map(function(result) {
|
||||||
|
return {
|
||||||
|
id: result.id,
|
||||||
|
text: result.name
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
pagination: {
|
||||||
|
more: page * results_per_page < meta.recordsFiltered
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var handleErrors = function(xhr) {
|
||||||
|
console.error(xhr);
|
||||||
|
|
||||||
|
// track complete queries
|
||||||
|
complete++;
|
||||||
|
|
||||||
|
// abort if we already responded
|
||||||
|
if (responded) return;
|
||||||
|
|
||||||
|
handleEmptyResponse();
|
||||||
|
};
|
||||||
|
if (term.length > 0) {
|
||||||
|
xhrs.push(Grocy.Api.Get('objects/product_barcodes?limit=1&query%5B%5D=barcode%3D' + encodeURIComponent(term),
|
||||||
|
function(results, meta) {
|
||||||
|
// track complete queries
|
||||||
|
complete++;
|
||||||
|
|
||||||
|
// abort if we already responded
|
||||||
|
if (responded) return;
|
||||||
|
|
||||||
|
// abort if no results
|
||||||
|
if (results.length === 0) {
|
||||||
|
handleEmptyResponse();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cur_xhr = Grocy.Api.Get('objects/products?' + baseQuery.concat('query%5B%5D=id%3D' + encodeURIComponent(results[0].product_id)).join('&'),
|
||||||
|
function(results, meta) {
|
||||||
|
handleResponse(results, meta, cur_xhr);
|
||||||
|
},
|
||||||
|
handleErrors
|
||||||
|
);
|
||||||
|
xhrs.push(cur_xhr);
|
||||||
|
},
|
||||||
|
handleErrors
|
||||||
|
));
|
||||||
|
}
|
||||||
|
xhrs = xhrs.concat(queries.map(function(query) {
|
||||||
|
var cur_xhr = Grocy.Api.Get('objects/products' + (query.length > 0 ? '?' + query : ''),
|
||||||
|
function(results, meta) {
|
||||||
|
handleResponse(results, meta, cur_xhr);
|
||||||
|
},
|
||||||
|
handleErrors
|
||||||
|
);
|
||||||
|
return cur_xhr;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var prefillProduct = GetUriParam('product-name');
|
// forward 'results:all' event
|
||||||
var prefillProduct2 = Grocy.Components.ProductPicker.GetPicker().parent().data('prefill-by-name').toString();
|
Grocy.Components.ProductPicker.GetPicker().data('select2').on('results:all', function(data) {
|
||||||
if (!prefillProduct2.isEmpty())
|
Grocy.Components.ProductPicker.GetPicker().trigger('Grocy.ResultsUpdated', data);
|
||||||
{
|
});
|
||||||
prefillProduct = prefillProduct2;
|
|
||||||
}
|
|
||||||
if (typeof prefillProduct !== "undefined")
|
|
||||||
{
|
|
||||||
var possibleOptionElement = $("#product_id option[data-additional-searchdata*=\"" + prefillProduct + "\"]").first();
|
|
||||||
if (possibleOptionElement.length === 0)
|
|
||||||
{
|
|
||||||
possibleOptionElement = $("#product_id option:contains(\"" + prefillProduct + "\")").first();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (possibleOptionElement.length > 0)
|
// handle barcode scanning
|
||||||
{
|
$(document).on("Grocy.BarcodeScanned", function(e, barcode, target) {
|
||||||
$('#product_id').val(possibleOptionElement.val());
|
// check that the barcode scan is for the product picker
|
||||||
$('#product_id').data('combobox').refresh();
|
if (!(target == "@productpicker" || target == "undefined" || target == undefined)) return;
|
||||||
$('#product_id').trigger('change');
|
|
||||||
|
|
||||||
var nextInputElement = $(Grocy.Components.ProductPicker.GetPicker().parent().data('next-input-selector').toString());
|
Grocy.Components.ProductPicker.Search(barcode);
|
||||||
nextInputElement.focus();
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var prefillProductId = GetUriParam("product");
|
// fix placement of bootbox footer buttons
|
||||||
var prefillProductId2 = Grocy.Components.ProductPicker.GetPicker().parent().data('prefill-by-id').toString();
|
$(document).on("shown.bs.modal", function() {
|
||||||
if (!prefillProductId2.isEmpty())
|
$(".modal-footer").addClass("d-block").addClass("d-sm-flex");
|
||||||
{
|
$(".modal-footer").find("button").addClass("mt-2").addClass("mt-sm-0");
|
||||||
prefillProductId = prefillProductId2;
|
});
|
||||||
}
|
|
||||||
if (typeof prefillProductId !== "undefined")
|
|
||||||
{
|
|
||||||
$('#product_id').val(prefillProductId);
|
|
||||||
$('#product_id').data('combobox').refresh();
|
|
||||||
$('#product_id').trigger('change');
|
|
||||||
|
|
||||||
var nextInputElement = $(Grocy.Components.ProductPicker.GetPicker().parent().data('next-input-selector').toString());
|
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct") {
|
||||||
nextInputElement.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct")
|
|
||||||
{
|
|
||||||
$('#InplaceAddBarcodeToExistingProduct').text(GetUriParam("barcode"));
|
$('#InplaceAddBarcodeToExistingProduct').text(GetUriParam("barcode"));
|
||||||
$('#flow-info-InplaceAddBarcodeToExistingProduct').removeClass('d-none');
|
$('#flow-info-InplaceAddBarcodeToExistingProduct').removeClass('d-none');
|
||||||
$('#barcode-lookup-disabled-hint').removeClass('d-none');
|
$('#barcode-lookup-disabled-hint').removeClass('d-none');
|
||||||
$('#barcode-lookup-hint').addClass('d-none');
|
$('#barcode-lookup-hint').addClass('d-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prefill by name
|
||||||
|
var prefillProduct = Grocy.Components.ProductPicker.GetOption('prefill-by-name') || GetUriParam('product-name');
|
||||||
|
if (typeof prefillProduct === 'string' && !prefillProduct.isEmpty()) {
|
||||||
|
Grocy.Components.ProductPicker.Search(prefillProduct, function() {
|
||||||
|
$(Grocy.Components.ProductPicker.GetOption('next-input-selector')).trigger('focus');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefill by ID
|
||||||
|
var prefillProduct = Grocy.Components.ProductPicker.GetOption('prefill-by-id') || GetUriParam('product');
|
||||||
|
if (typeof prefillProduct === 'string' && !prefillProduct.isEmpty()) {
|
||||||
|
Grocy.Components.ProductPicker.SetId(prefillProduct, function() {
|
||||||
|
$(Grocy.Components.ProductPicker.GetOption('next-input-selector')).trigger('focus');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// open create product/barcode dialog if no results
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
$('#product_id_text_input').on('blur', function(e)
|
Grocy.Components.ProductPicker.GetPicker().on('select2:close', function() {
|
||||||
{
|
if (Grocy.Components.ProductPicker.PopupOpen || Grocy.Components.ProductPicker.GetPicker().select2('data').length > 0) return;
|
||||||
if (Grocy.Components.ProductPicker.GetPicker().hasClass("combobox-menu-visible"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$('#product_id').attr("barcode", "null");
|
|
||||||
|
|
||||||
var input = $('#product_id_text_input').val().toString();
|
|
||||||
var possibleOptionElement = [];
|
|
||||||
|
|
||||||
// grocycode handling
|
|
||||||
if (input.startsWith("grcy"))
|
|
||||||
{
|
|
||||||
var gc = input.split(":");
|
|
||||||
if (gc[1] == "p")
|
|
||||||
{
|
|
||||||
possibleOptionElement = $("#product_id option[value=\"" + gc[2] + "\"]").first();
|
|
||||||
$("#product_id").data("grocycode", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // Normal product barcode handling
|
|
||||||
{
|
|
||||||
possibleOptionElement = $("#product_id option[data-additional-searchdata*=\"" + input + ",\"]").first();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetUriParam('flow') === undefined && input.length > 0 && possibleOptionElement.length > 0)
|
|
||||||
{
|
|
||||||
$('#product_id').val(possibleOptionElement.val());
|
|
||||||
$('#product_id').attr("barcode", input);
|
|
||||||
$('#product_id').data('combobox').refresh();
|
|
||||||
$('#product_id').trigger('change');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Grocy.Components.ProductPicker.PopupOpen === true)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var optionElement = $("#product_id option:contains(\"" + input + "\")").first();
|
|
||||||
if (input.length > 0 && optionElement.length === 0 && GetUriParam('flow') === undefined && Grocy.Components.ProductPicker.GetPicker().parent().data('disallow-all-product-workflows').toString() === "false")
|
|
||||||
{
|
|
||||||
var addProductWorkflowsAdditionalCssClasses = "";
|
var addProductWorkflowsAdditionalCssClasses = "";
|
||||||
if (Grocy.Components.ProductPicker.GetPicker().parent().data('disallow-add-product-workflows').toString() === "true")
|
if (Grocy.Components.ProductPicker.GetOption('disallow-add-product-workflows')) {
|
||||||
{
|
|
||||||
addProductWorkflowsAdditionalCssClasses = "d-none";
|
addProductWorkflowsAdditionalCssClasses = "d-none";
|
||||||
}
|
}
|
||||||
|
|
||||||
var embedded = "";
|
var embedded = "";
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
embedded = "embedded";
|
embedded = "embedded";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,58 +343,51 @@ $('#product_id_text_input').on('blur', function(e)
|
||||||
cancel: {
|
cancel: {
|
||||||
label: __t('Cancel'),
|
label: __t('Cancel'),
|
||||||
className: 'btn-secondary responsive-button',
|
className: 'btn-secondary responsive-button',
|
||||||
callback: function()
|
callback: function() {
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
Grocy.Components.ProductPicker.Clear();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addnewproduct: {
|
addnewproduct: {
|
||||||
label: '<strong>P</strong> ' + __t('Add as new product'),
|
label: '<strong>P</strong> ' + __t('Add as new product'),
|
||||||
className: 'btn-success add-new-product-dialog-button responsive-button ' + addProductWorkflowsAdditionalCssClasses,
|
className: 'btn-success add-new-product-dialog-button responsive-button ' + addProductWorkflowsAdditionalCssClasses,
|
||||||
callback: function()
|
callback: function() {
|
||||||
{
|
|
||||||
// Not the best place here - this is only relevant when this flow is started from the shopping list item form
|
// Not the best place here - this is only relevant when this flow is started from the shopping list item form
|
||||||
// (to select the correct shopping list on return)
|
// (to select the correct shopping list on return)
|
||||||
if (GetUriParam("list") !== undefined)
|
if (GetUriParam("list") !== undefined) {
|
||||||
{
|
|
||||||
embedded += "&list=" + GetUriParam("list");
|
embedded += "&list=" + GetUriParam("list");
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
window.location.href = U('/product/new?flow=InplaceNewProductWithName&name=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(Grocy.CurrentUrlRelative + "?flow=InplaceNewProductWithName&" + embedded) + "&" + embedded);
|
window.location.href = U('/product/new?flow=InplaceNewProductWithName&name=' + encodeURIComponent(lastProductSearchTerm) + '&returnto=' + encodeURIComponent(Grocy.CurrentUrlRelative + "?flow=InplaceNewProductWithName&" + embedded) + "&" + embedded);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addbarcode: {
|
addbarcode: {
|
||||||
label: '<strong>B</strong> ' + __t('Add as barcode to existing product'),
|
label: '<strong>B</strong> ' + __t('Add as barcode to existing product'),
|
||||||
className: 'btn-info add-new-barcode-dialog-button responsive-button',
|
className: 'btn-info add-new-barcode-dialog-button responsive-button',
|
||||||
callback: function()
|
callback: function() {
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
window.location.href = U(Grocy.CurrentUrlRelative + '?flow=InplaceAddBarcodeToExistingProduct&barcode=' + encodeURIComponent(input) + "&" + embedded);
|
window.location.href = U(Grocy.CurrentUrlRelative + '?flow=InplaceAddBarcodeToExistingProduct&barcode=' + encodeURIComponent(lastProductSearchTerm) + "&" + embedded);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addnewproductwithbarcode: {
|
addnewproductwithbarcode: {
|
||||||
label: '<strong>A</strong> ' + __t('Add as new product and prefill barcode'),
|
label: '<strong>A</strong> ' + __t('Add as new product and prefill barcode'),
|
||||||
className: 'btn-warning add-new-product-with-barcode-dialog-button responsive-button ' + addProductWorkflowsAdditionalCssClasses,
|
className: 'btn-warning add-new-product-with-barcode-dialog-button responsive-button ' + addProductWorkflowsAdditionalCssClasses,
|
||||||
callback: function()
|
callback: function() {
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
window.location.href = U('/product/new?flow=InplaceNewProductWithBarcode&barcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(Grocy.CurrentUrlRelative + "?flow=InplaceAddBarcodeToExistingProduct&barcode=" + input + "&" + embedded) + "&" + embedded);
|
window.location.href = U('/product/new?flow=InplaceNewProductWithBarcode&barcode=' + encodeURIComponent(lastProductSearchTerm) + '&returnto=' + encodeURIComponent(Grocy.CurrentUrlRelative + "?flow=InplaceAddBarcodeToExistingProduct&barcode=" + lastProductSearchTerm + "&" + embedded) + "&" + embedded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_DISABLE_BROWSER_BARCODE_CAMERA_SCANNING)
|
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_DISABLE_BROWSER_BARCODE_CAMERA_SCANNING) {
|
||||||
{
|
|
||||||
buttons.retrycamerascanning = {
|
buttons.retrycamerascanning = {
|
||||||
label: '<strong>C</strong> <i class="fas fa-camera"></i>',
|
label: '<strong>C</strong> <i class="fas fa-camera"></i>',
|
||||||
className: 'btn-primary responsive-button retry-camera-scanning-button',
|
className: 'btn-primary responsive-button retry-camera-scanning-button',
|
||||||
callback: function()
|
callback: function() {
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
Grocy.Components.ProductPicker.Clear();
|
||||||
$("#barcodescanner-start-button").click();
|
$("#barcodescanner-start-button").trigger('click');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -259,119 +398,60 @@ $('#product_id_text_input').on('blur', function(e)
|
||||||
// otherwise an error validation message that the product is not in stock
|
// otherwise an error validation message that the product is not in stock
|
||||||
var existsAsProduct = false;
|
var existsAsProduct = false;
|
||||||
var existsAsBarcode = false;
|
var existsAsBarcode = false;
|
||||||
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + input,
|
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + lastProductSearchTerm,
|
||||||
function(barcodeResult)
|
function(barcodeResult) {
|
||||||
{
|
if (barcodeResult.length > 0) {
|
||||||
if (barcodeResult.length > 0)
|
|
||||||
{
|
|
||||||
existsAsProduct = true;
|
existsAsProduct = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Get('objects/products?query[]=name=' + input,
|
Grocy.Api.Get('objects/products?query[]=name=' + lastProductSearchTerm,
|
||||||
function(productResult)
|
function(productResult) {
|
||||||
{
|
if (productResult.length > 0) {
|
||||||
if (productResult.length > 0)
|
|
||||||
{
|
|
||||||
existsAsProduct = true;
|
existsAsProduct = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!existsAsBarcode && !existsAsProduct)
|
if (!existsAsBarcode && !existsAsProduct) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = true;
|
Grocy.Components.ProductPicker.PopupOpen = true;
|
||||||
bootbox.dialog({
|
bootbox.dialog({
|
||||||
message: __t('"%s" could not be resolved to a product, how do you want to proceed?', input),
|
message: __t('"%s" could not be resolved to a product, how do you want to proceed?', lastProductSearchTerm),
|
||||||
title: __t('Create or assign product'),
|
title: __t('Create or assign product'),
|
||||||
onEscape: function()
|
onEscape: function() {
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
Grocy.Components.ProductPicker.Clear();
|
||||||
},
|
},
|
||||||
size: 'large',
|
size: 'large',
|
||||||
backdrop: true,
|
backdrop: true,
|
||||||
closeButton: false,
|
closeButton: false,
|
||||||
buttons: buttons
|
buttons: buttons
|
||||||
}).on('keypress', function(e)
|
}).on('keypress', function(e) {
|
||||||
{
|
if (e.key === 'B' || e.key === 'b') {
|
||||||
if (e.key === 'B' || e.key === 'b')
|
$('.add-new-barcode-dialog-button').not(".d-none").trigger('click');
|
||||||
{
|
|
||||||
$('.add-new-barcode-dialog-button').not(".d-none").click();
|
|
||||||
}
|
}
|
||||||
if (e.key === 'p' || e.key === 'P')
|
if (e.key === 'p' || e.key === 'P') {
|
||||||
{
|
$('.add-new-product-dialog-button').not(".d-none").trigger('click');
|
||||||
$('.add-new-product-dialog-button').not(".d-none").click();
|
|
||||||
}
|
}
|
||||||
if (e.key === 'a' || e.key === 'A')
|
if (e.key === 'a' || e.key === 'A') {
|
||||||
{
|
$('.add-new-product-with-barcode-dialog-button').not(".d-none").trigger('click');
|
||||||
$('.add-new-product-with-barcode-dialog-button').not(".d-none").click();
|
|
||||||
}
|
}
|
||||||
if (e.key === 'c' || e.key === 'C')
|
if (e.key === 'c' || e.key === 'C') {
|
||||||
{
|
$('.retry-camera-scanning-button').not(".d-none").trigger('click');
|
||||||
$('.retry-camera-scanning-button').not(".d-none").click();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.Reset();
|
Grocy.Components.ProductAmountPicker.Reset();
|
||||||
Grocy.Components.ProductPicker.Clear();
|
Grocy.Components.ProductPicker.Clear();
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
Grocy.Components.ProductPicker.ShowCustomError(__t('This product is not in stock'));
|
Grocy.Components.ProductPicker.ShowCustomError(__t('This product is not in stock'));
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on("Grocy.BarcodeScanned", function(e, barcode, target)
|
|
||||||
{
|
|
||||||
if (!(target == "@productpicker" || target == "undefined" || target == undefined)) // Default target
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't know why the blur event does not fire immediately ... this works...
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focusout();
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().blur();
|
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().val(barcode);
|
|
||||||
|
|
||||||
setTimeout(function()
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focusout();
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().blur();
|
|
||||||
}, 200);
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on("shown.bs.modal", function(e)
|
|
||||||
{
|
|
||||||
$(".modal-footer").addClass("d-block").addClass("d-sm-flex");
|
|
||||||
$(".modal-footer").find("button").addClass("mt-2").addClass("mt-sm-0");
|
|
||||||
})
|
|
||||||
|
|
||||||
// Make that ENTER behaves the same like TAB (trigger blur to start workflows, but only when the dropdown is not opened)
|
|
||||||
$('#product_id_text_input').keydown(function(event)
|
|
||||||
{
|
|
||||||
if (event.keyCode === 13) // Enter
|
|
||||||
{
|
|
||||||
if (Grocy.Components.ProductPicker.GetPicker().hasClass("combobox-menu-visible"))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#product_id_text_input").trigger("blur");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
$('#save-consume-button').on('click', function(e)
|
$('#save-consume-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,51 +16,42 @@
|
||||||
jsonData.spoiled = $('#spoiled').is(':checked');
|
jsonData.spoiled = $('#spoiled').is(':checked');
|
||||||
jsonData.allow_subproduct_substitution = true;
|
jsonData.allow_subproduct_substitution = true;
|
||||||
|
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked")) {
|
||||||
{
|
|
||||||
jsonData.stock_entry_id = jsonForm.specific_stock_entry;
|
jsonData.stock_entry_id = jsonForm.specific_stock_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
jsonData.location_id = $("#location_id").val();
|
jsonData.location_id = $("#location_id").val();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_RECIPES && Grocy.Components.RecipePicker.GetValue().toString().length > 0)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_RECIPES && Grocy.Components.RecipePicker.GetValue().toString().length > 0) {
|
||||||
{
|
|
||||||
jsonData.recipe_id = Grocy.Components.RecipePicker.GetValue();
|
jsonData.recipe_id = Grocy.Components.RecipePicker.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
var bookingResponse = null;
|
var bookingResponse = null;
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
Grocy.Api.Post(apiUrl, jsonData,
|
Grocy.Api.Post(apiUrl, jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled)) {
|
||||||
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled))
|
|
||||||
{
|
|
||||||
Grocy.UISound.Success();
|
Grocy.UISound.Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
bookingResponse = result;
|
bookingResponse = result;
|
||||||
|
|
||||||
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct")
|
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct") {
|
||||||
{
|
|
||||||
var jsonDataBarcode = {};
|
var jsonDataBarcode = {};
|
||||||
jsonDataBarcode.barcode = GetUriParam("barcode");
|
jsonDataBarcode.barcode = GetUriParam("barcode");
|
||||||
jsonDataBarcode.product_id = jsonForm.product_id;
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
|
|
||||||
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
||||||
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
||||||
$('#barcode-lookup-hint').removeClass('d-none');
|
$('#barcode-lookup-hint').removeClass('d-none');
|
||||||
window.history.replaceState({}, document.title, U("/consume"));
|
window.history.replaceState({}, document.title, U("/consume"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
|
|
@ -70,28 +59,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked")) {
|
||||||
{
|
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").click();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1 && !jsonData.exact_amount)
|
if (productDetails.product.enable_tare_weight_handling == 1 && !jsonData.exact_amount) {
|
||||||
{
|
|
||||||
var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount - (parseFloat(productDetails.product.tare_weight) + parseFloat(productDetails.stock_amount))) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount - (parseFloat(productDetails.product.tare_weight) + parseFloat(productDetails.stock_amount))) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
toastr.success(successMessage);
|
toastr.success(successMessage);
|
||||||
Grocy.Components.ProductPicker.FinishFlow();
|
Grocy.Components.ProductPicker.FinishFlow();
|
||||||
|
|
@ -99,54 +81,45 @@
|
||||||
Grocy.Components.ProductAmountPicker.Reset();
|
Grocy.Components.ProductAmountPicker.Reset();
|
||||||
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
||||||
$("#display_amount").removeAttr("max");
|
$("#display_amount").removeAttr("max");
|
||||||
if (BoolVal(Grocy.UserSettings.stock_default_consume_amount_use_quick_consume_amount))
|
if (BoolVal(Grocy.UserSettings.stock_default_consume_amount_use_quick_consume_amount)) {
|
||||||
{
|
|
||||||
$('#display_amount').val(productDetails.product.quick_consume_amount);
|
$('#display_amount').val(productDetails.product.quick_consume_amount);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_consume_amount));
|
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_consume_amount));
|
||||||
}
|
}
|
||||||
RefreshLocaleNumberInput();
|
RefreshLocaleNumberInput();
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
Grocy.Components.ProductPicker.Clear();
|
Grocy.Components.ProductPicker.Clear();
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_RECIPES)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_RECIPES) {
|
||||||
{
|
|
||||||
Grocy.Components.RecipePicker.Clear();
|
Grocy.Components.RecipePicker.Clear();
|
||||||
}
|
}
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
$("#location_id").find("option").remove().end().append("<option></option>");
|
$("#location_id").find("option").remove().end().append("<option></option>");
|
||||||
}
|
}
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
$("#consume-exact-amount-group").addClass("d-none");
|
$("#consume-exact-amount-group").addClass("d-none");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#save-mark-as-open-button').on('click', function(e)
|
$('#save-mark-as-open-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,123 +132,98 @@ $('#save-mark-as-open-button').on('click', function(e)
|
||||||
jsonData.amount = jsonForm.amount;
|
jsonData.amount = jsonForm.amount;
|
||||||
jsonData.allow_subproduct_substitution = true;
|
jsonData.allow_subproduct_substitution = true;
|
||||||
|
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked")) {
|
||||||
{
|
|
||||||
jsonData.stock_entry_id = jsonForm.specific_stock_entry;
|
jsonData.stock_entry_id = jsonForm.specific_stock_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
Grocy.Api.Post(apiUrl, jsonData,
|
Grocy.Api.Post(apiUrl, jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked")) {
|
||||||
{
|
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").click();
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
toastr.success(__t('Marked %1$s of %2$s as opened', parseFloat(jsonForm.amount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + result[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>');
|
toastr.success(__t('Marked %1$s of %2$s as opened', parseFloat(jsonForm.amount).toLocaleString({
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts
|
||||||
|
}) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + result[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>');
|
||||||
|
|
||||||
if (BoolVal(Grocy.UserSettings.stock_default_consume_amount_use_quick_consume_amount))
|
if (BoolVal(Grocy.UserSettings.stock_default_consume_amount_use_quick_consume_amount)) {
|
||||||
{
|
|
||||||
$('#display_amount').val(productDetails.product.quick_consume_amount);
|
$('#display_amount').val(productDetails.product.quick_consume_amount);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_consume_amount));
|
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_consume_amount));
|
||||||
}
|
}
|
||||||
RefreshLocaleNumberInput();
|
RefreshLocaleNumberInput();
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
Grocy.Components.ProductPicker.Clear();
|
Grocy.Components.ProductPicker.Clear();
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
Grocy.FrontendHelpers.EndUiBusy("consume-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
var sumValue = 0;
|
var sumValue = 0;
|
||||||
$("#location_id").on('change', function(e)
|
$("#location_id").on('change', function(e) {
|
||||||
{
|
|
||||||
var locationId = $(e.target).val();
|
var locationId = $(e.target).val();
|
||||||
|
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked")) {
|
||||||
{
|
$("#use_specific_stock_entry").trigger('click');
|
||||||
$("#use_specific_stock_entry").click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
OnLocationChange(locationId, GetUriParam('stockId'));
|
OnLocationChange(locationId, GetUriParam('stockId'));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// try to get stock id from grocycode
|
// try to get stock id from grocycode
|
||||||
if ($("#product_id").data("grocycode"))
|
if (Grocy.Components.ProductPicker.GetState('grocycode')) {
|
||||||
{
|
var gc = Grocy.Components.ProductPicker.GetState('barcode').split(':');
|
||||||
var gc = $("#product_id").attr("barcode").split(":");
|
if (gc.length == 4) {
|
||||||
if (gc.length == 4)
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?query%5B%5D=stock_id%3D' + gc[3],
|
||||||
{
|
function(stockEntries) {
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?query[]=stock_id=' + gc[3],
|
|
||||||
function(stockEntries)
|
|
||||||
{
|
|
||||||
OnLocationChange(stockEntries[0].location_id, gc[3]);
|
OnLocationChange(stockEntries[0].location_id, gc[3]);
|
||||||
$('#display_amount').val(stockEntries[0].amount);
|
$('#display_amount').val(stockEntries[0].amount);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
OnLocationChange(locationId, null);
|
OnLocationChange(locationId, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function OnLocationChange(locationId, stockId)
|
function OnLocationChange(locationId, stockId) {
|
||||||
{
|
|
||||||
sumValue = 0;
|
sumValue = 0;
|
||||||
|
|
||||||
if (locationId)
|
if (locationId) {
|
||||||
{
|
if ($("#location_id").val() != locationId) {
|
||||||
if ($("#location_id").val() != locationId)
|
|
||||||
{
|
|
||||||
$("#location_id").val(locationId);
|
$("#location_id").val(locationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?include_sub_products=true',
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?include_sub_products=true',
|
||||||
function(stockEntries)
|
function(stockEntries) {
|
||||||
{
|
stockEntries.forEach(stockEntry => {
|
||||||
stockEntries.forEach(stockEntry =>
|
|
||||||
{
|
|
||||||
var openTxt = __t("Not opened");
|
var openTxt = __t("Not opened");
|
||||||
if (stockEntry.open == 1)
|
if (stockEntry.open == 1) {
|
||||||
{
|
|
||||||
openTxt = __t("Opened");
|
openTxt = __t("Opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stockEntry.location_id == locationId)
|
if (stockEntry.location_id == locationId) {
|
||||||
{
|
if ($("#specific_stock_entry option[value='" + stockEntry.stock_id + "']").length == 0) {
|
||||||
if ($("#specific_stock_entry option[value='" + stockEntry.stock_id + "']").length == 0)
|
|
||||||
{
|
|
||||||
$("#specific_stock_entry").append($("<option>", {
|
$("#specific_stock_entry").append($("<option>", {
|
||||||
value: stockEntry.stock_id,
|
value: stockEntry.stock_id,
|
||||||
amount: stockEntry.amount,
|
amount: stockEntry.amount,
|
||||||
|
|
@ -285,8 +233,7 @@ function OnLocationChange(locationId, stockId)
|
||||||
|
|
||||||
sumValue = sumValue + parseFloat(stockEntry.amount || 0);
|
sumValue = sumValue + parseFloat(stockEntry.amount || 0);
|
||||||
|
|
||||||
if (stockEntry.stock_id == stockId)
|
if (stockEntry.stock_id == stockId) {
|
||||||
{
|
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").click();
|
||||||
$("#specific_stock_entry").val(stockId);
|
$("#specific_stock_entry").val(stockId);
|
||||||
}
|
}
|
||||||
|
|
@ -294,63 +241,51 @@ function OnLocationChange(locationId, stockId)
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(),
|
Grocy.Api.Get('stock/products/' + Grocy.Components.ProductPicker.GetValue(),
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
current_productDetails = productDetails;
|
current_productDetails = productDetails;
|
||||||
RefreshForm();
|
RefreshForm();
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (document.getElementById("product_id").getAttribute("barcode") == "null")
|
if (document.getElementById("product_id").getAttribute("barcode") == "null") {
|
||||||
{
|
|
||||||
ScanModeSubmit();
|
ScanModeSubmit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
{
|
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled)) {
|
||||||
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled))
|
|
||||||
{
|
|
||||||
Grocy.UISound.BarcodeScannerBeep();
|
Grocy.UISound.BarcodeScannerBeep();
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked")) {
|
||||||
{
|
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").click();
|
||||||
}
|
}
|
||||||
$("#location_id").val("");
|
$("#location_id").val("");
|
||||||
|
|
||||||
var productId = $(e.target).val();
|
var productId = $(e.target).val();
|
||||||
|
|
||||||
if (productId)
|
if (productId) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductCard.Refresh(productId);
|
Grocy.Components.ProductCard.Refresh(productId);
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
current_productDetails = productDetails;
|
current_productDetails = productDetails;
|
||||||
|
|
||||||
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
||||||
if (BoolVal(Grocy.UserSettings.stock_default_consume_amount_use_quick_consume_amount))
|
if (BoolVal(Grocy.UserSettings.stock_default_consume_amount_use_quick_consume_amount)) {
|
||||||
{
|
|
||||||
$('#display_amount').val(productDetails.product.quick_consume_amount);
|
$('#display_amount').val(productDetails.product.quick_consume_amount);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_consume_amount));
|
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_consume_amount));
|
||||||
}
|
}
|
||||||
RefreshLocaleNumberInput();
|
RefreshLocaleNumberInput();
|
||||||
|
|
@ -358,13 +293,10 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
|
|
||||||
$("#location_id").find("option").remove().end().append("<option></option>");
|
$("#location_id").find("option").remove().end().append("<option></option>");
|
||||||
Grocy.Api.Get("stock/products/" + productId + '/locations?include_sub_products=true',
|
Grocy.Api.Get("stock/products/" + productId + '/locations?include_sub_products=true',
|
||||||
function(stockLocations)
|
function(stockLocations) {
|
||||||
{
|
|
||||||
var setDefault = 0;
|
var setDefault = 0;
|
||||||
stockLocations.forEach(stockLocation =>
|
stockLocations.forEach(stockLocation => {
|
||||||
{
|
if (productDetails.location.id == stockLocation.location_id) {
|
||||||
if (productDetails.location.id == stockLocation.location_id)
|
|
||||||
{
|
|
||||||
$("#location_id").append($("<option>", {
|
$("#location_id").append($("<option>", {
|
||||||
value: stockLocation.location_id,
|
value: stockLocation.location_id,
|
||||||
text: stockLocation.location_name + " (" + __t("Default location") + ")"
|
text: stockLocation.location_name + " (" + __t("Default location") + ")"
|
||||||
|
|
@ -372,41 +304,32 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
$("#location_id").val(productDetails.location.id);
|
$("#location_id").val(productDetails.location.id);
|
||||||
$("#location_id").trigger('change');
|
$("#location_id").trigger('change');
|
||||||
setDefault = 1;
|
setDefault = 1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#location_id").append($("<option>", {
|
$("#location_id").append($("<option>", {
|
||||||
value: stockLocation.location_id,
|
value: stockLocation.location_id,
|
||||||
text: stockLocation.location_name
|
text: stockLocation.location_name
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setDefault == 0)
|
if (setDefault == 0) {
|
||||||
{
|
|
||||||
$("#location_id").val(stockLocation.location_id);
|
$("#location_id").val(stockLocation.location_id);
|
||||||
$("#location_id").trigger('change');
|
$("#location_id").trigger('change');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (document.getElementById("product_id").getAttribute("barcode") != "null")
|
if (document.getElementById("product_id").getAttribute("barcode") != "null") {
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
||||||
function(barcodeResult)
|
function(barcodeResult) {
|
||||||
{
|
if (barcodeResult != null) {
|
||||||
if (barcodeResult != null)
|
|
||||||
{
|
|
||||||
var barcode = barcodeResult[0];
|
var barcode = barcodeResult[0];
|
||||||
|
|
||||||
if (barcode != null)
|
if (barcode != null) {
|
||||||
{
|
if (barcode.amount != null && !barcode.amount.isEmpty()) {
|
||||||
if (barcode.amount != null && !barcode.amount.isEmpty())
|
|
||||||
{
|
|
||||||
$("#display_amount").val(barcode.amount);
|
$("#display_amount").val(barcode.amount);
|
||||||
$("#display_amount").select();
|
$("#display_amount").select();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (barcode.qu_id != null && !barcode.qu_id.isEmpty())
|
if (barcode.qu_id != null && !barcode.qu_id.isEmpty()) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(barcode.qu_id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(barcode.qu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,27 +340,22 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", productDetails.product.tare_weight);
|
$("#display_amount").attr("min", productDetails.product.tare_weight);
|
||||||
$('#display_amount').attr('max', parseFloat(productDetails.stock_amount) + parseFloat(productDetails.product.tare_weight));
|
$('#display_amount').attr('max', parseFloat(productDetails.stock_amount) + parseFloat(productDetails.product.tare_weight));
|
||||||
$("#tare-weight-handling-info").removeClass("d-none");
|
$("#tare-weight-handling-info").removeClass("d-none");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
}
|
}
|
||||||
|
|
@ -446,17 +364,13 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
$('#display_amount').focus();
|
$('#display_amount').focus();
|
||||||
|
|
||||||
if (productDetails.stock_amount == productDetails.stock_amount_opened || productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.stock_amount == productDetails.stock_amount_opened || productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
$("#save-mark-as-open-button").addClass("disabled");
|
$("#save-mark-as-open-button").addClass("disabled");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#save-mark-as-open-button").removeClass("disabled");
|
$("#save-mark-as-open-button").removeClass("disabled");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -467,29 +381,24 @@ $('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_consume_amo
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
|
|
||||||
$('#display_amount').on('focus', function(e)
|
$('#display_amount').on('focus', function(e) {
|
||||||
{
|
|
||||||
$(this).select();
|
$(this).select();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#price').on('focus', function(e)
|
$('#price').on('focus', function(e) {
|
||||||
{
|
|
||||||
$(this).select();
|
$(this).select();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$('#consume-form input').keyup(function(event)
|
$('#consume-form input').keyup(function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#consume-form select').change(function(event)
|
$('#consume-form select').change(function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#consume-form input').keydown(function(event)
|
$('#consume-form input').keydown(function(event) {
|
||||||
{
|
|
||||||
if (event.keyCode === 13) //Enter
|
if (event.keyCode === 13) //Enter
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -497,58 +406,43 @@ $('#consume-form input').keydown(function(event)
|
||||||
if (document.getElementById('consume-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('consume-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#save-consume-button').click();
|
$('#save-consume-button').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#specific_stock_entry").on("change", function(e)
|
$("#specific_stock_entry").on("change", function(e) {
|
||||||
{
|
if ($(e.target).val() == "") {
|
||||||
if ($(e.target).val() == "")
|
|
||||||
{
|
|
||||||
sumValue = 0;
|
sumValue = 0;
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?include_sub_products=true',
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries?include_sub_products=true',
|
||||||
function(stockEntries)
|
function(stockEntries) {
|
||||||
{
|
stockEntries.forEach(stockEntry => {
|
||||||
stockEntries.forEach(stockEntry =>
|
if (stockEntry.location_id == $("#location_id").val() || stockEntry.location_id == "") {
|
||||||
{
|
|
||||||
if (stockEntry.location_id == $("#location_id").val() || stockEntry.location_id == "")
|
|
||||||
{
|
|
||||||
sumValue = sumValue + parseFloat(stockEntry.amount_aggregated);
|
sumValue = sumValue + parseFloat(stockEntry.amount_aggregated);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("#display_amount").attr("max", sumValue);
|
$("#display_amount").attr("max", sumValue);
|
||||||
if (sumValue == 0)
|
if (sumValue == 0) {
|
||||||
{
|
|
||||||
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#display_amount").attr("max", $('option:selected', this).attr('amount'));
|
$("#display_amount").attr("max", $('option:selected', this).attr('amount'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#use_specific_stock_entry").on("change", function()
|
$("#use_specific_stock_entry").on("change", function() {
|
||||||
{
|
|
||||||
var value = $(this).is(":checked");
|
var value = $(this).is(":checked");
|
||||||
|
|
||||||
if (value)
|
if (value) {
|
||||||
{
|
|
||||||
$("#specific_stock_entry").removeAttr("disabled");
|
$("#specific_stock_entry").removeAttr("disabled");
|
||||||
$("#specific_stock_entry").attr("required", "");
|
$("#specific_stock_entry").attr("required", "");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#specific_stock_entry").attr("disabled", "");
|
$("#specific_stock_entry").attr("disabled", "");
|
||||||
$("#specific_stock_entry").removeAttr("required");
|
$("#specific_stock_entry").removeAttr("required");
|
||||||
$("#specific_stock_entry").val("");
|
$("#specific_stock_entry").val("");
|
||||||
|
|
@ -558,146 +452,114 @@ $("#use_specific_stock_entry").on("change", function()
|
||||||
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#qu_id").on("change", function()
|
$("#qu_id").on("change", function() {
|
||||||
{
|
|
||||||
RefreshForm();
|
RefreshForm();
|
||||||
});
|
});
|
||||||
|
|
||||||
function UndoStockBooking(bookingId)
|
function UndoStockBooking(bookingId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
toastr.success(__t("Booking successfully undone"));
|
toastr.success(__t("Booking successfully undone"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function UndoStockTransaction(transactionId)
|
function UndoStockTransaction(transactionId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
toastr.success(__t("Transaction successfully undone"));
|
toastr.success(__t("Transaction successfully undone"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
var locationId = GetUriParam('locationId');
|
var locationId = GetUriParam('locationId');
|
||||||
|
|
||||||
if (typeof locationId === 'undefined')
|
if (typeof locationId === 'undefined') {
|
||||||
{
|
Grocy.Components.ProductPicker.Validate();
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
} else {
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#location_id").val(locationId);
|
$("#location_id").val(locationId);
|
||||||
$("#location_id").trigger('change');
|
$("#location_id").trigger('change');
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").trigger('click');
|
||||||
$("#use_specific_stock_entry").trigger('change');
|
$("#use_specific_stock_entry").trigger('change');
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
Grocy.Components.ProductPicker.Validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default input field
|
// Default input field
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Focus();
|
||||||
|
|
||||||
$(document).on("change", "#scan-mode", function(e)
|
$(document).on("change", "#scan-mode", function(e) {
|
||||||
{
|
if ($(this).prop("checked")) {
|
||||||
if ($(this).prop("checked"))
|
|
||||||
{
|
|
||||||
Grocy.UISound.AskForPermission();
|
Grocy.UISound.AskForPermission();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#scan-mode-button").on("click", function(e)
|
$("#scan-mode-button").on("click", function(e) {
|
||||||
{
|
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
$("#scan-mode").click();
|
$("#scan-mode").trigger('click');
|
||||||
$("#scan-mode-button").toggleClass("btn-success").toggleClass("btn-danger");
|
$("#scan-mode-button").toggleClass("btn-success").toggleClass("btn-danger");
|
||||||
if ($("#scan-mode").prop("checked"))
|
if ($("#scan-mode").prop("checked")) {
|
||||||
{
|
|
||||||
$("#scan-mode-status").text(__t("on"));
|
$("#scan-mode-status").text(__t("on"));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#scan-mode-status").text(__t("off"));
|
$("#scan-mode-status").text(__t("off"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#consume-exact-amount').on('change', RefreshForm);
|
$('#consume-exact-amount').on('change', RefreshForm);
|
||||||
var current_productDetails;
|
var current_productDetails;
|
||||||
function RefreshForm()
|
|
||||||
{
|
function RefreshForm() {
|
||||||
var productDetails = current_productDetails;
|
var productDetails = current_productDetails;
|
||||||
if (!productDetails)
|
if (!productDetails) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
$("#consume-exact-amount-group").removeClass("d-none");
|
$("#consume-exact-amount-group").removeClass("d-none");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#consume-exact-amount-group").addClass("d-none");
|
$("#consume-exact-amount-group").addClass("d-none");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1 && !$('#consume-exact-amount').is(':checked'))
|
if (productDetails.product.enable_tare_weight_handling == 1 && !$('#consume-exact-amount').is(':checked')) {
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", productDetails.product.tare_weight);
|
$("#display_amount").attr("min", productDetails.product.tare_weight);
|
||||||
$('#display_amount').attr('max', sumValue + parseFloat(productDetails.product.tare_weight));
|
$('#display_amount').attr('max', sumValue + parseFloat(productDetails.product.tare_weight));
|
||||||
$("#tare-weight-handling-info").removeClass("d-none");
|
$("#tare-weight-handling-info").removeClass("d-none");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
|
|
||||||
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
||||||
$('#display_amount').attr('max', sumValue * $("#qu_id option:selected").attr("data-qu-factor"));
|
$('#display_amount').attr('max', sumValue * $("#qu_id option:selected").attr("data-qu-factor"));
|
||||||
|
|
||||||
if (sumValue == 0)
|
if (sumValue == 0) {
|
||||||
{
|
|
||||||
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productDetails.has_childs)
|
if (productDetails.has_childs) {
|
||||||
{
|
|
||||||
$("#display_amount").removeAttr("max");
|
$("#display_amount").removeAttr("max");
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
||||||
}
|
}
|
||||||
|
|
||||||
function ScanModeSubmit(singleUnit = true)
|
function ScanModeSubmit(singleUnit = true) {
|
||||||
{
|
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled)) {
|
||||||
if (BoolVal(Grocy.UserSettings.scan_mode_consume_enabled))
|
if (singleUnit) {
|
||||||
{
|
|
||||||
if (singleUnit)
|
|
||||||
{
|
|
||||||
$("#display_amount").val(1);
|
$("#display_amount").val(1);
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
Grocy.FrontendHelpers.ValidateForm("consume-form");
|
||||||
if (document.getElementById("consume-form").checkValidity() === true)
|
if (document.getElementById("consume-form").checkValidity() === true) {
|
||||||
{
|
|
||||||
$('#save-consume-button').click();
|
$('#save-consume-button').click();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
toastr.warning(__t("Scan mode is on but not all required fields could be populated automatically"));
|
toastr.warning(__t("Scan mode is on but not all required fields could be populated automatically"));
|
||||||
Grocy.UISound.Error();
|
Grocy.UISound.Error();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
$('#save-inventory-button').on('click', function(e)
|
$('#save-inventory-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -11,11 +9,9 @@
|
||||||
Grocy.FrontendHelpers.BeginUiBusy("inventory-form");
|
Grocy.FrontendHelpers.BeginUiBusy("inventory-form");
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
var price = "";
|
var price = "";
|
||||||
if (!jsonForm.price.toString().isEmpty())
|
if (!jsonForm.price.toString().isEmpty()) {
|
||||||
{
|
|
||||||
price = parseFloat(jsonForm.price).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
price = parseFloat(jsonForm.price).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,16 +19,13 @@
|
||||||
jsonData.new_amount = jsonForm.amount;
|
jsonData.new_amount = jsonForm.amount;
|
||||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||||
jsonData.stock_label_type = jsonForm.stock_label_type;
|
jsonData.stock_label_type = jsonForm.stock_label_type;
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
||||||
{
|
|
||||||
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
||||||
}
|
}
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||||
}
|
}
|
||||||
if (Grocy.UserSettings.show_purchased_date_on_purchase)
|
if (Grocy.UserSettings.show_purchased_date_on_purchase) {
|
||||||
{
|
|
||||||
jsonData.purchased_date = Grocy.Components.DateTimePicker2.GetValue();
|
jsonData.purchased_date = Grocy.Components.DateTimePicker2.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,69 +34,57 @@
|
||||||
var bookingResponse = null;
|
var bookingResponse = null;
|
||||||
|
|
||||||
Grocy.Api.Post('stock/products/' + jsonForm.product_id + '/inventory', jsonData,
|
Grocy.Api.Post('stock/products/' + jsonForm.product_id + '/inventory', jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
bookingResponse = result;
|
bookingResponse = result;
|
||||||
|
|
||||||
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct")
|
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct") {
|
||||||
{
|
|
||||||
var jsonDataBarcode = {};
|
var jsonDataBarcode = {};
|
||||||
jsonDataBarcode.barcode = GetUriParam("barcode");
|
jsonDataBarcode.barcode = GetUriParam("barcode");
|
||||||
jsonDataBarcode.product_id = jsonForm.product_id;
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
jsonDataBarcode.shopping_location_id = jsonForm.shopping_location_id;
|
jsonDataBarcode.shopping_location_id = jsonForm.shopping_location_id;
|
||||||
|
|
||||||
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
||||||
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
||||||
$('#barcode-lookup-hint').removeClass('d-none');
|
$('#barcode-lookup-hint').removeClass('d-none');
|
||||||
window.history.replaceState({}, document.title, U("/inventory"));
|
window.history.replaceState({}, document.title, U("/inventory"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER && parseFloat($("#display_amount").attr("data-estimated-booking-amount")) > 0)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER && parseFloat($("#display_amount").attr("data-estimated-booking-amount")) > 0) {
|
||||||
{
|
if (Grocy.Webhooks.labelprinter !== undefined) {
|
||||||
if (Grocy.Webhooks.labelprinter !== undefined)
|
|
||||||
{
|
|
||||||
if (jsonForm.stock_label_type == 1) // Single label
|
if (jsonForm.stock_label_type == 1) // Single label
|
||||||
{
|
{
|
||||||
var webhookData = {};
|
var webhookData = {};
|
||||||
webhookData.product = productDetails.product.name;
|
webhookData.product = productDetails.product.name;
|
||||||
webhookData.grocycode = 'grcy:p:' + jsonForm.product_id + ":" + result[0].stock_id;
|
webhookData.grocycode = 'grcy:p:' + jsonForm.product_id + ":" + result[0].stock_id;
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) {
|
||||||
{
|
|
||||||
webhookData.due_date = __t('DD') + ': ' + result[0].best_before_date;
|
webhookData.due_date = __t('DD') + ': ' + result[0].best_before_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, webhookData);
|
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, webhookData);
|
||||||
}
|
} else if (jsonForm.stock_label_type == 2) // Label per unit
|
||||||
else if (jsonForm.stock_label_type == 2) // Label per unit
|
|
||||||
{
|
{
|
||||||
Grocy.Api.Get('stock/transactions/' + result[0].transaction_id,
|
Grocy.Api.Get('stock/transactions/' + result[0].transaction_id,
|
||||||
function(stockEntries)
|
function(stockEntries) {
|
||||||
{
|
stockEntries.forEach(stockEntry => {
|
||||||
stockEntries.forEach(stockEntry =>
|
|
||||||
{
|
|
||||||
var webhookData = {};
|
var webhookData = {};
|
||||||
webhookData.product = productDetails.product.name;
|
webhookData.product = productDetails.product.name;
|
||||||
webhookData.grocycode = 'grcy:p:' + jsonForm.product_id + ":" + stockEntry.stock_id;
|
webhookData.grocycode = 'grcy:p:' + jsonForm.product_id + ":" + stockEntry.stock_id;
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) {
|
||||||
{
|
|
||||||
webhookData.due_date = __t('DD') + ': ' + result[0].best_before_date;
|
webhookData.due_date = __t('DD') + ': ' + result[0].best_before_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, webhookData);
|
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, webhookData);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -112,18 +93,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
var successMessage = __t('Stock amount of %1$s is now %2$s', result.product.name, result.stock_amount + " " + __n(result.stock_amount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true)) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
var successMessage = __t('Stock amount of %1$s is now %2$s', result.product.name, result.stock_amount + " " + __n(result.stock_amount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true)) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
||||||
toastr.success(successMessage);
|
toastr.success(successMessage);
|
||||||
Grocy.Components.ProductPicker.FinishFlow();
|
Grocy.Components.ProductPicker.FinishFlow();
|
||||||
|
|
@ -137,125 +114,99 @@
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
$('#price').val('');
|
$('#price').val('');
|
||||||
Grocy.Components.DateTimePicker.Clear();
|
Grocy.Components.DateTimePicker.Clear();
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
Grocy.Components.ProductPicker.Clear();
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
||||||
}
|
}
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER) {
|
||||||
{
|
|
||||||
$("#stock_label_type").val(0);
|
$("#stock_label_type").val(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
Grocy.FrontendHelpers.EndUiBusy("inventory-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
{
|
|
||||||
var productId = $(e.target).val();
|
var productId = $(e.target).val();
|
||||||
|
|
||||||
if (productId)
|
if (productId) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductCard.Refresh(productId);
|
Grocy.Components.ProductCard.Refresh(productId);
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
||||||
|
|
||||||
$('#display_amount').attr("data-stock-amount", productDetails.stock_amount)
|
$('#display_amount').attr("data-stock-amount", productDetails.stock_amount)
|
||||||
$('#display_amount').attr('data-not-equal', productDetails.stock_amount * $("#qu_id option:selected").attr("data-qu-factor"));
|
$('#display_amount').attr('data-not-equal', productDetails.stock_amount * $("#qu_id option:selected").attr("data-qu-factor"));
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", productDetails.product.tare_weight);
|
$("#display_amount").attr("min", productDetails.product.tare_weight);
|
||||||
$("#tare-weight-handling-info").removeClass("d-none");
|
$("#tare-weight-handling-info").removeClass("d-none");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", "0");
|
$("#display_amount").attr("min", "0");
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#price').val(parseFloat(productDetails.last_price));
|
$('#price').val(parseFloat(productDetails.last_price));
|
||||||
RefreshLocaleNumberInput();
|
RefreshLocaleNumberInput();
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.last_shopping_location_id);
|
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.last_shopping_location_id);
|
||||||
}
|
}
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) {
|
||||||
{
|
if (productDetails.product.default_best_before_days.toString() !== '0') {
|
||||||
if (productDetails.product.default_best_before_days.toString() !== '0')
|
if (productDetails.product.default_best_before_days == -1) {
|
||||||
{
|
if (!$("#datetimepicker-shortcut").is(":checked")) {
|
||||||
if (productDetails.product.default_best_before_days == -1)
|
|
||||||
{
|
|
||||||
if (!$("#datetimepicker-shortcut").is(":checked"))
|
|
||||||
{
|
|
||||||
$("#datetimepicker-shortcut").click();
|
$("#datetimepicker-shortcut").click();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.DateTimePicker.SetValue(moment().add(productDetails.product.default_best_before_days, 'days').format('YYYY-MM-DD'));
|
Grocy.Components.DateTimePicker.SetValue(moment().add(productDetails.product.default_best_before_days, 'days').format('YYYY-MM-DD'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER) {
|
||||||
{
|
|
||||||
$("#stock_label_type").val(productDetails.product.default_stock_label_type);
|
$("#stock_label_type").val(productDetails.product.default_stock_label_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.getElementById("product_id").getAttribute("barcode") != "null")
|
if (document.getElementById("product_id").getAttribute("barcode") != "null") {
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
||||||
function(barcodeResult)
|
function(barcodeResult) {
|
||||||
{
|
if (barcodeResult != null) {
|
||||||
if (barcodeResult != null)
|
|
||||||
{
|
|
||||||
var barcode = barcodeResult[0];
|
var barcode = barcodeResult[0];
|
||||||
|
|
||||||
if (barcode != null)
|
if (barcode != null) {
|
||||||
{
|
if (barcode.amount != null && !barcode.amount.isEmpty()) {
|
||||||
if (barcode.amount != null && !barcode.amount.isEmpty())
|
|
||||||
{
|
|
||||||
$("#display_amount").val(barcode.amount);
|
$("#display_amount").val(barcode.amount);
|
||||||
$("#display_amount").select();
|
$("#display_amount").select();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (barcode.qu_id != null && !barcode.qu_id.isEmpty())
|
if (barcode.qu_id != null && !barcode.qu_id.isEmpty()) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(barcode.qu_id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(barcode.qu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,8 +216,7 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -278,8 +228,7 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
$('#display_amount').focus();
|
$('#display_amount').focus();
|
||||||
$('#display_amount').trigger('keyup');
|
$('#display_amount').trigger('keyup');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -290,39 +239,29 @@ $('#display_amount').val('');
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||||
|
|
||||||
if (Grocy.Components.ProductPicker.InAnyFlow() === false && GetUriParam("embedded") === undefined)
|
if (Grocy.Components.ProductPicker.InAnyFlow() === false && GetUriParam("embedded") === undefined) {
|
||||||
{
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
} else {
|
||||||
}
|
Grocy.Components.ProductPicker.Validate();
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
|
||||||
|
|
||||||
if (Grocy.Components.ProductPicker.InProductModifyWorkflow())
|
if (Grocy.Components.ProductPicker.InProductModifyWorkflow()) {
|
||||||
{
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#display_amount').on('focus', function(e)
|
$('#display_amount').on('focus', function(e) {
|
||||||
{
|
if (Grocy.Components.ProductPicker.GetValue().length === 0) {
|
||||||
if (Grocy.Components.ProductPicker.GetValue().length === 0)
|
Grocy.Components.ProductPicker.Focus();
|
||||||
{
|
} else {
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$(this).select();
|
$(this).select();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#inventory-form input').keyup(function(event)
|
$('#inventory-form input').keyup(function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#inventory-form input').keydown(function(event)
|
$('#inventory-form input').keydown(function(event) {
|
||||||
{
|
|
||||||
if (event.keyCode === 13) //Enter
|
if (event.keyCode === 13) //Enter
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -330,46 +269,37 @@ $('#inventory-form input').keydown(function(event)
|
||||||
if (document.getElementById('inventory-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('inventory-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#save-inventory-button').click();
|
$('#save-inventory-button').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$('#qu_id').on('change', function(e)
|
$('#qu_id').on('change', function(e) {
|
||||||
{
|
|
||||||
$('#display_amount').attr('data-not-equal', parseFloat($('#display_amount').attr('data-stock-amount')) * parseFloat($("#qu_id option:selected").attr("data-qu-factor")));
|
$('#display_amount').attr('data-not-equal', parseFloat($('#display_amount').attr('data-stock-amount')) * parseFloat($("#qu_id option:selected").attr("data-qu-factor")));
|
||||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.DateTimePicker.GetInputElement().on('change', function(e)
|
Grocy.Components.DateTimePicker.GetInputElement().on('change', function(e) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.DateTimePicker.GetInputElement().on('keypress', function(e)
|
Grocy.Components.DateTimePicker.GetInputElement().on('keypress', function(e) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#display_amount').on('keyup', function(e)
|
$('#display_amount').on('keyup', function(e) {
|
||||||
{
|
|
||||||
var productId = Grocy.Components.ProductPicker.GetValue();
|
var productId = Grocy.Components.ProductPicker.GetValue();
|
||||||
var newAmount = parseFloat($('#amount').val());
|
var newAmount = parseFloat($('#amount').val());
|
||||||
|
|
||||||
if (productId)
|
if (productId) {
|
||||||
{
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
var productStockAmount = parseFloat(productDetails.stock_amount || parseFloat('0'));
|
var productStockAmount = parseFloat(productDetails.stock_amount || parseFloat('0'));
|
||||||
|
|
||||||
var containerWeight = parseFloat("0");
|
var containerWeight = parseFloat("0");
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
containerWeight = parseFloat(productDetails.product.tare_weight);
|
containerWeight = parseFloat(productDetails.product.tare_weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,71 +308,54 @@ $('#display_amount').on('keyup', function(e)
|
||||||
estimatedBookingAmount = Math.abs(estimatedBookingAmount);
|
estimatedBookingAmount = Math.abs(estimatedBookingAmount);
|
||||||
$('#inventory-change-info').removeClass('d-none');
|
$('#inventory-change-info').removeClass('d-none');
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1 && newAmount < containerWeight)
|
if (productDetails.product.enable_tare_weight_handling == 1 && newAmount < containerWeight) {
|
||||||
{
|
|
||||||
$('#inventory-change-info').addClass('d-none');
|
$('#inventory-change-info').addClass('d-none');
|
||||||
}
|
} else if (newAmount > productStockAmount + containerWeight) {
|
||||||
else if (newAmount > productStockAmount + containerWeight)
|
|
||||||
{
|
|
||||||
$('#inventory-change-info').text(__t('This means %s will be added to stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true)));
|
$('#inventory-change-info').text(__t('This means %s will be added to stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true)));
|
||||||
Grocy.Components.DateTimePicker.GetInputElement().attr('required', '');
|
Grocy.Components.DateTimePicker.GetInputElement().attr('required', '');
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.LocationPicker.GetInputElement().attr('required', '');
|
Grocy.Components.LocationPicker.GetInputElement().attr('required', '');
|
||||||
}
|
}
|
||||||
}
|
} else if (newAmount < productStockAmount + containerWeight) {
|
||||||
else if (newAmount < productStockAmount + containerWeight)
|
|
||||||
{
|
|
||||||
$('#inventory-change-info').text(__t('This means %s will be removed from stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true)));
|
$('#inventory-change-info').text(__t('This means %s will be removed from stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true)));
|
||||||
Grocy.Components.DateTimePicker.GetInputElement().removeAttr('required');
|
Grocy.Components.DateTimePicker.GetInputElement().removeAttr('required');
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.LocationPicker.GetInputElement().removeAttr('required');
|
Grocy.Components.LocationPicker.GetInputElement().removeAttr('required');
|
||||||
}
|
}
|
||||||
}
|
} else if (newAmount == productStockAmount) {
|
||||||
else if (newAmount == productStockAmount)
|
|
||||||
{
|
|
||||||
$('#inventory-change-info').addClass('d-none');
|
$('#inventory-change-info').addClass('d-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.DateTimePicker.GetInputElement().removeAttr('required');
|
Grocy.Components.DateTimePicker.GetInputElement().removeAttr('required');
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
Grocy.FrontendHelpers.ValidateForm('inventory-form');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function UndoStockBooking(bookingId)
|
function UndoStockBooking(bookingId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
toastr.success(__t("Booking successfully undone"));
|
toastr.success(__t("Booking successfully undone"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function UndoStockTransaction(transactionId)
|
function UndoStockTransaction(transactionId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
toastr.success(__t("Transaction successfully undone"));
|
toastr.success(__t("Transaction successfully undone"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,85 +1,59 @@
|
||||||
function saveProductPicture(result, location, jsonData)
|
function saveProductPicture(result, location, jsonData) {
|
||||||
{
|
|
||||||
var productId = Grocy.EditObjectId || result.created_object_id;
|
var productId = Grocy.EditObjectId || result.created_object_id;
|
||||||
Grocy.EditObjectId = productId; // Grocy.EditObjectId is not yet set when adding a product
|
Grocy.EditObjectId = productId; // Grocy.EditObjectId is not yet set when adding a product
|
||||||
|
|
||||||
Grocy.Components.UserfieldsForm.Save(() =>
|
Grocy.Components.UserfieldsForm.Save(() => {
|
||||||
{
|
if (jsonData.hasOwnProperty("picture_file_name") && !Grocy.DeleteProductPictureOnSave) {
|
||||||
if (jsonData.hasOwnProperty("picture_file_name") && !Grocy.DeleteProductPictureOnSave)
|
|
||||||
{
|
|
||||||
Grocy.Api.UploadFile($("#product-picture")[0].files[0], 'productpictures', jsonData.picture_file_name,
|
Grocy.Api.UploadFile($("#product-picture")[0].files[0], 'productpictures', jsonData.picture_file_name,
|
||||||
(result) =>
|
(result) => {
|
||||||
{
|
if (Grocy.ProductEditFormRedirectUri == "reload") {
|
||||||
if (Grocy.ProductEditFormRedirectUri == "reload")
|
|
||||||
{
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnTo = GetUriParam('returnto');
|
var returnTo = GetUriParam('returnto');
|
||||||
if (GetUriParam("closeAfterCreation") !== undefined)
|
if (GetUriParam("closeAfterCreation") !== undefined) {
|
||||||
{
|
|
||||||
window.close();
|
window.close();
|
||||||
}
|
} else if (returnTo !== undefined) {
|
||||||
else if (returnTo !== undefined)
|
if (GetUriParam("flow") !== undefined) {
|
||||||
{
|
|
||||||
if (GetUriParam("flow") !== undefined)
|
|
||||||
{
|
|
||||||
window.location.href = U(returnTo) + '&product-name=' + encodeURIComponent($('#name').val());
|
window.location.href = U(returnTo) + '&product-name=' + encodeURIComponent($('#name').val());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.location.href = U(returnTo);
|
window.location.href = U(returnTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.location.href = U(location + productId);
|
window.location.href = U(location + productId);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
(xhr) =>
|
(xhr) => {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("product-form");
|
Grocy.FrontendHelpers.EndUiBusy("product-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
if (Grocy.ProductEditFormRedirectUri == "reload") {
|
||||||
{
|
|
||||||
if (Grocy.ProductEditFormRedirectUri == "reload")
|
|
||||||
{
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnTo = GetUriParam('returnto');
|
var returnTo = GetUriParam('returnto');
|
||||||
if (GetUriParam("closeAfterCreation") !== undefined)
|
if (GetUriParam("closeAfterCreation") !== undefined) {
|
||||||
{
|
|
||||||
window.close();
|
window.close();
|
||||||
}
|
} else if (returnTo !== undefined) {
|
||||||
else if (returnTo !== undefined)
|
if (GetUriParam("flow") !== undefined) {
|
||||||
{
|
|
||||||
if (GetUriParam("flow") !== undefined)
|
|
||||||
{
|
|
||||||
window.location.href = U(returnTo) + '&product-name=' + encodeURIComponent($('#name').val());
|
window.location.href = U(returnTo) + '&product-name=' + encodeURIComponent($('#name').val());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.location.href = U(returnTo);
|
window.location.href = U(returnTo);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.location.href = U(location + productId);
|
window.location.href = U(location + productId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.save-product-button').on('click', function(e)
|
$('.save-product-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var jsonData = $('#product-form').serializeJSON();
|
var jsonData = $('#product-form').serializeJSON();
|
||||||
|
|
@ -88,42 +62,35 @@ $('.save-product-button').on('click', function(e)
|
||||||
jsonData.parent_product_id = parentProductId;
|
jsonData.parent_product_id = parentProductId;
|
||||||
Grocy.FrontendHelpers.BeginUiBusy("product-form");
|
Grocy.FrontendHelpers.BeginUiBusy("product-form");
|
||||||
|
|
||||||
if (jsonData.parent_product_id.toString().isEmpty())
|
if (jsonData.parent_product_id.toString().isEmpty()) {
|
||||||
{
|
|
||||||
jsonData.parent_product_id = null;
|
jsonData.parent_product_id = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($("#product-picture")[0].files.length > 0)
|
if ($("#product-picture")[0].files.length > 0) {
|
||||||
{
|
|
||||||
var someRandomStuff = Math.random().toString(36).substring(2, 100) + Math.random().toString(36).substring(2, 100);
|
var someRandomStuff = Math.random().toString(36).substring(2, 100) + Math.random().toString(36).substring(2, 100);
|
||||||
jsonData.picture_file_name = someRandomStuff + CleanFileName($("#product-picture")[0].files[0].name);
|
jsonData.picture_file_name = someRandomStuff + CleanFileName($("#product-picture")[0].files[0].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const location = $(e.currentTarget).attr('data-location') == 'return' ? '/products?product=' : '/product/';
|
const location = $(e.currentTarget).attr('data-location') == 'return' ? '/products?product=' : '/product/';
|
||||||
|
|
||||||
if (Grocy.EditMode == 'create')
|
if (Grocy.EditMode == 'create') {
|
||||||
{
|
|
||||||
Grocy.Api.Post('objects/products', jsonData,
|
Grocy.Api.Post('objects/products', jsonData,
|
||||||
(result) => saveProductPicture(result, location, jsonData),
|
(result) => saveProductPicture(result, location, jsonData),
|
||||||
(xhr) =>
|
(xhr) => {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("product-form");
|
Grocy.FrontendHelpers.EndUiBusy("product-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.DeleteProductPictureOnSave)
|
if (Grocy.DeleteProductPictureOnSave) {
|
||||||
{
|
|
||||||
jsonData.picture_file_name = null;
|
jsonData.picture_file_name = null;
|
||||||
|
|
||||||
Grocy.Api.DeleteFile(Grocy.ProductPictureFileName, 'productpictures', {},
|
Grocy.Api.DeleteFile(Grocy.ProductPictureFileName, 'productpictures', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("product-form");
|
Grocy.FrontendHelpers.EndUiBusy("product-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||||
}
|
}
|
||||||
|
|
@ -132,55 +99,44 @@ $('.save-product-button').on('click', function(e)
|
||||||
|
|
||||||
Grocy.Api.Put('objects/products/' + Grocy.EditObjectId, jsonData,
|
Grocy.Api.Put('objects/products/' + Grocy.EditObjectId, jsonData,
|
||||||
(result) => saveProductPicture(result, location, jsonData),
|
(result) => saveProductPicture(result, location, jsonData),
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("product-form");
|
Grocy.FrontendHelpers.EndUiBusy("product-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Grocy.EditMode == "edit")
|
if (Grocy.EditMode == "edit") {
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/stock_log?limit=1&query[]=product_id=' + Grocy.EditObjectId,
|
Grocy.Api.Get('objects/stock_log?limit=1&query[]=product_id=' + Grocy.EditObjectId,
|
||||||
function(productJournalEntries)
|
function(productJournalEntries) {
|
||||||
{
|
if (productJournalEntries.length == 0) {
|
||||||
if (productJournalEntries.length == 0)
|
|
||||||
{
|
|
||||||
$('#qu_id_stock').removeAttr("disabled");
|
$('#qu_id_stock').removeAttr("disabled");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("flow") == "InplaceNewProductWithName")
|
if (GetUriParam("flow") == "InplaceNewProductWithName") {
|
||||||
{
|
|
||||||
$('#name').val(GetUriParam("name"));
|
$('#name').val(GetUriParam("name"));
|
||||||
$('#name').focus();
|
$('#name').focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("flow") !== undefined || GetUriParam("returnto") !== undefined)
|
if (GetUriParam("flow") !== undefined || GetUriParam("returnto") !== undefined) {
|
||||||
{
|
|
||||||
$("#save-hint").addClass("d-none");
|
$("#save-hint").addClass("d-none");
|
||||||
$(".save-product-button[data-location='return']").addClass("d-none");
|
$(".save-product-button[data-location='return']").addClass("d-none");
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.input-group-qu').on('change', function(e)
|
$('.input-group-qu').on('change', function(e) {
|
||||||
{
|
|
||||||
var quIdPurchase = $("#qu_id_purchase").val();
|
var quIdPurchase = $("#qu_id_purchase").val();
|
||||||
var quIdStock = $("#qu_id_stock").val();
|
var quIdStock = $("#qu_id_stock").val();
|
||||||
|
|
||||||
if (Grocy.EditMode == "create" && !quIdPurchase.toString().isEmpty() && !quIdStock.toString().isEmpty() && quIdPurchase != quIdStock)
|
if (Grocy.EditMode == "create" && !quIdPurchase.toString().isEmpty() && !quIdStock.toString().isEmpty() && quIdPurchase != quIdStock) {
|
||||||
{
|
|
||||||
Grocy.Api.Get("objects/quantity_unit_conversions?query[]=product_id=null&query[]=from_qu_id=" + quIdPurchase + "&query[]=to_qu_id=" + quIdStock,
|
Grocy.Api.Get("objects/quantity_unit_conversions?query[]=product_id=null&query[]=from_qu_id=" + quIdPurchase + "&query[]=to_qu_id=" + quIdStock,
|
||||||
function(response)
|
function(response) {
|
||||||
{
|
if (response != null && response.length > 0) {
|
||||||
if (response != null && response.length > 0)
|
|
||||||
{
|
|
||||||
var conversion = response[0];
|
var conversion = response[0];
|
||||||
|
|
||||||
$("#qu_factor_purchase_to_stock").val(conversion.factor);
|
$("#qu_factor_purchase_to_stock").val(conversion.factor);
|
||||||
|
|
@ -188,14 +144,11 @@ $('.input-group-qu').on('change', function(e)
|
||||||
RefreshQuConversionInfo();
|
RefreshQuConversionInfo();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
RefreshQuConversionInfo();
|
RefreshQuConversionInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -206,25 +159,20 @@ $('.input-group-qu').on('change', function(e)
|
||||||
Grocy.FrontendHelpers.ValidateForm('product-form');
|
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
function RefreshQuConversionInfo()
|
function RefreshQuConversionInfo() {
|
||||||
{
|
|
||||||
var quIdPurchase = $("#qu_id_purchase").val();
|
var quIdPurchase = $("#qu_id_purchase").val();
|
||||||
var quIdStock = $("#qu_id_stock").val();
|
var quIdStock = $("#qu_id_stock").val();
|
||||||
var factor = $('#qu_factor_purchase_to_stock').val();
|
var factor = $('#qu_factor_purchase_to_stock').val();
|
||||||
|
|
||||||
if (factor > 1 || quIdPurchase != quIdStock)
|
if (factor > 1 || quIdPurchase != quIdStock) {
|
||||||
{
|
|
||||||
$('#qu-conversion-info').text(__t('This means 1 %1$s purchased will be converted into %2$s %3$s in stock', $("#qu_id_purchase option:selected").text(), (1 * factor).toString(), __n((1 * factor).toString(), $("#qu_id_stock option:selected").text(), $("#qu_id_stock option:selected").data("plural-form"), true)));
|
$('#qu-conversion-info').text(__t('This means 1 %1$s purchased will be converted into %2$s %3$s in stock', $("#qu_id_purchase option:selected").text(), (1 * factor).toString(), __n((1 * factor).toString(), $("#qu_id_stock option:selected").text(), $("#qu_id_stock option:selected").data("plural-form"), true)));
|
||||||
$('#qu-conversion-info').removeClass('d-none');
|
$('#qu-conversion-info').removeClass('d-none');
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#qu-conversion-info').addClass('d-none');
|
$('#qu-conversion-info').addClass('d-none');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#product-form input').keyup(function(event)
|
$('#product-form input').on('keyup', function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('product-form');
|
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||||
$(".input-group-qu").trigger("change");
|
$(".input-group-qu").trigger("change");
|
||||||
$("#product-form select").trigger("select");
|
$("#product-form select").trigger("select");
|
||||||
|
|
@ -232,9 +180,7 @@ $('#product-form input').keyup(function(event)
|
||||||
if (document.getElementById('product-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('product-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
$("#qu-conversion-add-button").addClass("disabled");
|
$("#qu-conversion-add-button").addClass("disabled");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#qu-conversion-add-button").removeClass("disabled");
|
$("#qu-conversion-add-button").removeClass("disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,13 +190,11 @@ $('#product-form input').keyup(function(event)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#location_id').change(function(event)
|
$('#location_id').on('change', function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('product-form');
|
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#product-form input').keydown(function(event)
|
$('#product-form input').on('keydown', function(event) {
|
||||||
{
|
|
||||||
if (event.keyCode === 13) //Enter
|
if (event.keyCode === 13) //Enter
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -258,30 +202,23 @@ $('#product-form input').keydown(function(event)
|
||||||
if (document.getElementById('product-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('product-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('.default-submit-button').click();
|
$('.default-submit-button').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#enable_tare_weight_handling").on("click", function()
|
$("#enable_tare_weight_handling").on("click", function() {
|
||||||
{
|
if (this.checked) {
|
||||||
if (this.checked)
|
|
||||||
{
|
|
||||||
$("#tare_weight").removeAttr("disabled");
|
$("#tare_weight").removeAttr("disabled");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#tare_weight").attr("disabled", "");
|
$("#tare_weight").attr("disabled", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm("product-form");
|
Grocy.FrontendHelpers.ValidateForm("product-form");
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#product-picture").on("change", function(e)
|
$("#product-picture").on("change", function(e) {
|
||||||
{
|
|
||||||
$("#product-picture-label").removeClass("d-none");
|
$("#product-picture-label").removeClass("d-none");
|
||||||
$("#product-picture-label-none").addClass("d-none");
|
$("#product-picture-label-none").addClass("d-none");
|
||||||
$("#delete-current-product-picture-on-save-hint").addClass("d-none");
|
$("#delete-current-product-picture-on-save-hint").addClass("d-none");
|
||||||
|
|
@ -290,8 +227,7 @@ $("#product-picture").on("change", function(e)
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.DeleteProductPictureOnSave = false;
|
Grocy.DeleteProductPictureOnSave = false;
|
||||||
$("#delete-current-product-picture-button").on("click", function(e)
|
$("#delete-current-product-picture-button").on("click", function(e) {
|
||||||
{
|
|
||||||
Grocy.DeleteProductPictureOnSave = true;
|
Grocy.DeleteProductPictureOnSave = true;
|
||||||
$("#current-product-picture").addClass("d-none");
|
$("#current-product-picture").addClass("d-none");
|
||||||
$("#delete-current-product-picture-on-save-hint").removeClass("d-none");
|
$("#delete-current-product-picture-on-save-hint").removeClass("d-none");
|
||||||
|
|
@ -300,12 +236,24 @@ $("#delete-current-product-picture-button").on("click", function(e)
|
||||||
});
|
});
|
||||||
|
|
||||||
var quConversionsTable = $('#qu-conversions-table-products').DataTable({
|
var quConversionsTable = $('#qu-conversions-table-products').DataTable({
|
||||||
'order': [[1, 'asc']],
|
'order': [
|
||||||
"orderFixed": [[4, 'asc']],
|
[1, 'asc']
|
||||||
'columnDefs': [
|
],
|
||||||
{ 'orderable': false, 'targets': 0 },
|
"orderFixed": [
|
||||||
{ 'searchable': false, "targets": 0 },
|
[4, 'asc']
|
||||||
{ 'visible': false, 'targets': 4 }
|
],
|
||||||
|
'columnDefs': [{
|
||||||
|
'orderable': false,
|
||||||
|
'targets': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'searchable': false,
|
||||||
|
"targets": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'visible': false,
|
||||||
|
'targets': 4
|
||||||
|
}
|
||||||
].concat($.fn.dataTable.defaults.columnDefs),
|
].concat($.fn.dataTable.defaults.columnDefs),
|
||||||
'rowGroup': {
|
'rowGroup': {
|
||||||
enable: true,
|
enable: true,
|
||||||
|
|
@ -316,13 +264,28 @@ $('#qu-conversions-table-products tbody').removeClass("d-none");
|
||||||
quConversionsTable.columns.adjust().draw();
|
quConversionsTable.columns.adjust().draw();
|
||||||
|
|
||||||
var barcodeTable = $('#barcode-table').DataTable({
|
var barcodeTable = $('#barcode-table').DataTable({
|
||||||
'order': [[1, 'asc']],
|
'order': [
|
||||||
"orderFixed": [[1, 'asc']],
|
[1, 'asc']
|
||||||
'columnDefs': [
|
],
|
||||||
{ 'orderable': false, 'targets': 0 },
|
"orderFixed": [
|
||||||
{ 'searchable': false, "targets": 0 },
|
[1, 'asc']
|
||||||
{ 'visible': false, 'targets': 5 },
|
],
|
||||||
{ 'visible': false, 'targets': 6 }
|
'columnDefs': [{
|
||||||
|
'orderable': false,
|
||||||
|
'targets': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'searchable': false,
|
||||||
|
"targets": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'visible': false,
|
||||||
|
'targets': 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'visible': false,
|
||||||
|
'targets': 6
|
||||||
|
}
|
||||||
].concat($.fn.dataTable.defaults.columnDefs)
|
].concat($.fn.dataTable.defaults.columnDefs)
|
||||||
});
|
});
|
||||||
$('#barcode-table tbody').removeClass("d-none");
|
$('#barcode-table tbody').removeClass("d-none");
|
||||||
|
|
@ -330,27 +293,23 @@ barcodeTable.columns.adjust().draw();
|
||||||
|
|
||||||
Grocy.Components.UserfieldsForm.Load();
|
Grocy.Components.UserfieldsForm.Load();
|
||||||
$("#name").trigger("keyup");
|
$("#name").trigger("keyup");
|
||||||
$('#name').focus();
|
$('#name').trigger('focus');
|
||||||
$('.input-group-qu').trigger('change');
|
$('.input-group-qu').trigger('change');
|
||||||
Grocy.FrontendHelpers.ValidateForm('product-form');
|
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||||
|
|
||||||
$(document).on('click', '.product-grocycode-label-print', function(e)
|
$(document).on('click', '.product-grocycode-label-print', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
|
|
||||||
var productId = $(e.currentTarget).attr('data-product-id');
|
var productId = $(e.currentTarget).attr('data-product-id');
|
||||||
Grocy.Api.Get('stock/products/' + productId + '/printlabel', function(labelData)
|
Grocy.Api.Get('stock/products/' + productId + '/printlabel', function(labelData) {
|
||||||
{
|
if (Grocy.Webhooks.labelprinter !== undefined) {
|
||||||
if (Grocy.Webhooks.labelprinter !== undefined)
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, labelData);
|
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, labelData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.qu-conversion-delete-button', function(e)
|
$(document).on('click', '.qu-conversion-delete-button', function(e) {
|
||||||
{
|
|
||||||
var objectId = $(e.currentTarget).attr('data-qu-conversion-id');
|
var objectId = $(e.currentTarget).attr('data-qu-conversion-id');
|
||||||
|
|
||||||
bootbox.confirm({
|
bootbox.confirm({
|
||||||
|
|
@ -366,18 +325,14 @@ $(document).on('click', '.qu-conversion-delete-button', function(e)
|
||||||
className: 'btn-danger'
|
className: 'btn-danger'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
callback: function(result)
|
callback: function(result) {
|
||||||
{
|
if (result === true) {
|
||||||
if (result === true)
|
|
||||||
{
|
|
||||||
Grocy.Api.Delete('objects/quantity_unit_conversions/' + objectId, {},
|
Grocy.Api.Delete('objects/quantity_unit_conversions/' + objectId, {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
Grocy.ProductEditFormRedirectUri = "reload";
|
Grocy.ProductEditFormRedirectUri = "reload";
|
||||||
$('#save-product-button').click();
|
$('#save-product-button').click();
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -386,8 +341,7 @@ $(document).on('click', '.qu-conversion-delete-button', function(e)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.barcode-delete-button', function(e)
|
$(document).on('click', '.barcode-delete-button', function(e) {
|
||||||
{
|
|
||||||
var objectId = $(e.currentTarget).attr('data-barcode-id');
|
var objectId = $(e.currentTarget).attr('data-barcode-id');
|
||||||
|
|
||||||
bootbox.confirm({
|
bootbox.confirm({
|
||||||
|
|
@ -403,18 +357,14 @@ $(document).on('click', '.barcode-delete-button', function(e)
|
||||||
className: 'btn-danger'
|
className: 'btn-danger'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
callback: function(result)
|
callback: function(result) {
|
||||||
{
|
if (result === true) {
|
||||||
if (result === true)
|
|
||||||
{
|
|
||||||
Grocy.Api.Delete('objects/product_barcodes/' + objectId, {},
|
Grocy.Api.Delete('objects/product_barcodes/' + objectId, {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
Grocy.ProductEditFormRedirectUri = "reload";
|
Grocy.ProductEditFormRedirectUri = "reload";
|
||||||
$('#save-product-button').click();
|
$('#save-product-button').click();
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -423,14 +373,12 @@ $(document).on('click', '.barcode-delete-button', function(e)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#qu_id_stock').change(function(e)
|
$('#qu_id_stock').on('change', function(e) {
|
||||||
{
|
|
||||||
// Preset QU purchase with stock QU if unset
|
// Preset QU purchase with stock QU if unset
|
||||||
var quIdStock = $('#qu_id_stock');
|
var quIdStock = $('#qu_id_stock');
|
||||||
var quIdPurchase = $('#qu_id_purchase');
|
var quIdPurchase = $('#qu_id_purchase');
|
||||||
|
|
||||||
if (quIdPurchase[0].selectedIndex === 0 && quIdStock[0].selectedIndex !== 0)
|
if (quIdPurchase[0].selectedIndex === 0 && quIdStock[0].selectedIndex !== 0) {
|
||||||
{
|
|
||||||
quIdPurchase[0].selectedIndex = quIdStock[0].selectedIndex;
|
quIdPurchase[0].selectedIndex = quIdStock[0].selectedIndex;
|
||||||
Grocy.FrontendHelpers.ValidateForm('product-form');
|
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||||
}
|
}
|
||||||
|
|
@ -438,59 +386,47 @@ $('#qu_id_stock').change(function(e)
|
||||||
RefreshQuConversionInfo();
|
RefreshQuConversionInfo();
|
||||||
});
|
});
|
||||||
|
|
||||||
$(window).on("message", function(e)
|
$(window).on("message", function(e) {
|
||||||
{
|
|
||||||
var data = e.originalEvent.data;
|
var data = e.originalEvent.data;
|
||||||
|
|
||||||
if (data.Message === "ProductBarcodesChanged" || data.Message === "ProductQUConversionChanged")
|
if (data.Message === "ProductBarcodesChanged" || data.Message === "ProductQUConversionChanged") {
|
||||||
{
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Grocy.EditMode == "create" && GetUriParam("copy-of") != undefined)
|
if (Grocy.EditMode == "create" && GetUriParam("copy-of") != undefined) {
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/products/' + GetUriParam("copy-of"),
|
Grocy.Api.Get('objects/products/' + GetUriParam("copy-of"),
|
||||||
function(sourceProduct)
|
function(sourceProduct) {
|
||||||
{
|
if (sourceProduct.parent_product_id != null) {
|
||||||
if (sourceProduct.parent_product_id != null)
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.SetId(sourceProduct.parent_product_id);
|
Grocy.Components.ProductPicker.SetId(sourceProduct.parent_product_id);
|
||||||
}
|
}
|
||||||
if (sourceProduct.description != null)
|
if (sourceProduct.description != null) {
|
||||||
{
|
|
||||||
$("#description").summernote("pasteHTML", sourceProduct.description);
|
$("#description").summernote("pasteHTML", sourceProduct.description);
|
||||||
}
|
}
|
||||||
$("#location_id").val(sourceProduct.location_id);
|
$("#location_id").val(sourceProduct.location_id);
|
||||||
if (sourceProduct.shopping_location_id != null)
|
if (sourceProduct.shopping_location_id != null) {
|
||||||
{
|
|
||||||
Grocy.Components.ShoppingLocationPicker.SetId(sourceProduct.shopping_location_id);
|
Grocy.Components.ShoppingLocationPicker.SetId(sourceProduct.shopping_location_id);
|
||||||
}
|
}
|
||||||
$("#min_stock_amount").val(sourceProduct.min_stock_amount);
|
$("#min_stock_amount").val(sourceProduct.min_stock_amount);
|
||||||
if (BoolVal(sourceProduct.cumulate_min_stock_amount_of_sub_products))
|
if (BoolVal(sourceProduct.cumulate_min_stock_amount_of_sub_products)) {
|
||||||
{
|
|
||||||
$("#cumulate_min_stock_amount_of_sub_products").prop("checked", true);
|
$("#cumulate_min_stock_amount_of_sub_products").prop("checked", true);
|
||||||
}
|
}
|
||||||
$("#default_best_before_days").val(sourceProduct.default_best_before_days);
|
$("#default_best_before_days").val(sourceProduct.default_best_before_days);
|
||||||
$("#default_best_before_days_after_open").val(sourceProduct.default_best_before_days_after_open);
|
$("#default_best_before_days_after_open").val(sourceProduct.default_best_before_days_after_open);
|
||||||
if (sourceProduct.product_group_id != null)
|
if (sourceProduct.product_group_id != null) {
|
||||||
{
|
|
||||||
$("#product_group_id").val(sourceProduct.product_group_id);
|
$("#product_group_id").val(sourceProduct.product_group_id);
|
||||||
}
|
}
|
||||||
$("#qu_id_stock").val(sourceProduct.qu_id_stock);
|
$("#qu_id_stock").val(sourceProduct.qu_id_stock);
|
||||||
$("#qu_id_purchase").val(sourceProduct.qu_id_purchase);
|
$("#qu_id_purchase").val(sourceProduct.qu_id_purchase);
|
||||||
$("#qu_factor_purchase_to_stock").val(sourceProduct.qu_factor_purchase_to_stock);
|
$("#qu_factor_purchase_to_stock").val(sourceProduct.qu_factor_purchase_to_stock);
|
||||||
if (BoolVal(sourceProduct.enable_tare_weight_handling))
|
if (BoolVal(sourceProduct.enable_tare_weight_handling)) {
|
||||||
{
|
|
||||||
$("#enable_tare_weight_handling").prop("checked", true);
|
$("#enable_tare_weight_handling").prop("checked", true);
|
||||||
}
|
}
|
||||||
$("#tare_weight").val(sourceProduct.tare_weight);
|
$("#tare_weight").val(sourceProduct.tare_weight);
|
||||||
if (BoolVal(sourceProduct.not_check_stock_fulfillment_for_recipes))
|
if (BoolVal(sourceProduct.not_check_stock_fulfillment_for_recipes)) {
|
||||||
{
|
|
||||||
$("#not_check_stock_fulfillment_for_recipes").prop("checked", true);
|
$("#not_check_stock_fulfillment_for_recipes").prop("checked", true);
|
||||||
}
|
}
|
||||||
if (sourceProduct.calories != null)
|
if (sourceProduct.calories != null) {
|
||||||
{
|
|
||||||
$("#calories").val(sourceProduct.calories);
|
$("#calories").val(sourceProduct.calories);
|
||||||
}
|
}
|
||||||
$("#default_best_before_days_after_freezing").val(sourceProduct.default_best_before_days_after_freezing);
|
$("#default_best_before_days_after_freezing").val(sourceProduct.default_best_before_days_after_freezing);
|
||||||
|
|
@ -499,75 +435,57 @@ if (Grocy.EditMode == "create" && GetUriParam("copy-of") != undefined)
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('product-form');
|
Grocy.FrontendHelpers.ValidateForm('product-form');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else if (Grocy.EditMode === 'create') {
|
||||||
else if (Grocy.EditMode === 'create')
|
if (Grocy.UserSettings.product_presets_location_id.toString() !== '-1') {
|
||||||
{
|
|
||||||
if (Grocy.UserSettings.product_presets_location_id.toString() !== '-1')
|
|
||||||
{
|
|
||||||
$("#location_id").val(Grocy.UserSettings.product_presets_location_id);
|
$("#location_id").val(Grocy.UserSettings.product_presets_location_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.UserSettings.product_presets_product_group_id.toString() !== '-1')
|
if (Grocy.UserSettings.product_presets_product_group_id.toString() !== '-1') {
|
||||||
{
|
|
||||||
$("#product_group_id").val(Grocy.UserSettings.product_presets_product_group_id);
|
$("#product_group_id").val(Grocy.UserSettings.product_presets_product_group_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.UserSettings.product_presets_qu_id.toString() !== '-1')
|
if (Grocy.UserSettings.product_presets_qu_id.toString() !== '-1') {
|
||||||
{
|
|
||||||
$("select.input-group-qu").val(Grocy.UserSettings.product_presets_qu_id);
|
$("select.input-group-qu").val(Grocy.UserSettings.product_presets_qu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.UserSettings.product_presets_default_due_days.toString() !== '0')
|
if (Grocy.UserSettings.product_presets_default_due_days.toString() !== '0') {
|
||||||
{
|
|
||||||
$("#default_best_before_days").val(Grocy.UserSettings.product_presets_default_due_days);
|
$("#default_best_before_days").val(Grocy.UserSettings.product_presets_default_due_days);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING) {
|
||||||
{
|
|
||||||
$("#treat_opened_as_out_of_stock").prop("checked", BoolVal(Grocy.UserSettings.product_presets_treat_opened_as_out_of_stock));
|
$("#treat_opened_as_out_of_stock").prop("checked", BoolVal(Grocy.UserSettings.product_presets_treat_opened_as_out_of_stock));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
{
|
|
||||||
var parentProductId = $(e.target).val();
|
var parentProductId = $(e.target).val();
|
||||||
|
|
||||||
if (parentProductId)
|
if (parentProductId) {
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/products/' + parentProductId,
|
Grocy.Api.Get('objects/products/' + parentProductId,
|
||||||
function(parentProduct)
|
function(parentProduct) {
|
||||||
{
|
if (BoolVal(parentProduct.cumulate_min_stock_amount_of_sub_products)) {
|
||||||
if (BoolVal(parentProduct.cumulate_min_stock_amount_of_sub_products))
|
|
||||||
{
|
|
||||||
|
|
||||||
$("#min_stock_amount").attr("disabled", "");
|
$("#min_stock_amount").attr("disabled", "");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#min_stock_amount').removeAttr("disabled");
|
$('#min_stock_amount').removeAttr("disabled");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#min_stock_amount').removeAttr("disabled");
|
$('#min_stock_amount').removeAttr("disabled");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm("product-form");
|
Grocy.FrontendHelpers.ValidateForm("product-form");
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger("change");
|
Grocy.Components.ProductPicker.Validate();
|
||||||
|
|
||||||
if (Grocy.EditMode == "edit")
|
if (Grocy.EditMode == "edit") {
|
||||||
{
|
|
||||||
$(".save-product-button").toggleClass("default-submit-button");
|
$(".save-product-button").toggleClass("default-submit-button");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,61 +1,180 @@
|
||||||
var productsTable = $('#products-table').DataTable({
|
var userfieldsColumns = userfields.map(function(userfield) {
|
||||||
'order': [[1, 'asc']],
|
if (userfield.show_as_column_in_tables != 1) return null;
|
||||||
'columnDefs': [
|
return {
|
||||||
{ 'orderable': false, 'targets': 0 },
|
data: 'userfields.' + userfield.name,
|
||||||
{ 'searchable': false, "targets": 0 },
|
defaultContent: ''
|
||||||
{ 'visible': false, 'targets': 7 },
|
};
|
||||||
{ "type": "html-num-fmt", "targets": 3 }
|
}).filter(function(userfield) {
|
||||||
].concat($.fn.dataTable.defaults.columnDefs)
|
return userfield !== null;
|
||||||
});
|
});
|
||||||
$('#products-table tbody').removeClass("d-none");
|
|
||||||
productsTable.columns.adjust().draw();
|
|
||||||
|
|
||||||
$("#search").on("keyup", Delay(function()
|
var productsTable = $('#products-table').DataTable({
|
||||||
{
|
ajax: function(data, callback, settings) {
|
||||||
|
Grocy.FrontendHelpers.BeginUiBusy();
|
||||||
|
|
||||||
|
var query = [];
|
||||||
|
if (GetUriParam('only_in_stock')) {
|
||||||
|
query.push('only_in_stock=true');
|
||||||
|
}
|
||||||
|
if (!GetUriParam('include_disabled')) {
|
||||||
|
query.push('query%5B%5D=' + encodeURIComponent('active=1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.columns.forEach(function(column) {
|
||||||
|
var search = column.search.value.trim();
|
||||||
|
if (search.length > 0) {
|
||||||
|
query.push('query%5B%5D=' + encodeURIComponent(column.data + '=' + search));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var search = data.search.value.trim();
|
||||||
|
if (search.length > 0) {
|
||||||
|
query.push('search=' + encodeURIComponent(search));
|
||||||
|
}
|
||||||
|
|
||||||
|
query.push('limit=' + encodeURIComponent(data.length));
|
||||||
|
query.push('offset=' + encodeURIComponent(data.start));
|
||||||
|
query.push('order=' + encodeURIComponent(data.order.map(function(order) {
|
||||||
|
return data.columns[order.column].data + ':' + order.dir;
|
||||||
|
}).join(',')));
|
||||||
|
|
||||||
|
Grocy.Api.Get('objects/products' + (query.length > 0 ? '?' + query.join('&') : ''),
|
||||||
|
function(result, meta) {
|
||||||
|
callback({
|
||||||
|
data: result,
|
||||||
|
recordsTotal: meta.recordsTotal,
|
||||||
|
recordsFiltered: meta.recordsFiltered,
|
||||||
|
});
|
||||||
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
|
},
|
||||||
|
function(xhr) {
|
||||||
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
|
Grocy.FrontendHelpers.ShowGenericError('Server error', xhr.response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
paging: true,
|
||||||
|
serverSide: true,
|
||||||
|
deferRender: true,
|
||||||
|
autoWidth: true,
|
||||||
|
order: [
|
||||||
|
[1, 'asc']
|
||||||
|
],
|
||||||
|
columns: [{
|
||||||
|
searchable: false,
|
||||||
|
orderable: false,
|
||||||
|
render: function(data, type, row, meta) {
|
||||||
|
return '<a class="btn btn-info btn-sm" href="/product/' + encodeURIComponent(row.id) + '"' +
|
||||||
|
' data-toggle="tooltip" title="' + __t('Edit this item') + '">' +
|
||||||
|
' <i class="fas fa-edit"></i>' +
|
||||||
|
'</a>' +
|
||||||
|
'<a class="btn btn-danger btn-sm product-delete-button" href="#"' +
|
||||||
|
' data-product-id="' + row.id + '" data-product-name="' + row.name + '"' +
|
||||||
|
' data-toggle="tooltip" title="' + __t('Delete this item') + '">' +
|
||||||
|
' <i class="fas fa-trash"></i>' +
|
||||||
|
'</a>' +
|
||||||
|
'<div class="dropdown d-inline-block">' +
|
||||||
|
' <button class="btn btn-sm btn-light text-secondary" type="button"' +
|
||||||
|
' data-toggle="dropdown">' +
|
||||||
|
' <i class="fas fa-ellipsis-v"></i>' +
|
||||||
|
' </button>' +
|
||||||
|
' <div class="table-inline-menu dropdown-menu dropdown-menu-right">' +
|
||||||
|
' <a class="dropdown-item" type="button"' +
|
||||||
|
' href="/product/new?copy-of=' + encodeURIComponent(row.id) + '">' +
|
||||||
|
' <span class="dropdown-item-text">' + __t('Copy') + '</span>' +
|
||||||
|
' </a>' +
|
||||||
|
' <a class="dropdown-item merge-products-button"' +
|
||||||
|
' data-product-id="' + row.id + '" data-product-name="' + row.name + '"' +
|
||||||
|
' type="button" href="#" >' +
|
||||||
|
' <span class="dropdown-item-text">' + __t('Merge') + '</span>' +
|
||||||
|
' </a>' +
|
||||||
|
' </div>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'name',
|
||||||
|
searchable: true,
|
||||||
|
render: function(data, type, row, meta) {
|
||||||
|
return data + (row.picture_file_name ? (
|
||||||
|
' <i class="fas fa-image text-muted" data-toggle="tooltip" ' +
|
||||||
|
'title="' + __t('This product has a picture') + '"></i>'
|
||||||
|
) : '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'location.name',
|
||||||
|
defaultContent: '',
|
||||||
|
visible: Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'min_stock_amount',
|
||||||
|
type: 'html-num-fmt',
|
||||||
|
render: function(data, type, row, meta) {
|
||||||
|
return '<span class="locale-number locale-number-quantity-amount">' + data + '</span>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'qu_purchase.name',
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'qu_stock.name',
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'product_group.name',
|
||||||
|
defaultContent: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'shopping_location.name',
|
||||||
|
defaultContent: '',
|
||||||
|
visible: Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING
|
||||||
|
}
|
||||||
|
].concat(userfieldsColumns),
|
||||||
|
});
|
||||||
|
|
||||||
|
productsTable.on('draw', function() {
|
||||||
|
$('[data-toggle=tooltip]').tooltip();
|
||||||
|
$('[data-toggle=dropdown]').dropdown();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#search').on('keyup', Delay(function() {
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
if (value === "all")
|
if (value === 'all') {
|
||||||
{
|
value = '';
|
||||||
value = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
productsTable.search(value).draw();
|
productsTable.search(value).draw();
|
||||||
}, 200));
|
}, 500));
|
||||||
|
|
||||||
$("#product-group-filter").on("change", function()
|
$('#product-group-filter').on('change', function() {
|
||||||
{
|
var value = $('#product-group-filter option:selected').text();
|
||||||
var value = $("#product-group-filter option:selected").text();
|
if (value === __t('All')) {
|
||||||
if (value === __t("All"))
|
value = '';
|
||||||
{
|
|
||||||
value = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
productsTable.column(productsTable.colReorder.transpose(6)).search(value).draw();
|
productsTable.column(productsTable.colReorder.transpose(6)).search(value).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#clear-filter-button").on("click", function()
|
$('#clear-filter-button').on('click', function() {
|
||||||
{
|
$('#search').val('');
|
||||||
$("#search").val("");
|
$('#product-group-filter').val('all');
|
||||||
$("#product-group-filter").val("all");
|
productsTable.column(productsTable.colReorder.transpose(6)).search('');
|
||||||
productsTable.column(productsTable.colReorder.transpose(6)).search("").draw();
|
productsTable.search('');
|
||||||
productsTable.search("").draw();
|
if ($('#show-disabled').is(':checked') || $('#show-only-in-stock').is(':checked')) {
|
||||||
if ($("#show-disabled").is(":checked") || $("#show-only-in-stock").is(":checked"))
|
$('#show-disabled').prop('checked', false);
|
||||||
{
|
$('#show-only-in-stock').prop('checked', false);
|
||||||
$("#show-disabled").prop("checked", false);
|
RemoveUriParam('include_disabled');
|
||||||
$("#show-only-in-stock").prop("checked", false);
|
RemoveUriParam('only_in_stock');
|
||||||
RemoveUriParam("include_disabled");
|
|
||||||
RemoveUriParam("only_in_stock");
|
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
|
productsTable.draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof GetUriParam("product-group") !== "undefined")
|
if (typeof GetUriParam('product-group') !== 'undefined') {
|
||||||
{
|
$('#product-group-filter').val(GetUriParam('product-group'));
|
||||||
$("#product-group-filter").val(GetUriParam("product-group"));
|
$('#product-group-filter').trigger('change');
|
||||||
$("#product-group-filter").trigger("change");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).on('click', '.product-delete-button', function(e)
|
$(document).on('click', '.product-delete-button', function(e) {
|
||||||
{
|
|
||||||
var objectName = $(e.currentTarget).attr('data-product-name');
|
var objectName = $(e.currentTarget).attr('data-product-name');
|
||||||
var objectId = $(e.currentTarget).attr('data-product-id');
|
var objectId = $(e.currentTarget).attr('data-product-id');
|
||||||
|
|
||||||
|
|
@ -72,19 +191,15 @@ $(document).on('click', '.product-delete-button', function(e)
|
||||||
className: 'btn-danger'
|
className: 'btn-danger'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
callback: function(result)
|
callback: function(result) {
|
||||||
{
|
if (result === true) {
|
||||||
if (result === true)
|
|
||||||
{
|
|
||||||
jsonData = {};
|
jsonData = {};
|
||||||
jsonData.active = 0;
|
jsonData.active = 0;
|
||||||
Grocy.Api.Delete('objects/products/' + objectId, {},
|
Grocy.Api.Delete('objects/products/' + objectId, {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
window.location.href = U('/products');
|
window.location.href = U('/products');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -93,61 +208,96 @@ $(document).on('click', '.product-delete-button', function(e)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#show-disabled").change(function()
|
$('#show-disabled').on('change', function() {
|
||||||
{
|
if (this.checked) {
|
||||||
if (this.checked)
|
UpdateUriParam('include_disabled', 'true');
|
||||||
{
|
} else {
|
||||||
UpdateUriParam("include_disabled", "true");
|
RemoveUriParam('include_disabled');
|
||||||
}
|
}
|
||||||
else
|
productsTable.draw();
|
||||||
{
|
|
||||||
RemoveUriParam("include_disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
window.location.reload();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#show-only-in-stock").change(function()
|
$('#show-only-in-stock').on('change', function() {
|
||||||
{
|
if (this.checked) {
|
||||||
if (this.checked)
|
UpdateUriParam('only_in_stock', 'true');
|
||||||
{
|
} else {
|
||||||
UpdateUriParam("only_in_stock", "true");
|
RemoveUriParam('only_in_stock');
|
||||||
}
|
}
|
||||||
else
|
productsTable.draw();
|
||||||
{
|
|
||||||
RemoveUriParam("only_in_stock");
|
|
||||||
}
|
|
||||||
|
|
||||||
window.location.reload();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (GetUriParam('include_disabled'))
|
if (GetUriParam('include_disabled')) {
|
||||||
{
|
$('#show-disabled').prop('checked', true);
|
||||||
$("#show-disabled").prop('checked', true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(document).on('click', '.merge-products-button', function(e) {
|
||||||
|
var $button = $(e.currentTarget);
|
||||||
|
var $mergeKeep = $('#merge-products-keep');
|
||||||
|
|
||||||
$(".merge-products-button").on("click", function(e)
|
var optionId = $button.attr('data-product-id');
|
||||||
{
|
var optionText = $button.attr('data-product-name');
|
||||||
var productId = $(e.currentTarget).attr("data-product-id");
|
|
||||||
$("#merge-products-keep").val(productId);
|
if ($mergeKeep.find('option[value="' + optionId + '"]').length) {
|
||||||
$("#merge-products-remove").val("");
|
$mergeKeep.val(optionId).trigger('change');
|
||||||
$("#merge-products-modal").modal("show");
|
} else {
|
||||||
|
var option = new Option(optionText, optionId, true, true);
|
||||||
|
$mergeKeep.append(option).trigger('change');
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#merge-products-remove').val(null).trigger('change');
|
||||||
|
$('#merge-products-modal').modal('show');
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#merge-products-save-button").on("click", function()
|
$('#merge-products-save-button').on('click', function() {
|
||||||
{
|
var productIdToKeep = $('#merge-products-keep').val();
|
||||||
var productIdToKeep = $("#merge-products-keep").val();
|
var productIdToRemove = $('#merge-products-remove').val();
|
||||||
var productIdToRemove = $("#merge-products-remove").val();
|
|
||||||
|
|
||||||
Grocy.Api.Post("stock/products/" + productIdToKeep.toString() + "/merge/" + productIdToRemove.toString(), {},
|
Grocy.Api.Post('stock/products/' + productIdToKeep.toString() + '/merge/' + productIdToRemove.toString(), {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
window.location.href = U('/products');
|
window.location.href = U('/products');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while merging', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while merging', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#merge-products-keep, #merge-products-remove').select2({
|
||||||
|
dropdownParent: $('#merge-products-modal'),
|
||||||
|
ajax: {
|
||||||
|
delay: 150,
|
||||||
|
transport: function(params, success, failure) {
|
||||||
|
var results_per_page = 10;
|
||||||
|
var page = params.data.page || 1;
|
||||||
|
var term = params.data.term || "";
|
||||||
|
|
||||||
|
var query = [];
|
||||||
|
query.push('query%5B%5D=active%3D1');
|
||||||
|
query.push('limit=' + encodeURIComponent(results_per_page));
|
||||||
|
query.push('offset=' + encodeURIComponent((page - 1) * results_per_page));
|
||||||
|
query.push('order=name%3Acollate%20nocase');
|
||||||
|
if (term.length > 0) {
|
||||||
|
query.push('search=' + encodeURIComponent(term));
|
||||||
|
}
|
||||||
|
|
||||||
|
Grocy.Api.Get('objects/products' + (query.length > 0 ? '?' + query.join('&') : ''),
|
||||||
|
function(results, meta) {
|
||||||
|
success({
|
||||||
|
results: results.map(function(result) {
|
||||||
|
return {
|
||||||
|
id: result.id,
|
||||||
|
text: result.name
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
pagination: {
|
||||||
|
more: page * results_per_page < meta.recordsFiltered
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(xhr) {
|
||||||
|
failure();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
var CurrentProductDetails;
|
var CurrentProductDetails;
|
||||||
|
|
||||||
$('#save-purchase-button').on('click', function(e)
|
$('#save-purchase-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -19,140 +16,116 @@ $('#save-purchase-button').on('click', function(e)
|
||||||
Grocy.FrontendHelpers.BeginUiBusy("purchase-form");
|
Grocy.FrontendHelpers.BeginUiBusy("purchase-form");
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
var jsonData = {};
|
var jsonData = {};
|
||||||
jsonData.amount = jsonForm.amount;
|
jsonData.amount = jsonForm.amount;
|
||||||
jsonData.stock_label_type = jsonForm.stock_label_type;
|
jsonData.stock_label_type = jsonForm.stock_label_type;
|
||||||
|
|
||||||
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
||||||
{
|
|
||||||
jsonData.price = 0;
|
jsonData.price = 0;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
var amount = jsonForm.display_amount;
|
var amount = jsonForm.display_amount;
|
||||||
if (BoolVal(productDetails.product.enable_tare_weight_handling))
|
if (BoolVal(productDetails.product.enable_tare_weight_handling)) {
|
||||||
{
|
|
||||||
amount -= parseFloat(productDetails.product.tare_weight);
|
amount -= parseFloat(productDetails.product.tare_weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
var price = parseFloat(jsonForm.price * $("#qu_id option:selected").attr("data-qu-factor")).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
var price = parseFloat(jsonForm.price * $("#qu_id option:selected").attr("data-qu-factor")).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
||||||
if ($("input[name='price-type']:checked").val() == "total-price")
|
if ($("input[name='price-type']:checked").val() == "total-price") {
|
||||||
{
|
|
||||||
price = parseFloat(price / amount).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
price = parseFloat(price / amount).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonData.price = price;
|
jsonData.price = price;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BoolVal(Grocy.UserSettings.show_purchased_date_on_purchase))
|
if (BoolVal(Grocy.UserSettings.show_purchased_date_on_purchase)) {
|
||||||
{
|
|
||||||
jsonData.purchased_date = Grocy.Components.DateTimePicker2.GetValue();
|
jsonData.purchased_date = Grocy.Components.DateTimePicker2.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.Components.DateTimePicker)
|
if (Grocy.Components.DateTimePicker) {
|
||||||
{
|
|
||||||
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
jsonData.best_before_date = Grocy.Components.DateTimePicker.GetValue();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
jsonData.best_before_date = null;
|
jsonData.best_before_date = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
||||||
{
|
|
||||||
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
jsonData.shopping_location_id = Grocy.Components.ShoppingLocationPicker.GetValue();
|
||||||
}
|
}
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
jsonData.location_id = Grocy.Components.LocationPicker.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Post('stock/products/' + jsonForm.product_id + '/add', jsonData,
|
Grocy.Api.Post('stock/products/' + jsonForm.product_id + '/add', jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
if ($("#purchase-form").hasAttr("data-used-barcode")) {
|
||||||
if ($("#purchase-form").hasAttr("data-used-barcode"))
|
Grocy.Api.Put('objects/product_barcodes/' + $("#purchase-form").attr("data-used-barcode"), {
|
||||||
{
|
last_price: $("#price").val()
|
||||||
Grocy.Api.Put('objects/product_barcodes/' + $("#purchase-form").attr("data-used-barcode"), { last_price: $("#price").val() },
|
},
|
||||||
function(result)
|
function(result) {},
|
||||||
{ },
|
function(xhr) {}
|
||||||
function(xhr)
|
|
||||||
{ }
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BoolVal(Grocy.UserSettings.scan_mode_purchase_enabled))
|
if (BoolVal(Grocy.UserSettings.scan_mode_purchase_enabled)) {
|
||||||
{
|
|
||||||
Grocy.UISound.Success();
|
Grocy.UISound.Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("flow") == "InplaceAddBarcodeToExistingProduct")
|
if (GetUriParam("flow") == "InplaceAddBarcodeToExistingProduct") {
|
||||||
{
|
|
||||||
var jsonDataBarcode = {};
|
var jsonDataBarcode = {};
|
||||||
jsonDataBarcode.barcode = GetUriParam("barcode");
|
jsonDataBarcode.barcode = GetUriParam("barcode");
|
||||||
jsonDataBarcode.product_id = jsonForm.product_id;
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
jsonDataBarcode.shopping_location_id = jsonForm.shopping_location_id;
|
jsonDataBarcode.shopping_location_id = jsonForm.shopping_location_id;
|
||||||
|
|
||||||
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
||||||
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
||||||
$('#barcode-lookup-hint').removeClass('d-none');
|
$('#barcode-lookup-hint').removeClass('d-none');
|
||||||
window.history.replaceState({}, document.title, U("/purchase"));
|
window.history.replaceState({}, document.title, U("/purchase"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var amountMessage = parseFloat(jsonForm.amount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts });
|
var amountMessage = parseFloat(jsonForm.amount).toLocaleString({
|
||||||
if (BoolVal(productDetails.product.enable_tare_weight_handling))
|
minimumFractionDigits: 0,
|
||||||
{
|
maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts
|
||||||
|
});
|
||||||
|
if (BoolVal(productDetails.product.enable_tare_weight_handling)) {
|
||||||
amountMessage = parseFloat(jsonForm.amount) - parseFloat(productDetails.stock_amount) - parseFloat(productDetails.product.tare_weight);
|
amountMessage = parseFloat(jsonForm.amount) - parseFloat(productDetails.stock_amount) - parseFloat(productDetails.product.tare_weight);
|
||||||
}
|
}
|
||||||
var successMessage = __t('Added %1$s of %2$s to stock', amountMessage + " " + __n(amountMessage, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + result[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
var successMessage = __t('Added %1$s of %2$s to stock', amountMessage + " " + __n(amountMessage, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + result[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER) {
|
||||||
{
|
if (Grocy.Webhooks.labelprinter !== undefined) {
|
||||||
if (Grocy.Webhooks.labelprinter !== undefined)
|
|
||||||
{
|
|
||||||
if (jsonForm.stock_label_type == 1) // Single label
|
if (jsonForm.stock_label_type == 1) // Single label
|
||||||
{
|
{
|
||||||
var webhookData = {};
|
var webhookData = {};
|
||||||
webhookData.product = productDetails.product.name;
|
webhookData.product = productDetails.product.name;
|
||||||
webhookData.grocycode = 'grcy:p:' + jsonForm.product_id + ":" + result[0].stock_id;
|
webhookData.grocycode = 'grcy:p:' + jsonForm.product_id + ":" + result[0].stock_id;
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) {
|
||||||
{
|
|
||||||
webhookData.due_date = __t('DD') + ': ' + result[0].best_before_date;
|
webhookData.due_date = __t('DD') + ': ' + result[0].best_before_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, webhookData);
|
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, webhookData);
|
||||||
}
|
} else if (jsonForm.stock_label_type == 2) // Label per unit
|
||||||
else if (jsonForm.stock_label_type == 2) // Label per unit
|
|
||||||
{
|
{
|
||||||
Grocy.Api.Get('stock/transactions/' + result[0].transaction_id,
|
Grocy.Api.Get('stock/transactions/' + result[0].transaction_id,
|
||||||
function(stockEntries)
|
function(stockEntries) {
|
||||||
{
|
stockEntries.forEach(stockEntry => {
|
||||||
stockEntries.forEach(stockEntry =>
|
|
||||||
{
|
|
||||||
var webhookData = {};
|
var webhookData = {};
|
||||||
webhookData.product = productDetails.product.name;
|
webhookData.product = productDetails.product.name;
|
||||||
webhookData.grocycode = 'grcy:p:' + jsonForm.product_id + ":" + stockEntry.stock_id;
|
webhookData.grocycode = 'grcy:p:' + jsonForm.product_id + ":" + stockEntry.stock_id;
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) {
|
||||||
{
|
|
||||||
webhookData.due_date = __t('DD') + ': ' + result[0].best_before_date;
|
webhookData.due_date = __t('DD') + ': ' + result[0].best_before_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, webhookData);
|
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, webhookData);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -160,24 +133,19 @@ $('#save-purchase-button').on('click', function(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("AfterItemAdded", GetUriParam("listitemid")), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("AfterItemAdded", GetUriParam("listitemid")), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("Ready"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("Ready"), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
||||||
toastr.success(successMessage);
|
toastr.success(successMessage);
|
||||||
Grocy.Components.ProductPicker.FinishFlow();
|
Grocy.Components.ProductPicker.FinishFlow();
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && BoolVal(Grocy.UserSettings.show_warning_on_purchase_when_due_date_is_earlier_than_next))
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && BoolVal(Grocy.UserSettings.show_warning_on_purchase_when_due_date_is_earlier_than_next)) {
|
||||||
{
|
if (moment(jsonData.best_before_date).isBefore(CurrentProductDetails.next_due_date)) {
|
||||||
if (moment(jsonData.best_before_date).isBefore(CurrentProductDetails.next_due_date))
|
|
||||||
{
|
|
||||||
toastr.warning(__t("This is due earlier than already in-stock items"));
|
toastr.warning(__t("This is due earlier than already in-stock items"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -189,23 +157,19 @@ $('#save-purchase-button').on('click', function(e)
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
$('#price').val('');
|
$('#price').val('');
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.LocationPicker.Clear();
|
Grocy.Components.LocationPicker.Clear();
|
||||||
}
|
}
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.DateTimePicker.Clear();
|
Grocy.Components.DateTimePicker.Clear();
|
||||||
}
|
}
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
Grocy.Components.ProductPicker.Clear();
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
Grocy.Components.ShoppingLocationPicker.SetValue('');
|
||||||
}
|
}
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER) {
|
||||||
{
|
|
||||||
$("#stock_label_type").val(0);
|
$("#stock_label_type").val(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,85 +181,66 @@ $('#save-purchase-button').on('click', function(e)
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
Grocy.FrontendHelpers.EndUiBusy("purchase-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Grocy.Components.ProductPicker !== undefined)
|
if (Grocy.Components.ProductPicker !== undefined) {
|
||||||
{
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
if (BoolVal(Grocy.UserSettings.scan_mode_purchase_enabled)) {
|
||||||
{
|
|
||||||
if (BoolVal(Grocy.UserSettings.scan_mode_purchase_enabled))
|
|
||||||
{
|
|
||||||
Grocy.UISound.BarcodeScannerBeep();
|
Grocy.UISound.BarcodeScannerBeep();
|
||||||
}
|
}
|
||||||
|
|
||||||
var productId = $(e.target).val();
|
var productId = $(e.target).val();
|
||||||
|
|
||||||
if (productId)
|
if (productId) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductCard.Refresh(productId);
|
Grocy.Components.ProductCard.Refresh(productId);
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
CurrentProductDetails = productDetails;
|
CurrentProductDetails = productDetails;
|
||||||
|
|
||||||
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
||||||
$("#qu_id").attr("disabled", "");
|
$("#qu_id").attr("disabled", "");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.default_quantity_unit_purchase.id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.default_quantity_unit_purchase.id);
|
||||||
}
|
}
|
||||||
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_purchase_amount));
|
$('#display_amount').val(parseFloat(Grocy.UserSettings.stock_default_purchase_amount));
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
|
|
||||||
if (GetUriParam("flow") === "shoppinglistitemtostock")
|
if (GetUriParam("flow") === "shoppinglistitemtostock") {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(GetUriParam("quId"));
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(GetUriParam("quId"));
|
||||||
$('#display_amount').val(parseFloat(GetUriParam("amount") * $("#qu_id option:selected").attr("data-qu-factor")));
|
$('#display_amount').val(parseFloat(GetUriParam("amount") * $("#qu_id option:selected").attr("data-qu-factor")));
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) {
|
||||||
{
|
if (productDetails.last_shopping_location_id != null) {
|
||||||
if (productDetails.last_shopping_location_id != null)
|
|
||||||
{
|
|
||||||
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.last_shopping_location_id);
|
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.last_shopping_location_id);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.default_shopping_location_id);
|
Grocy.Components.ShoppingLocationPicker.SetId(productDetails.default_shopping_location_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) {
|
||||||
{
|
|
||||||
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
Grocy.Components.LocationPicker.SetId(productDetails.location.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productDetails.last_price == null || productDetails.last_price == 0)
|
if (productDetails.last_price == null || productDetails.last_price == 0) {
|
||||||
{
|
|
||||||
$("#price").val("")
|
$("#price").val("")
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#price').val(parseFloat(productDetails.last_price / $("#qu_id option:selected").attr("data-qu-factor")));
|
$('#price').val(parseFloat(productDetails.last_price / $("#qu_id option:selected").attr("data-qu-factor")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,65 +250,52 @@ if (Grocy.Components.ProductPicker !== undefined)
|
||||||
|
|
||||||
refreshPriceHint();
|
refreshPriceHint();
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
var minAmount = parseFloat(productDetails.product.tare_weight) / $("#qu_id option:selected").attr("data-qu-factor") + parseFloat(productDetails.stock_amount);
|
var minAmount = parseFloat(productDetails.product.tare_weight) / $("#qu_id option:selected").attr("data-qu-factor") + parseFloat(productDetails.stock_amount);
|
||||||
$("#display_amount").attr("min", minAmount);
|
$("#display_amount").attr("min", minAmount);
|
||||||
$("#tare-weight-handling-info").removeClass("d-none");
|
$("#tare-weight-handling-info").removeClass("d-none");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
}
|
}
|
||||||
|
|
||||||
PrefillBestBeforeDate(productDetails.product, productDetails.location);
|
PrefillBestBeforeDate(productDetails.product, productDetails.location);
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER) {
|
||||||
{
|
|
||||||
$("#stock_label_type").val(productDetails.product.default_stock_label_type);
|
$("#stock_label_type").val(productDetails.product.default_stock_label_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#display_amount").focus();
|
$("#display_amount").focus();
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
if (GetUriParam("flow") === "shoppinglistitemtostock" && BoolVal(Grocy.UserSettings.shopping_list_to_stock_workflow_auto_submit_when_prefilled) && document.getElementById("purchase-form").checkValidity() === true)
|
if (GetUriParam("flow") === "shoppinglistitemtostock" && BoolVal(Grocy.UserSettings.shopping_list_to_stock_workflow_auto_submit_when_prefilled) && document.getElementById("purchase-form").checkValidity() === true) {
|
||||||
{
|
|
||||||
$("#save-purchase-button").click();
|
$("#save-purchase-button").click();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshLocaleNumberInput();
|
RefreshLocaleNumberInput();
|
||||||
|
|
||||||
if (document.getElementById("product_id").getAttribute("barcode") != "null")
|
if (document.getElementById("product_id").getAttribute("barcode") != "null") {
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
||||||
function(barcodeResult)
|
function(barcodeResult) {
|
||||||
{
|
if (barcodeResult != null) {
|
||||||
if (barcodeResult != null)
|
|
||||||
{
|
|
||||||
var barcode = barcodeResult[0];
|
var barcode = barcodeResult[0];
|
||||||
$("#purchase-form").attr("data-used-barcode", barcode.id);
|
$("#purchase-form").attr("data-used-barcode", barcode.id);
|
||||||
|
|
||||||
if (barcode != null)
|
if (barcode != null) {
|
||||||
{
|
if (barcode.amount != null && !barcode.amount.isEmpty()) {
|
||||||
if (barcode.amount != null && !barcode.amount.isEmpty())
|
|
||||||
{
|
|
||||||
$("#display_amount").val(barcode.amount);
|
$("#display_amount").val(barcode.amount);
|
||||||
$("#display_amount").select();
|
$("#display_amount").select();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (barcode.qu_id != null && !barcode.qu_id.isEmpty())
|
if (barcode.qu_id != null && !barcode.qu_id.isEmpty()) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(barcode.qu_id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(barcode.qu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING && barcode.shopping_location_id != null)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING && barcode.shopping_location_id != null) {
|
||||||
{
|
|
||||||
Grocy.Components.ShoppingLocationPicker.SetId(barcode.shopping_location_id);
|
Grocy.Components.ShoppingLocationPicker.SetId(barcode.shopping_location_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (barcode.last_price != null && !barcode.last_price.isEmpty())
|
if (barcode.last_price != null && !barcode.last_price.isEmpty()) {
|
||||||
{
|
|
||||||
$("#price").val(barcode.last_price);
|
$("#price").val(barcode.last_price);
|
||||||
$("#price-type-total-price").click();
|
$("#price-type-total-price").click();
|
||||||
}
|
}
|
||||||
|
|
@ -376,22 +308,18 @@ if (Grocy.Components.ProductPicker !== undefined)
|
||||||
|
|
||||||
ScanModeSubmit(false);
|
ScanModeSubmit(false);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#purchase-form").removeAttr("data-used-barcode");
|
$("#purchase-form").removeAttr("data-used-barcode");
|
||||||
ScanModeSubmit();
|
ScanModeSubmit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#display_amount').trigger("keyup");
|
$('#display_amount').trigger("keyup");
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -399,51 +327,36 @@ if (Grocy.Components.ProductPicker !== undefined)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function PrefillBestBeforeDate(product, location)
|
function PrefillBestBeforeDate(product, location) {
|
||||||
{
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) {
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
|
||||||
{
|
|
||||||
var dueDays;
|
var dueDays;
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRODUCT_FREEZING && BoolVal(location.is_freezer))
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRODUCT_FREEZING && BoolVal(location.is_freezer)) {
|
||||||
{
|
|
||||||
dueDays = product.default_best_before_days_after_freezing;
|
dueDays = product.default_best_before_days_after_freezing;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
dueDays = product.default_best_before_days;
|
dueDays = product.default_best_before_days;
|
||||||
}
|
}
|
||||||
|
|
||||||
dueDays = parseFloat(dueDays);
|
dueDays = parseFloat(dueDays);
|
||||||
if (dueDays != 0)
|
if (dueDays != 0) {
|
||||||
{
|
if (dueDays == -1) {
|
||||||
if (dueDays == -1)
|
if (!$("#datetimepicker-shortcut").is(":checked")) {
|
||||||
{
|
|
||||||
if (!$("#datetimepicker-shortcut").is(":checked"))
|
|
||||||
{
|
|
||||||
$("#datetimepicker-shortcut").click();
|
$("#datetimepicker-shortcut").click();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.DateTimePicker.SetValue(moment().add(dueDays, 'days').format('YYYY-MM-DD'));
|
Grocy.Components.DateTimePicker.SetValue(moment().add(dueDays, 'days').format('YYYY-MM-DD'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.Components.LocationPicker !== undefined)
|
if (Grocy.Components.LocationPicker !== undefined) {
|
||||||
{
|
Grocy.Components.LocationPicker.GetPicker().on('change', function(e) {
|
||||||
Grocy.Components.LocationPicker.GetPicker().on('change', function(e)
|
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRODUCT_FREEZING) {
|
||||||
{
|
|
||||||
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRODUCT_FREEZING)
|
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/locations/' + Grocy.Components.LocationPicker.GetValue(),
|
Grocy.Api.Get('objects/locations/' + Grocy.Components.LocationPicker.GetValue(),
|
||||||
function(location)
|
function(location) {
|
||||||
{
|
|
||||||
PrefillBestBeforeDate(CurrentProductDetails.product, location);
|
PrefillBestBeforeDate(CurrentProductDetails.product, location);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {}
|
||||||
{ }
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -454,47 +367,35 @@ RefreshLocaleNumberInput();
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
|
|
||||||
if (Grocy.Components.ProductPicker)
|
if (Grocy.Components.ProductPicker) {
|
||||||
{
|
if (Grocy.Components.ProductPicker.InAnyFlow() === false && GetUriParam("embedded") === undefined) {
|
||||||
if (Grocy.Components.ProductPicker.InAnyFlow() === false && GetUriParam("embedded") === undefined)
|
Grocy.Components.ProductPicker.Focus();
|
||||||
{
|
} else {
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Validate();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
|
||||||
|
|
||||||
if (Grocy.Components.ProductPicker.InProductModifyWorkflow())
|
if (Grocy.Components.ProductPicker.InProductModifyWorkflow()) {
|
||||||
{
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#display_amount').on('focus', function(e)
|
$('#display_amount').on('focus', function(e) {
|
||||||
{
|
if (Grocy.Components.ProductPicker.GetValue().length === 0) {
|
||||||
if (Grocy.Components.ProductPicker.GetValue().length === 0)
|
Grocy.Components.ProductPicker.Focus();
|
||||||
{
|
} else {
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$(this).select();
|
$(this).select();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#price').on('focus', function(e)
|
$('#price').on('focus', function(e) {
|
||||||
{
|
|
||||||
$(this).select();
|
$(this).select();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#purchase-form input').keyup(function(event)
|
$('#purchase-form input').keyup(function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#purchase-form input').keydown(function(event)
|
$('#purchase-form input').keydown(function(event) {
|
||||||
{
|
|
||||||
if (event.keyCode === 13) //Enter
|
if (event.keyCode === 13) //Enter
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -502,191 +403,154 @@ $('#purchase-form input').keydown(function(event)
|
||||||
if (document.getElementById('purchase-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('purchase-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#save-purchase-button').click();
|
$('#save-purchase-button').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Grocy.Components.DateTimePicker)
|
if (Grocy.Components.DateTimePicker) {
|
||||||
{
|
Grocy.Components.DateTimePicker.GetInputElement().on('change', function(e) {
|
||||||
Grocy.Components.DateTimePicker.GetInputElement().on('change', function(e)
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.DateTimePicker.GetInputElement().on('keypress', function(e)
|
Grocy.Components.DateTimePicker.GetInputElement().on('keypress', function(e) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.Components.DateTimePicker2)
|
if (Grocy.Components.DateTimePicker2) {
|
||||||
{
|
Grocy.Components.DateTimePicker2.GetInputElement().on('change', function(e) {
|
||||||
Grocy.Components.DateTimePicker2.GetInputElement().on('change', function(e)
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.DateTimePicker2.GetInputElement().on('keypress', function(e)
|
Grocy.Components.DateTimePicker2.GetInputElement().on('keypress', function(e) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.DateTimePicker2.GetInputElement().trigger("input");
|
Grocy.Components.DateTimePicker2.GetInputElement().trigger("input");
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#price').on('keyup', function(e)
|
$('#price').on('keyup', function(e) {
|
||||||
{
|
|
||||||
refreshPriceHint();
|
refreshPriceHint();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#price-type-unit-price').on('change', function(e)
|
$('#price-type-unit-price').on('change', function(e) {
|
||||||
{
|
|
||||||
refreshPriceHint();
|
refreshPriceHint();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#price-type-total-price').on('change', function(e)
|
$('#price-type-total-price').on('change', function(e) {
|
||||||
{
|
|
||||||
refreshPriceHint();
|
refreshPriceHint();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#display_amount').on('change', function(e)
|
$('#display_amount').on('change', function(e) {
|
||||||
{
|
|
||||||
refreshPriceHint();
|
refreshPriceHint();
|
||||||
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
Grocy.FrontendHelpers.ValidateForm('purchase-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
function refreshPriceHint()
|
function refreshPriceHint() {
|
||||||
{
|
if ($('#amount').val() == 0 || $('#price').val() == 0) {
|
||||||
if ($('#amount').val() == 0 || $('#price').val() == 0)
|
|
||||||
{
|
|
||||||
$('#price-hint').text("");
|
$('#price-hint').text("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($("input[name='price-type']:checked").val() == "total-price" || $("#qu_id").attr("data-destination-qu-name") != $("#qu_id option:selected").text())
|
if ($("input[name='price-type']:checked").val() == "total-price" || $("#qu_id").attr("data-destination-qu-name") != $("#qu_id option:selected").text()) {
|
||||||
{
|
|
||||||
var amount = $('#display_amount').val();
|
var amount = $('#display_amount').val();
|
||||||
if (BoolVal(CurrentProductDetails.product.enable_tare_weight_handling))
|
if (BoolVal(CurrentProductDetails.product.enable_tare_weight_handling)) {
|
||||||
{
|
|
||||||
amount -= parseFloat(CurrentProductDetails.product.tare_weight);
|
amount -= parseFloat(CurrentProductDetails.product.tare_weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
var price = parseFloat($('#price').val() * $("#qu_id option:selected").attr("data-qu-factor")).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
var price = parseFloat($('#price').val() * $("#qu_id option:selected").attr("data-qu-factor")).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
||||||
if ($("input[name='price-type']:checked").val() == "total-price")
|
if ($("input[name='price-type']:checked").val() == "total-price") {
|
||||||
{
|
|
||||||
price = parseFloat(price / amount).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
price = parseFloat(price / amount).toFixed(Grocy.UserSettings.stock_decimal_places_prices);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#price-hint').text(__t('means %1$s per %2$s', price.toLocaleString(undefined, { style: "currency", currency: Grocy.Currency, minimumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices }), $("#qu_id").attr("data-destination-qu-name")));
|
$('#price-hint').text(__t('means %1$s per %2$s', price.toLocaleString(undefined, {
|
||||||
}
|
style: "currency",
|
||||||
else
|
currency: Grocy.Currency,
|
||||||
{
|
minimumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices,
|
||||||
|
maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_prices
|
||||||
|
}), $("#qu_id").attr("data-destination-qu-name")));
|
||||||
|
} else {
|
||||||
$('#price-hint').text("");
|
$('#price-hint').text("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function UndoStockBooking(bookingId)
|
function UndoStockBooking(bookingId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
toastr.success(__t("Booking successfully undone"));
|
toastr.success(__t("Booking successfully undone"));
|
||||||
|
|
||||||
Grocy.Api.Get('stock/bookings/' + bookingId.toString(),
|
Grocy.Api.Get('stock/bookings/' + bookingId.toString(),
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
window.postMessage(WindowMessageBag("ProductChanged", result.product_id), Grocy.BaseUrl);
|
window.postMessage(WindowMessageBag("ProductChanged", result.product_id), Grocy.BaseUrl);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function UndoStockTransaction(transactionId)
|
function UndoStockTransaction(transactionId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
toastr.success(__t("Transaction successfully undone"));
|
toastr.success(__t("Transaction successfully undone"));
|
||||||
|
|
||||||
Grocy.Api.Get('stock/transactions/' + transactionId.toString(),
|
Grocy.Api.Get('stock/transactions/' + transactionId.toString(),
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
window.postMessage(WindowMessageBag("ProductChanged", result[0].product_id), Grocy.BaseUrl);
|
window.postMessage(WindowMessageBag("ProductChanged", result[0].product_id), Grocy.BaseUrl);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
$("#scan-mode").on("change", function(e)
|
$("#scan-mode").on("change", function(e) {
|
||||||
{
|
if ($(this).prop("checked")) {
|
||||||
if ($(this).prop("checked"))
|
|
||||||
{
|
|
||||||
Grocy.UISound.AskForPermission();
|
Grocy.UISound.AskForPermission();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#scan-mode-button").on("click", function(e)
|
$("#scan-mode-button").on("click", function(e) {
|
||||||
{
|
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
$("#scan-mode").click();
|
$("#scan-mode").click();
|
||||||
$("#scan-mode-button").toggleClass("btn-success").toggleClass("btn-danger");
|
$("#scan-mode-button").toggleClass("btn-success").toggleClass("btn-danger");
|
||||||
if ($("#scan-mode").prop("checked"))
|
if ($("#scan-mode").prop("checked")) {
|
||||||
{
|
|
||||||
$("#scan-mode-status").text(__t("on"));
|
$("#scan-mode-status").text(__t("on"));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#scan-mode-status").text(__t("off"));
|
$("#scan-mode-status").text(__t("off"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#qu_id').on('change', function(e)
|
$('#qu_id').on('change', function(e) {
|
||||||
{
|
|
||||||
var priceTypeUnitPrice = $("#price-type-unit-price");
|
var priceTypeUnitPrice = $("#price-type-unit-price");
|
||||||
var priceTypeUnitPriceLabel = $("[for=" + priceTypeUnitPrice.attr("id") + "]");
|
var priceTypeUnitPriceLabel = $("[for=" + priceTypeUnitPrice.attr("id") + "]");
|
||||||
priceTypeUnitPriceLabel.text($("#qu_id option:selected").text() + " " + __t("price"));
|
priceTypeUnitPriceLabel.text($("#qu_id option:selected").text() + " " + __t("price"));
|
||||||
refreshPriceHint();
|
refreshPriceHint();
|
||||||
});
|
});
|
||||||
|
|
||||||
function ScanModeSubmit(singleUnit = true)
|
function ScanModeSubmit(singleUnit = true) {
|
||||||
{
|
if (BoolVal(Grocy.UserSettings.scan_mode_purchase_enabled)) {
|
||||||
if (BoolVal(Grocy.UserSettings.scan_mode_purchase_enabled))
|
if (singleUnit) {
|
||||||
{
|
|
||||||
if (singleUnit)
|
|
||||||
{
|
|
||||||
$("#display_amount").val(1);
|
$("#display_amount").val(1);
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm("purchase-form");
|
Grocy.FrontendHelpers.ValidateForm("purchase-form");
|
||||||
if (document.getElementById("purchase-form").checkValidity() === true)
|
if (document.getElementById("purchase-form").checkValidity() === true) {
|
||||||
{
|
|
||||||
$('#save-purchase-button').click();
|
$('#save-purchase-button').click();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
toastr.warning(__t("Scan mode is on but not all required fields could be populated automatically"));
|
toastr.warning(__t("Scan mode is on but not all required fields could be populated automatically"));
|
||||||
Grocy.UISound.Error();
|
Grocy.UISound.Error();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
Grocy.RecipePosFormInitialLoadDone = false;
|
Grocy.RecipePosFormInitialLoadDone = false;
|
||||||
|
|
||||||
$('#save-recipe-pos-button').on('click', function(e)
|
$('#save-recipe-pos-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -15,31 +13,24 @@ $('#save-recipe-pos-button').on('click', function(e)
|
||||||
|
|
||||||
Grocy.FrontendHelpers.BeginUiBusy("recipe-pos-form");
|
Grocy.FrontendHelpers.BeginUiBusy("recipe-pos-form");
|
||||||
|
|
||||||
if (Grocy.EditMode === 'create')
|
if (Grocy.EditMode === 'create') {
|
||||||
{
|
|
||||||
Grocy.Api.Post('objects/recipes_pos', jsonData,
|
Grocy.Api.Post('objects/recipes_pos', jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
window.parent.postMessage(WindowMessageBag("IngredientsChanged"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("IngredientsChanged"), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("recipe-pos-form");
|
Grocy.FrontendHelpers.EndUiBusy("recipe-pos-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Api.Put('objects/recipes_pos/' + Grocy.EditObjectId, jsonData,
|
Grocy.Api.Put('objects/recipes_pos/' + Grocy.EditObjectId, jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
window.parent.postMessage(WindowMessageBag("IngredientsChanged"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("IngredientsChanged"), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("recipe-pos-form");
|
Grocy.FrontendHelpers.EndUiBusy("recipe-pos-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response)
|
||||||
}
|
}
|
||||||
|
|
@ -47,33 +38,25 @@ $('#save-recipe-pos-button').on('click', function(e)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
{
|
|
||||||
var productId = $(e.target).val();
|
var productId = $(e.target).val();
|
||||||
|
|
||||||
if (productId)
|
if (productId) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductCard.Refresh(productId);
|
Grocy.Components.ProductCard.Refresh(productId);
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
if (!Grocy.RecipePosFormInitialLoadDone) {
|
||||||
if (!Grocy.RecipePosFormInitialLoadDone)
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id, true);
|
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id, true);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Grocy.Mode == "create")
|
if (Grocy.Mode == "create") {
|
||||||
{
|
|
||||||
$("#not_check_stock_fulfillment").prop("checked", productDetails.product.not_check_stock_fulfillment_for_recipes == 1);
|
$("#not_check_stock_fulfillment").prop("checked", productDetails.product.not_check_stock_fulfillment_for_recipes == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$("#only_check_single_unit_in_stock").prop("checked") && Grocy.RecipePosFormInitialLoadDone)
|
if (!$("#only_check_single_unit_in_stock").prop("checked") && Grocy.RecipePosFormInitialLoadDone) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,8 +64,7 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
||||||
Grocy.RecipePosFormInitialLoadDone = true;
|
Grocy.RecipePosFormInitialLoadDone = true;
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -91,41 +73,32 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
||||||
|
|
||||||
if (Grocy.Components.ProductPicker.InProductAddWorkflow() === false)
|
if (Grocy.Components.ProductPicker.InProductAddWorkflow() === false) {
|
||||||
{
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
}
|
}
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
Grocy.Components.ProductPicker.Validate();
|
||||||
|
|
||||||
if (Grocy.EditMode == "create")
|
if (Grocy.EditMode == "create") {
|
||||||
{
|
|
||||||
Grocy.RecipePosFormInitialLoadDone = true;
|
Grocy.RecipePosFormInitialLoadDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#display_amount').on('focus', function(e)
|
$('#display_amount').on('focus', function(e) {
|
||||||
{
|
if (Grocy.Components.ProductPicker.GetValue().length === 0) {
|
||||||
if (Grocy.Components.ProductPicker.GetValue().length === 0)
|
Grocy.Components.ProductPicker.Focus();
|
||||||
{
|
} else {
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$(this).select();
|
$(this).select();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#recipe-pos-form input').keyup(function(event)
|
$('#recipe-pos-form input').keyup(function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#qu_id').change(function(event)
|
$('#qu_id').change(function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
Grocy.FrontendHelpers.ValidateForm('recipe-pos-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#recipe-pos-form input').keydown(function(event)
|
$('#recipe-pos-form input').keydown(function(event) {
|
||||||
{
|
|
||||||
if (event.keyCode === 13) //Enter
|
if (event.keyCode === 13) //Enter
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -133,32 +106,25 @@ $('#recipe-pos-form input').keydown(function(event)
|
||||||
if (document.getElementById('recipe-pos-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('recipe-pos-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#save-recipe-pos-button').click();
|
$('#save-recipe-pos-button').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#only_check_single_unit_in_stock").on("change", function()
|
$("#only_check_single_unit_in_stock").on("change", function() {
|
||||||
{
|
if (this.checked) {
|
||||||
if (this.checked)
|
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
||||||
Grocy.Components.ProductAmountPicker.AllowAnyQu(true);
|
Grocy.Components.ProductAmountPicker.AllowAnyQu(true);
|
||||||
Grocy.FrontendHelpers.ValidateForm("recipe-pos-form");
|
Grocy.FrontendHelpers.ValidateForm("recipe-pos-form");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", "0");
|
$("#display_amount").attr("min", "0");
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger("change"); // Selects the default quantity unit of the selected product
|
Grocy.Components.ProductPicker.Validate(); // Selects the default quantity unit of the selected product
|
||||||
Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled = false;
|
Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled = false;
|
||||||
Grocy.FrontendHelpers.ValidateForm("recipe-pos-form");
|
Grocy.FrontendHelpers.ValidateForm("recipe-pos-form");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if ($("#only_check_single_unit_in_stock").prop("checked"))
|
if ($("#only_check_single_unit_in_stock").prop("checked")) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.AllowAnyQu(true);
|
Grocy.Components.ProductAmountPicker.AllowAnyQu(true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,40 @@
|
||||||
Grocy.ShoppingListItemFormInitialLoadDone = false;
|
Grocy.ShoppingListItemFormInitialLoadDone = false;
|
||||||
|
|
||||||
$('#save-shoppinglist-button').on('click', function(e)
|
$('#save-shoppinglist-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonData = $('#shoppinglist-form').serializeJSON();
|
var jsonData = $('#shoppinglist-form').serializeJSON();
|
||||||
var displayAmount = parseFloat(jsonData.display_amount);
|
var displayAmount = parseFloat(jsonData.display_amount);
|
||||||
if (!jsonData.product_id)
|
if (!jsonData.product_id) {
|
||||||
{
|
|
||||||
jsonData.amount = jsonData.display_amount;
|
jsonData.amount = jsonData.display_amount;
|
||||||
}
|
}
|
||||||
delete jsonData.display_amount;
|
delete jsonData.display_amount;
|
||||||
|
|
||||||
Grocy.FrontendHelpers.BeginUiBusy("shoppinglist-form");
|
Grocy.FrontendHelpers.BeginUiBusy("shoppinglist-form");
|
||||||
|
|
||||||
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct")
|
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct") {
|
||||||
{
|
|
||||||
var jsonDataBarcode = {};
|
var jsonDataBarcode = {};
|
||||||
jsonDataBarcode.barcode = GetUriParam("barcode");
|
jsonDataBarcode.barcode = GetUriParam("barcode");
|
||||||
jsonDataBarcode.product_id = jsonData.product_id;
|
jsonDataBarcode.product_id = jsonData.product_id;
|
||||||
|
|
||||||
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
||||||
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
||||||
$('#barcode-lookup-hint').removeClass('d-none');
|
$('#barcode-lookup-hint').removeClass('d-none');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("shoppinglist-form");
|
Grocy.FrontendHelpers.EndUiBusy("shoppinglist-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("updateexistingproduct") !== undefined)
|
if (GetUriParam("updateexistingproduct") !== undefined) {
|
||||||
{
|
|
||||||
jsonData.product_amount = jsonData.amount;
|
jsonData.product_amount = jsonData.amount;
|
||||||
delete jsonData.amount;
|
delete jsonData.amount;
|
||||||
|
|
||||||
|
|
@ -49,118 +42,96 @@ $('#save-shoppinglist-button').on('click', function(e)
|
||||||
delete jsonData.shopping_list_id;
|
delete jsonData.shopping_list_id;
|
||||||
|
|
||||||
Grocy.Api.Post('stock/shoppinglist/add-product', jsonData,
|
Grocy.Api.Post('stock/shoppinglist/add-product', jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
Grocy.EditObjectId = result.created_object_id;
|
Grocy.EditObjectId = result.created_object_id;
|
||||||
Grocy.Components.UserfieldsForm.Save();
|
Grocy.Components.UserfieldsForm.Save();
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonData.product_id,
|
Grocy.Api.Get('stock/products/' + jsonData.product_id,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts
|
||||||
|
}) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.location.href = U('/shoppinglist?list=' + $("#shopping_list_id").val().toString());
|
window.location.href = U('/shoppinglist?list=' + $("#shopping_list_id").val().toString());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("shoppinglist-form");
|
Grocy.FrontendHelpers.EndUiBusy("shoppinglist-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else if (Grocy.EditMode === 'create') {
|
||||||
else if (Grocy.EditMode === 'create')
|
|
||||||
{
|
|
||||||
Grocy.Api.Post('objects/shopping_list', jsonData,
|
Grocy.Api.Post('objects/shopping_list', jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
Grocy.EditObjectId = result.created_object_id;
|
Grocy.EditObjectId = result.created_object_id;
|
||||||
Grocy.Components.UserfieldsForm.Save();
|
Grocy.Components.UserfieldsForm.Save();
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
if (jsonData.product_id) {
|
||||||
if (jsonData.product_id)
|
|
||||||
{
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonData.product_id,
|
Grocy.Api.Get('stock/products/' + jsonData.product_id,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts
|
||||||
|
}) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.location.href = U('/shoppinglist?list=' + $("#shopping_list_id").val().toString());
|
window.location.href = U('/shoppinglist?list=' + $("#shopping_list_id").val().toString());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("shoppinglist-form");
|
Grocy.FrontendHelpers.EndUiBusy("shoppinglist-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Api.Put('objects/shopping_list/' + Grocy.EditObjectId, jsonData,
|
Grocy.Api.Put('objects/shopping_list/' + Grocy.EditObjectId, jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
Grocy.Components.UserfieldsForm.Save();
|
Grocy.Components.UserfieldsForm.Save();
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
if (jsonData.product_id) {
|
||||||
if (jsonData.product_id)
|
|
||||||
{
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonData.product_id,
|
Grocy.Api.Get('stock/products/' + jsonData.product_id,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts
|
||||||
|
}) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
window.location.href = U('/shoppinglist?list=' + $("#shopping_list_id").val().toString());
|
window.location.href = U('/shoppinglist?list=' + $("#shopping_list_id").val().toString());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("shoppinglist-form");
|
Grocy.FrontendHelpers.EndUiBusy("shoppinglist-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
|
|
@ -168,74 +139,57 @@ $('#save-shoppinglist-button').on('click', function(e)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
{
|
|
||||||
var productId = $(e.target).val();
|
var productId = $(e.target).val();
|
||||||
|
|
||||||
if (productId)
|
if (productId) {
|
||||||
{
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
if (!Grocy.ShoppingListItemFormInitialLoadDone) {
|
||||||
if (!Grocy.ShoppingListItemFormInitialLoadDone)
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id, true);
|
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id, true);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.default_quantity_unit_purchase.id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.default_quantity_unit_purchase.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($("#display_amount").val().toString().isEmpty())
|
if ($("#display_amount").val().toString().isEmpty()) {
|
||||||
{
|
|
||||||
$("#display_amount").val(1);
|
$("#display_amount").val(1);
|
||||||
$("#display_amount").trigger("change");
|
$("#display_amount").trigger("change");
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#display_amount').focus();
|
$('#display_amount').trigger('focus');
|
||||||
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
||||||
Grocy.ShoppingListItemFormInitialLoadDone = true;
|
Grocy.ShoppingListItemFormInitialLoadDone = true;
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: what is the point of this?
|
||||||
$("#note").trigger("input");
|
$("#note").trigger("input");
|
||||||
$("#product_id").trigger("input");
|
// Grocy.Components.ProductPicker.GetPicker().trigger("input");
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
||||||
setTimeout(function()
|
setTimeout(function() {
|
||||||
{
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
}, 250);
|
}, 250);
|
||||||
|
|
||||||
if (Grocy.EditMode === "edit")
|
if (Grocy.EditMode == "create") {
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Grocy.EditMode == "create")
|
|
||||||
{
|
|
||||||
Grocy.ShoppingListItemFormInitialLoadDone = true;
|
Grocy.ShoppingListItemFormInitialLoadDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#display_amount').on('focus', function(e)
|
$('#display_amount').on('focus', function(e) {
|
||||||
{
|
$(this).trigger('select');
|
||||||
$(this).select();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#shoppinglist-form input').keyup(function(event)
|
$('#shoppinglist-form input').on('keyup', function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#shoppinglist-form input').keydown(function(event)
|
$('#shoppinglist-form input').on('keydown', function(event) {
|
||||||
{
|
|
||||||
if (event.keyCode === 13) //Enter
|
if (event.keyCode === 13) //Enter
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -243,52 +197,48 @@ $('#shoppinglist-form input').keydown(function(event)
|
||||||
if (document.getElementById('shoppinglist-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('shoppinglist-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#save-shoppinglist-button').click();
|
$('#save-shoppinglist-button').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (GetUriParam("list") !== undefined)
|
if (GetUriParam("list") !== undefined) {
|
||||||
{
|
|
||||||
$("#shopping_list_id").val(GetUriParam("list"));
|
$("#shopping_list_id").val(GetUriParam("list"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("amount") !== undefined)
|
if (GetUriParam("amount") !== undefined) {
|
||||||
{
|
|
||||||
$("#display_amount").val(parseFloat(GetUriParam("amount")));
|
$("#display_amount").val(parseFloat(GetUriParam("amount")));
|
||||||
RefreshLocaleNumberInput();
|
RefreshLocaleNumberInput();
|
||||||
$(".input-group-productamountpicker").trigger("change");
|
$(".input-group-productamountpicker").trigger("change");
|
||||||
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
if (GetUriParam("product") !== undefined) {
|
||||||
if (GetUriParam("product") !== undefined)
|
$("#display_amount").trigger('focus');
|
||||||
{
|
} else {
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
Grocy.Components.ProductPicker.Focus();
|
||||||
$("#display_amount").focus();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var eitherRequiredFields = $("#product_id,#product_id_text_input,#note");
|
$("#note").prop('required', "");
|
||||||
eitherRequiredFields.prop('required', "");
|
$("#note").on('input', function() {
|
||||||
eitherRequiredFields.on('input', function()
|
if (!$(this).val().length) {
|
||||||
{
|
Grocy.Components.ProductPicker.Require();
|
||||||
eitherRequiredFields.not(this).prop('required', !$(this).val().length);
|
} else {
|
||||||
|
Grocy.Components.ProductPicker.Optional();
|
||||||
|
}
|
||||||
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Grocy.Components.ProductPicker.OnChange(function() {
|
||||||
|
$("#note").prop('required', !$(this).val().length);
|
||||||
|
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
|
||||||
|
});
|
||||||
|
|
||||||
if (GetUriParam("product-name") != null)
|
if (GetUriParam("product-name") != null) {
|
||||||
{
|
Grocy.Components.ProductPicker.Validate();
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Components.UserfieldsForm.Load();
|
Grocy.Components.UserfieldsForm.Load();
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,68 @@
|
||||||
var stockEntriesTable = $('#stockentries-table').DataTable({
|
var stockEntriesTable = $('#stockentries-table').DataTable({
|
||||||
'order': [[2, 'asc']],
|
'order': [
|
||||||
'columnDefs': [
|
[2, 'asc']
|
||||||
{ 'orderable': false, 'targets': 0 },
|
],
|
||||||
{ 'searchable': false, "targets": 0 },
|
'columnDefs': [{
|
||||||
{ 'visible': false, 'targets': 10 },
|
'orderable': false,
|
||||||
{ "type": "num", "targets": 1 },
|
'targets': 0
|
||||||
{ "type": "num", "targets": 3 },
|
},
|
||||||
{ "type": "html", "targets": 4 },
|
{
|
||||||
{ "type": "html-num-fmt", "targets": 7 },
|
'searchable': false,
|
||||||
{ "type": "html", "targets": 8 },
|
"targets": 0
|
||||||
{ "type": "html", "targets": 9 }
|
},
|
||||||
|
{
|
||||||
|
'visible': false,
|
||||||
|
'targets': 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "num",
|
||||||
|
"targets": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "num",
|
||||||
|
"targets": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "html",
|
||||||
|
"targets": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "html-num-fmt",
|
||||||
|
"targets": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "html",
|
||||||
|
"targets": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "html",
|
||||||
|
"targets": 9
|
||||||
|
}
|
||||||
].concat($.fn.dataTable.defaults.columnDefs)
|
].concat($.fn.dataTable.defaults.columnDefs)
|
||||||
});
|
});
|
||||||
$('#stockentries-table tbody').removeClass("d-none");
|
$('#stockentries-table tbody').removeClass("d-none");
|
||||||
stockEntriesTable.columns.adjust().draw();
|
stockEntriesTable.columns.adjust().draw();
|
||||||
|
|
||||||
$.fn.dataTable.ext.search.push(function(settings, data, dataIndex)
|
$.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
|
||||||
{
|
|
||||||
var productId = Grocy.Components.ProductPicker.GetValue();
|
var productId = Grocy.Components.ProductPicker.GetValue();
|
||||||
|
|
||||||
if ((isNaN(productId) || productId == "" || productId == data[1]))
|
if ((isNaN(productId) || productId == "" || productId == data[1])) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#clear-filter-button").on("click", function()
|
$("#clear-filter-button").on("click", function() {
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.Clear();
|
Grocy.Components.ProductPicker.Clear();
|
||||||
stockEntriesTable.draw();
|
stockEntriesTable.draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
{
|
|
||||||
stockEntriesTable.draw();
|
stockEntriesTable.draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetInputElement().on('keyup', function(e)
|
$(document).on('click', '.stock-consume-button', function(e) {
|
||||||
{
|
|
||||||
stockEntriesTable.draw();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on('click', '.stock-consume-button', function(e)
|
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// Remove the focus from the current button
|
// Remove the focus from the current button
|
||||||
|
|
@ -61,15 +79,21 @@ $(document).on('click', '.stock-consume-button', function(e)
|
||||||
|
|
||||||
var wasSpoiled = $(e.currentTarget).hasClass("stock-consume-button-spoiled");
|
var wasSpoiled = $(e.currentTarget).hasClass("stock-consume-button-spoiled");
|
||||||
|
|
||||||
Grocy.Api.Post('stock/products/' + productId + '/consume', { 'amount': consumeAmount, 'spoiled': wasSpoiled, 'location_id': locationId, 'stock_entry_id': specificStockEntryId, 'exact_amount': true },
|
Grocy.Api.Post('stock/products/' + productId + '/consume', {
|
||||||
function(bookingResponse)
|
'amount': consumeAmount,
|
||||||
{
|
'spoiled': wasSpoiled,
|
||||||
|
'location_id': locationId,
|
||||||
|
'stock_entry_id': specificStockEntryId,
|
||||||
|
'exact_amount': true
|
||||||
|
},
|
||||||
|
function(bookingResponse) {
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
var toastMessage = __t('Removed %1$s of %2$s from stock', parseFloat(consumeAmount).toLocaleString({
|
||||||
var toastMessage = __t('Removed %1$s of %2$s from stock', parseFloat(consumeAmount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockBookingEntry(' + bookingResponse[0].id + ',' + stockRowId + ')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
minimumFractionDigits: 0,
|
||||||
if (wasSpoiled)
|
maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts
|
||||||
{
|
}) + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockBookingEntry(' + bookingResponse[0].id + ',' + stockRowId + ')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
||||||
|
if (wasSpoiled) {
|
||||||
toastMessage += " (" + __t("Spoiled") + ")";
|
toastMessage += " (" + __t("Spoiled") + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,23 +101,20 @@ $(document).on('click', '.stock-consume-button', function(e)
|
||||||
RefreshStockEntryRow(stockRowId);
|
RefreshStockEntryRow(stockRowId);
|
||||||
toastr.success(toastMessage);
|
toastr.success(toastMessage);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.product-open-button', function(e)
|
$(document).on('click', '.product-open-button', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// Remove the focus from the current button
|
// Remove the focus from the current button
|
||||||
|
|
@ -109,65 +130,55 @@ $(document).on('click', '.product-open-button', function(e)
|
||||||
var stockRowId = $(e.currentTarget).attr('data-stockrow-id');
|
var stockRowId = $(e.currentTarget).attr('data-stockrow-id');
|
||||||
var button = $(e.currentTarget);
|
var button = $(e.currentTarget);
|
||||||
|
|
||||||
Grocy.Api.Post('stock/products/' + productId + '/open', { 'amount': 1, 'stock_entry_id': specificStockEntryId },
|
Grocy.Api.Post('stock/products/' + productId + '/open', {
|
||||||
function(bookingResponse)
|
'amount': 1,
|
||||||
{
|
'stock_entry_id': specificStockEntryId
|
||||||
|
},
|
||||||
|
function(bookingResponse) {
|
||||||
button.addClass("disabled");
|
button.addClass("disabled");
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
toastr.success(__t('Marked %1$s of %2$s as opened', 1 + " " + productQuName, productName) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockBookingEntry(' + bookingResponse[0].id + ',' + stockRowId + ')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>');
|
toastr.success(__t('Marked %1$s of %2$s as opened', 1 + " " + productQuName, productName) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockBookingEntry(' + bookingResponse[0].id + ',' + stockRowId + ')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>');
|
||||||
RefreshStockEntryRow(stockRowId);
|
RefreshStockEntryRow(stockRowId);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("click", ".stock-name-cell", function(e)
|
$(document).on("click", ".stock-name-cell", function(e) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductCard.Refresh($(e.currentTarget).attr("data-stock-id"));
|
Grocy.Components.ProductCard.Refresh($(e.currentTarget).attr("data-stock-id"));
|
||||||
$("#stockentry-productcard-modal").modal("show");
|
$("#stockentry-productcard-modal").modal("show");
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '.stockentry-grocycode-label-print', function(e)
|
$(document).on('click', '.stockentry-grocycode-label-print', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
|
|
||||||
var stockId = $(e.currentTarget).attr('data-stock-id');
|
var stockId = $(e.currentTarget).attr('data-stock-id');
|
||||||
Grocy.Api.Get('stock/entry/' + stockId + '/printlabel', function(labelData)
|
Grocy.Api.Get('stock/entry/' + stockId + '/printlabel', function(labelData) {
|
||||||
{
|
if (Grocy.Webhooks.labelprinter !== undefined) {
|
||||||
if (Grocy.Webhooks.labelprinter !== undefined)
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, labelData);
|
Grocy.FrontendHelpers.RunWebhook(Grocy.Webhooks.labelprinter, labelData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function RefreshStockEntryRow(stockRowId)
|
function RefreshStockEntryRow(stockRowId) {
|
||||||
{
|
|
||||||
Grocy.Api.Get("stock/entry/" + stockRowId,
|
Grocy.Api.Get("stock/entry/" + stockRowId,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
var stockRow = $('#stock-' + stockRowId + '-row');
|
var stockRow = $('#stock-' + stockRowId + '-row');
|
||||||
|
|
||||||
// If the stock row not exists / is invisible (happens after consume/undo because the undone new stock row has different id), just reload the page for now
|
// If the stock row not exists / is invisible (happens after consume/undo because the undone new stock row has different id), just reload the page for now
|
||||||
if (!stockRow.length || stockRow.hasClass("d-none"))
|
if (!stockRow.length || stockRow.hasClass("d-none")) {
|
||||||
{
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == null || result.amount == 0)
|
if (result == null || result.amount == 0) {
|
||||||
{
|
animateCSS("#stock-" + stockRowId + "-row", "fadeOut", function() {
|
||||||
animateCSS("#stock-" + stockRowId + "-row", "fadeOut", function()
|
|
||||||
{
|
|
||||||
$("#stock-" + stockRowId + "-row").addClass("d-none");
|
$("#stock-" + stockRowId + "-row").addClass("d-none");
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
var dueThreshold = moment().add(Grocy.UserSettings.stock_due_soon_days, "days");
|
var dueThreshold = moment().add(Grocy.UserSettings.stock_due_soon_days, "days");
|
||||||
var now = moment();
|
var now = moment();
|
||||||
var bestBeforeDate = moment(result.best_before_date);
|
var bestBeforeDate = moment(result.best_before_date);
|
||||||
|
|
@ -177,19 +188,13 @@ function RefreshStockEntryRow(stockRowId)
|
||||||
stockRow.removeClass("table-info");
|
stockRow.removeClass("table-info");
|
||||||
stockRow.removeClass("d-none");
|
stockRow.removeClass("d-none");
|
||||||
stockRow.removeAttr("style");
|
stockRow.removeAttr("style");
|
||||||
if (now.isAfter(bestBeforeDate))
|
if (now.isAfter(bestBeforeDate)) {
|
||||||
{
|
if (stockRow.attr("data-due-type") == 1) {
|
||||||
if (stockRow.attr("data-due-type") == 1)
|
|
||||||
{
|
|
||||||
stockRow.addClass("table-secondary");
|
stockRow.addClass("table-secondary");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
stockRow.addClass("table-danger");
|
stockRow.addClass("table-danger");
|
||||||
}
|
}
|
||||||
}
|
} else if (bestBeforeDate.isBefore(dueThreshold)) {
|
||||||
else if (bestBeforeDate.isBefore(dueThreshold))
|
|
||||||
{
|
|
||||||
stockRow.addClass("table-warning");
|
stockRow.addClass("table-warning");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,15 +208,13 @@ function RefreshStockEntryRow(stockRowId)
|
||||||
|
|
||||||
var locationName = "";
|
var locationName = "";
|
||||||
Grocy.Api.Get("objects/locations/" + result.location_id,
|
Grocy.Api.Get("objects/locations/" + result.location_id,
|
||||||
function(locationResult)
|
function(locationResult) {
|
||||||
{
|
|
||||||
locationName = locationResult.name;
|
locationName = locationResult.name;
|
||||||
|
|
||||||
$('#stock-' + stockRowId + '-location').attr('data-location-id', result.location_id);
|
$('#stock-' + stockRowId + '-location').attr('data-location-id', result.location_id);
|
||||||
$('#stock-' + stockRowId + '-location').text(locationName);
|
$('#stock-' + stockRowId + '-location').text(locationName);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -222,74 +225,61 @@ function RefreshStockEntryRow(stockRowId)
|
||||||
|
|
||||||
var shoppingLocationName = "";
|
var shoppingLocationName = "";
|
||||||
Grocy.Api.Get("objects/shopping_locations/" + result.shopping_location_id,
|
Grocy.Api.Get("objects/shopping_locations/" + result.shopping_location_id,
|
||||||
function(shoppingLocationResult)
|
function(shoppingLocationResult) {
|
||||||
{
|
|
||||||
shoppingLocationName = shoppingLocationResult.name;
|
shoppingLocationName = shoppingLocationResult.name;
|
||||||
|
|
||||||
$('#stock-' + stockRowId + '-shopping-location').attr('data-shopping-location-id', result.location_id);
|
$('#stock-' + stockRowId + '-shopping-location').attr('data-shopping-location-id', result.location_id);
|
||||||
$('#stock-' + stockRowId + '-shopping-location').text(shoppingLocationName);
|
$('#stock-' + stockRowId + '-shopping-location').text(shoppingLocationName);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result.open == 1)
|
if (result.open == 1) {
|
||||||
{
|
|
||||||
$('#stock-' + stockRowId + '-opened-amount').text(__t('Opened'));
|
$('#stock-' + stockRowId + '-opened-amount').text(__t('Opened'));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#stock-' + stockRowId + '-opened-amount').text("");
|
$('#stock-' + stockRowId + '-opened-amount').text("");
|
||||||
$(".product-open-button[data-stockrow-id='" + stockRowId + "']").removeClass("disabled");
|
$(".product-open-button[data-stockrow-id='" + stockRowId + "']").removeClass("disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needs to be delayed because of the animation above the date-text would be wrong if fired immediately...
|
// Needs to be delayed because of the animation above the date-text would be wrong if fired immediately...
|
||||||
setTimeout(function()
|
setTimeout(function() {
|
||||||
{
|
|
||||||
RefreshContextualTimeago("#stock-" + stockRowId + "-row");
|
RefreshContextualTimeago("#stock-" + stockRowId + "-row");
|
||||||
RefreshLocaleNumberDisplay("#stock-" + stockRowId + "-row");
|
RefreshLocaleNumberDisplay("#stock-" + stockRowId + "-row");
|
||||||
}, 600);
|
}, 600);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy();
|
Grocy.FrontendHelpers.EndUiBusy();
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(window).on("message", function(e)
|
$(window).on("message", function(e) {
|
||||||
{
|
|
||||||
var data = e.originalEvent.data;
|
var data = e.originalEvent.data;
|
||||||
|
|
||||||
if (data.Message === "StockEntryChanged")
|
if (data.Message === "StockEntryChanged") {
|
||||||
{
|
|
||||||
RefreshStockEntryRow(data.Payload);
|
RefreshStockEntryRow(data.Payload);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
Grocy.Components.ProductPicker.Validate();
|
||||||
|
|
||||||
function UndoStockBookingEntry(bookingId, stockRowId)
|
function UndoStockBookingEntry(bookingId, stockRowId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
window.postMessage(WindowMessageBag("StockEntryChanged", stockRowId), Grocy.BaseUrl);
|
window.postMessage(WindowMessageBag("StockEntryChanged", stockRowId), Grocy.BaseUrl);
|
||||||
toastr.success(__t("Booking successfully undone"));
|
toastr.success(__t("Booking successfully undone"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).on("click", ".product-name-cell", function(e)
|
$(document).on("click", ".product-name-cell", function(e) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductCard.Refresh($(e.currentTarget).attr("data-product-id"));
|
Grocy.Components.ProductCard.Refresh($(e.currentTarget).attr("data-product-id"));
|
||||||
$("#productcard-modal").modal("show");
|
$("#productcard-modal").modal("show");
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,83 +1,118 @@
|
||||||
var stockJournalTable = $('#stock-journal-table').DataTable({
|
var stockJournalTable = $('#stock-journal-table').DataTable({
|
||||||
'order': [[3, 'desc']],
|
'order': [
|
||||||
'columnDefs': [
|
[3, 'desc']
|
||||||
{ 'orderable': false, 'targets': 0 },
|
],
|
||||||
{ 'searchable': false, "targets": 0 }
|
'columnDefs': [{
|
||||||
|
'orderable': false,
|
||||||
|
'targets': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'searchable': false,
|
||||||
|
"targets": 0
|
||||||
|
}
|
||||||
].concat($.fn.dataTable.defaults.columnDefs)
|
].concat($.fn.dataTable.defaults.columnDefs)
|
||||||
});
|
});
|
||||||
$('#stock-journal-table tbody').removeClass("d-none");
|
$('#stock-journal-table tbody').removeClass("d-none");
|
||||||
stockJournalTable.columns.adjust().draw();
|
stockJournalTable.columns.adjust().draw();
|
||||||
|
|
||||||
$("#product-filter").on("change", function()
|
$("#product-filter").select2({
|
||||||
{
|
ajax: {
|
||||||
var value = $(this).val();
|
delay: 150,
|
||||||
if (value === "all")
|
transport: function(params, success, failure) {
|
||||||
{
|
var results_per_page = 10;
|
||||||
RemoveUriParam("product");
|
var page = params.data.page || 1;
|
||||||
}
|
var term = params.data.term || "";
|
||||||
else
|
|
||||||
{
|
var query = [];
|
||||||
UpdateUriParam("product", value);
|
query.push('query%5B%5D=active%3D1');
|
||||||
|
query.push('limit=' + encodeURIComponent(results_per_page));
|
||||||
|
query.push('offset=' + encodeURIComponent((page - 1) * results_per_page));
|
||||||
|
query.push('order=name%3Acollate%20nocase');
|
||||||
|
if (term.length > 0) {
|
||||||
|
query.push('search=' + encodeURIComponent(term));
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.reload();
|
Grocy.Api.Get('objects/products' + (query.length > 0 ? '?' + query.join('&') : ''),
|
||||||
|
function(results, meta) {
|
||||||
|
success({
|
||||||
|
results: [{
|
||||||
|
id: 'all',
|
||||||
|
text: __t('All')
|
||||||
|
}].concat(results.map(function(result) {
|
||||||
|
return {
|
||||||
|
id: result.id,
|
||||||
|
text: result.name
|
||||||
|
};
|
||||||
|
})),
|
||||||
|
pagination: {
|
||||||
|
more: page * results_per_page < meta.recordsFiltered
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(xhr) {
|
||||||
|
failure();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#transaction-type-filter").on("change", function()
|
$("#product-filter").on("change", function() {
|
||||||
{
|
var value = $(this).val();
|
||||||
|
if (value === "all" && GetUriParam("product") !== undefined) {
|
||||||
|
RemoveUriParam("product");
|
||||||
|
window.location.reload();
|
||||||
|
} else if (GetUriParam("product") !== value) {
|
||||||
|
UpdateUriParam("product", value);
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#transaction-type-filter").on("change", function() {
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
var text = $("#transaction-type-filter option:selected").text();
|
var text = $("#transaction-type-filter option:selected").text();
|
||||||
if (value === "all")
|
if (value === "all") {
|
||||||
{
|
|
||||||
text = "";
|
text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
stockJournalTable.column(stockJournalTable.colReorder.transpose(4)).search(text).draw();
|
stockJournalTable.column(stockJournalTable.colReorder.transpose(4)).search(text).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#location-filter").on("change", function()
|
$("#location-filter").on("change", function() {
|
||||||
{
|
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
var text = $("#location-filter option:selected").text();
|
var text = $("#location-filter option:selected").text();
|
||||||
if (value === "all")
|
if (value === "all") {
|
||||||
{
|
|
||||||
text = "";
|
text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
stockJournalTable.column(stockJournalTable.colReorder.transpose(5)).search(text).draw();
|
stockJournalTable.column(stockJournalTable.colReorder.transpose(5)).search(text).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#user-filter").on("change", function()
|
$("#user-filter").on("change", function() {
|
||||||
{
|
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
var text = $("#user-filter option:selected").text();
|
var text = $("#user-filter option:selected").text();
|
||||||
if (value === "all")
|
if (value === "all") {
|
||||||
{
|
|
||||||
text = "";
|
text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
stockJournalTable.column(stockJournalTable.colReorder.transpose(6)).search(text).draw();
|
stockJournalTable.column(stockJournalTable.colReorder.transpose(6)).search(text).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#daterange-filter").on("change", function()
|
$("#daterange-filter").on("change", function() {
|
||||||
{
|
|
||||||
UpdateUriParam("months", $(this).val());
|
UpdateUriParam("months", $(this).val());
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#search").on("keyup", Delay(function()
|
$("#search").on("keyup", Delay(function() {
|
||||||
{
|
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
if (value === "all")
|
if (value === "all") {
|
||||||
{
|
|
||||||
value = "";
|
value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
stockJournalTable.search(value).draw();
|
stockJournalTable.search(value).draw();
|
||||||
}, 200));
|
}, 200));
|
||||||
|
|
||||||
$("#clear-filter-button").on("click", function()
|
$("#clear-filter-button").on("click", function() {
|
||||||
{
|
|
||||||
$("#search").val("");
|
$("#search").val("");
|
||||||
$("#transaction-type-filter").val("all");
|
$("#transaction-type-filter").val("all");
|
||||||
$("#location-filter").val("all");
|
$("#location-filter").val("all");
|
||||||
|
|
@ -90,40 +125,47 @@ $("#clear-filter-button").on("click", function()
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof GetUriParam("product") !== "undefined")
|
var prefillProductId = GetUriParam("product");
|
||||||
{
|
if (typeof prefillProductId !== "undefined") {
|
||||||
$("#product-filter").val(GetUriParam("product"));
|
if ($("#product-filter").find('option[value="' + prefillProductId + '"]').length) {
|
||||||
|
$("#product-filter").val(prefillProductId).trigger('change');
|
||||||
|
} else {
|
||||||
|
Grocy.Api.Get('objects/products/' + encodeURIComponent(prefillProductId),
|
||||||
|
function(result) {
|
||||||
|
var option = new Option(result.name, prefillProductId, true, true);
|
||||||
|
$("#product-filter").append(option).trigger('change');
|
||||||
|
},
|
||||||
|
function(xhr) {
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof GetUriParam("months") !== "undefined")
|
if (typeof GetUriParam("months") !== "undefined") {
|
||||||
{
|
|
||||||
$("#daterange-filter").val(GetUriParam("months"));
|
$("#daterange-filter").val(GetUriParam("months"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).on('click', '.undo-stock-booking-button', function(e)
|
$(document).on('click', '.undo-stock-booking-button', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var bookingId = $(e.currentTarget).attr('data-booking-id');
|
var bookingId = $(e.currentTarget).attr('data-booking-id');
|
||||||
var correlationId = $("#stock-booking-" + bookingId + "-row").attr("data-correlation-id");
|
var correlationId = $("#stock-booking-" + bookingId + "-row").attr("data-correlation-id");
|
||||||
|
|
||||||
var correspondingBookingsRoot = $("#stock-booking-" + bookingId + "-row");
|
var correspondingBookingsRoot = $("#stock-booking-" + bookingId + "-row");
|
||||||
if (!correlationId.isEmpty())
|
if (!correlationId.isEmpty()) {
|
||||||
{
|
|
||||||
correspondingBookingsRoot = $(".stock-booking-correlation-" + correlationId);
|
correspondingBookingsRoot = $(".stock-booking-correlation-" + correlationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
correspondingBookingsRoot.addClass("text-muted");
|
correspondingBookingsRoot.addClass("text-muted");
|
||||||
correspondingBookingsRoot.find("span.name-anchor").addClass("text-strike-through").after("<br>" + __t("Undone on") + " " + moment().format("YYYY-MM-DD HH:mm:ss") + " <time class='timeago timeago-contextual' datetime='" + moment().format("YYYY-MM-DD HH:mm:ss") + "'></time>");
|
correspondingBookingsRoot.find("span.name-anchor").addClass("text-strike-through").after("<br>" + __t("Undone on") + " " + moment().format("YYYY-MM-DD HH:mm:ss") + " <time class='timeago timeago-contextual' datetime='" + moment().format("YYYY-MM-DD HH:mm:ss") + "'></time>");
|
||||||
correspondingBookingsRoot.find(".undo-stock-booking-button").addClass("disabled");
|
correspondingBookingsRoot.find(".undo-stock-booking-button").addClass("disabled");
|
||||||
RefreshContextualTimeago("#stock-booking-" + bookingId + "-row");
|
RefreshContextualTimeago("#stock-booking-" + bookingId + "-row");
|
||||||
toastr.success(__t("Booking successfully undone"));
|
toastr.success(__t("Booking successfully undone"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
toastr.error(__t(JSON.parse(xhr.response).error_message));
|
toastr.error(__t(JSON.parse(xhr.response).error_message));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,64 +1,102 @@
|
||||||
var journalSummaryTable = $('#stock-journal-summary-table').DataTable({
|
var journalSummaryTable = $('#stock-journal-summary-table').DataTable({
|
||||||
'order': [[1, 'asc']],
|
'order': [
|
||||||
'columnDefs': [
|
[1, 'asc']
|
||||||
{ 'orderable': false, 'targets': 0 },
|
],
|
||||||
{ 'searchable': false, "targets": 0 }
|
'columnDefs': [{
|
||||||
|
'orderable': false,
|
||||||
|
'targets': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'searchable': false,
|
||||||
|
"targets": 0
|
||||||
|
}
|
||||||
].concat($.fn.dataTable.defaults.columnDefs)
|
].concat($.fn.dataTable.defaults.columnDefs)
|
||||||
});
|
});
|
||||||
$('#stock-journal-summary-table tbody').removeClass("d-none");
|
$('#stock-journal-summary-table tbody').removeClass("d-none");
|
||||||
journalSummaryTable.columns.adjust().draw();
|
journalSummaryTable.columns.adjust().draw();
|
||||||
|
|
||||||
$("#product-filter").on("change", function()
|
$("#product-filter").select2({
|
||||||
{
|
ajax: {
|
||||||
var value = $(this).val();
|
delay: 150,
|
||||||
var text = $("#product-filter option:selected").text();
|
transport: function(params, success, failure) {
|
||||||
if (value === "all")
|
var results_per_page = 10;
|
||||||
{
|
var page = params.data.page || 1;
|
||||||
journalSummaryTable.column(journalSummaryTable.colReorder.transpose(1)).search("").draw();
|
var term = params.data.term || "";
|
||||||
|
|
||||||
|
var query = [];
|
||||||
|
query.push('query%5B%5D=active%3D1');
|
||||||
|
query.push('limit=' + encodeURIComponent(results_per_page));
|
||||||
|
query.push('offset=' + encodeURIComponent((page - 1) * results_per_page));
|
||||||
|
query.push('order=name%3Acollate%20nocase');
|
||||||
|
if (term.length > 0) {
|
||||||
|
query.push('search=' + encodeURIComponent(term));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
Grocy.Api.Get('objects/products' + (query.length > 0 ? '?' + query.join('&') : ''),
|
||||||
|
function(results, meta) {
|
||||||
|
success({
|
||||||
|
results: [{
|
||||||
|
id: 'all',
|
||||||
|
text: __t('All')
|
||||||
|
}].concat(results.map(function(result) {
|
||||||
|
return {
|
||||||
|
id: result.id,
|
||||||
|
text: result.name
|
||||||
|
};
|
||||||
|
})),
|
||||||
|
pagination: {
|
||||||
|
more: page * results_per_page < meta.recordsFiltered
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(xhr) {
|
||||||
|
failure();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#product-filter").on("change", function() {
|
||||||
|
var value = $(this).val();
|
||||||
|
var text = $("#product-filter option:selected").text().trim();
|
||||||
|
if (value === "all") {
|
||||||
|
journalSummaryTable.column(journalSummaryTable.colReorder.transpose(1)).search("").draw();
|
||||||
|
} else {
|
||||||
journalSummaryTable.column(journalSummaryTable.colReorder.transpose(1)).search("^" + text + "$", true, false).draw();
|
journalSummaryTable.column(journalSummaryTable.colReorder.transpose(1)).search("^" + text + "$", true, false).draw();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#transaction-type-filter").on("change", function()
|
$("#transaction-type-filter").on("change", function() {
|
||||||
{
|
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
var text = $("#transaction-type-filter option:selected").text();
|
var text = $("#transaction-type-filter option:selected").text();
|
||||||
if (value === "all")
|
if (value === "all") {
|
||||||
{
|
|
||||||
text = "";
|
text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
journalSummaryTable.column(journalSummaryTable.colReorder.transpose(2)).search(text).draw();
|
journalSummaryTable.column(journalSummaryTable.colReorder.transpose(2)).search(text).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#user-filter").on("change", function()
|
$("#user-filter").on("change", function() {
|
||||||
{
|
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
var text = $("#user-filter option:selected").text();
|
var text = $("#user-filter option:selected").text();
|
||||||
if (value === "all")
|
if (value === "all") {
|
||||||
{
|
|
||||||
text = "";
|
text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
journalSummaryTable.column(journalSummaryTable.colReorder.transpose(3)).search(text).draw();
|
journalSummaryTable.column(journalSummaryTable.colReorder.transpose(3)).search(text).draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#search").on("keyup", Delay(function()
|
$("#search").on("keyup", Delay(function() {
|
||||||
{
|
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
if (value === "all")
|
if (value === "all") {
|
||||||
{
|
|
||||||
value = "";
|
value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
journalSummaryTable.search(value).draw();
|
journalSummaryTable.search(value).draw();
|
||||||
}, 200));
|
}, 200));
|
||||||
|
|
||||||
$("#clear-filter-button").on("click", function()
|
$("#clear-filter-button").on("click", function() {
|
||||||
{
|
|
||||||
$("#search").val("");
|
$("#search").val("");
|
||||||
$("#transaction-type-filter").val("all");
|
$("#transaction-type-filter").val("all");
|
||||||
$("#location-filter").val("all");
|
$("#location-filter").val("all");
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
$('#save-transfer-button').on('click', function(e)
|
$('#save-transfer-button').on('click', function(e) {
|
||||||
{
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if ($(".combobox-menu-visible").length)
|
if ($(".combobox-menu-visible").length) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,60 +15,48 @@
|
||||||
jsonData.location_id_to = $("#location_id_to").val();
|
jsonData.location_id_to = $("#location_id_to").val();
|
||||||
jsonData.location_id_from = $("#location_id_from").val();
|
jsonData.location_id_from = $("#location_id_from").val();
|
||||||
|
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked")) {
|
||||||
{
|
|
||||||
jsonData.stock_entry_id = jsonForm.specific_stock_entry;
|
jsonData.stock_entry_id = jsonForm.specific_stock_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bookingResponse = null;
|
var bookingResponse = null;
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
Grocy.Api.Get('stock/products/' + jsonForm.product_id,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
Grocy.Api.Post(apiUrl, jsonData,
|
Grocy.Api.Post(apiUrl, jsonData,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
bookingResponse = result;
|
bookingResponse = result;
|
||||||
|
|
||||||
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct")
|
if (GetUriParam("flow") === "InplaceAddBarcodeToExistingProduct") {
|
||||||
{
|
|
||||||
var jsonDataBarcode = {};
|
var jsonDataBarcode = {};
|
||||||
jsonDataBarcode.barcode = GetUriParam("barcode");
|
jsonDataBarcode.barcode = GetUriParam("barcode");
|
||||||
jsonDataBarcode.product_id = jsonForm.product_id;
|
jsonDataBarcode.product_id = jsonForm.product_id;
|
||||||
|
|
||||||
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
Grocy.Api.Post('objects/product_barcodes', jsonDataBarcode,
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
$("#flow-info-InplaceAddBarcodeToExistingProduct").addClass("d-none");
|
||||||
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
$('#barcode-lookup-disabled-hint').addClass('d-none');
|
||||||
$('#barcode-lookup-hint').removeClass('d-none');
|
$('#barcode-lookup-hint').removeClass('d-none');
|
||||||
window.history.replaceState({}, document.title, U("/transfer"));
|
window.history.replaceState({}, document.title, U("/transfer"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
||||||
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
var successMessage = __t('Transfered %1$s of %2$s from %3$s to %4$s', Math.abs(jsonForm.amount - parseFloat(productDetails.product.tare_weight)) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name, $('option:selected', "#location_id_from").text(), $('option:selected', "#location_id_to").text()) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
var successMessage = __t('Transfered %1$s of %2$s from %3$s to %4$s', Math.abs(jsonForm.amount - parseFloat(productDetails.product.tare_weight)) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name, $('option:selected', "#location_id_from").text(), $('option:selected', "#location_id_to").text()) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
var successMessage = __t('Transfered %1$s of %2$s from %3$s to %4$s', Math.abs(jsonForm.amount) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name, $('option:selected', "#location_id_from").text(), $('option:selected', "#location_id_to").text()) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
var successMessage = __t('Transfered %1$s of %2$s from %3$s to %4$s', Math.abs(jsonForm.amount) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name, $('option:selected', "#location_id_from").text(), $('option:selected', "#location_id_to").text()) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ProductChanged", jsonForm.product_id), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", successMessage), Grocy.BaseUrl);
|
||||||
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
||||||
toastr.success(successMessage);
|
toastr.success(successMessage);
|
||||||
Grocy.Components.ProductPicker.FinishFlow();
|
Grocy.Components.ProductPicker.FinishFlow();
|
||||||
|
|
@ -79,8 +65,7 @@
|
||||||
{
|
{
|
||||||
toastr.info('<span>' + __t("Frozen") + "</span> <i class='fas fa-snowflake'></i>");
|
toastr.info('<span>' + __t("Frozen") + "</span> <i class='fas fa-snowflake'></i>");
|
||||||
|
|
||||||
if (BoolVal(productDetails.product.should_not_be_frozen))
|
if (BoolVal(productDetails.product.should_not_be_frozen)) {
|
||||||
{
|
|
||||||
toastr.warning(__t("This product shouldn't be frozen"));
|
toastr.warning(__t("This product shouldn't be frozen"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -92,8 +77,7 @@
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
$("#specific_stock_entry").attr("disabled", "");
|
$("#specific_stock_entry").attr("disabled", "");
|
||||||
$("#specific_stock_entry").removeAttr("required");
|
$("#specific_stock_entry").removeAttr("required");
|
||||||
if ($("#use_specific_stock_entry").is(":checked"))
|
if ($("#use_specific_stock_entry").is(":checked")) {
|
||||||
{
|
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,67 +92,56 @@
|
||||||
Grocy.Components.ProductPicker.Clear();
|
Grocy.Components.ProductPicker.Clear();
|
||||||
$("#location_id_to").val("");
|
$("#location_id_to").val("");
|
||||||
$("#location_id_from").val("");
|
$("#location_id_from").val("");
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
Grocy.Components.ProductCard.Refresh(jsonForm.product_id);
|
||||||
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
Grocy.FrontendHelpers.EndUiBusy("transfer-form");
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
Grocy.Components.ProductPicker.OnChange(function(e) {
|
||||||
{
|
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
if ($("#use_specific_stock_entry").is(":checked") && GetUriParam("stockId") == null)
|
if ($("#use_specific_stock_entry").is(":checked") && GetUriParam("stockId") == null) {
|
||||||
{
|
$("#use_specific_stock_entry").trigger('click');
|
||||||
$("#use_specific_stock_entry").click();
|
|
||||||
}
|
}
|
||||||
$("#location_id_to").val("");
|
$("#location_id_to").val("");
|
||||||
if (GetUriParam("stockId") == null)
|
if (GetUriParam("stockId") == null) {
|
||||||
{
|
|
||||||
$("#location_id_from").val("");
|
$("#location_id_from").val("");
|
||||||
}
|
}
|
||||||
|
|
||||||
var productId = $(e.target).val();
|
var productId = $(e.target).val();
|
||||||
|
|
||||||
if (productId)
|
if (productId) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductCard.Refresh(productId);
|
Grocy.Components.ProductCard.Refresh(productId);
|
||||||
|
|
||||||
Grocy.Api.Get('stock/products/' + productId,
|
Grocy.Api.Get('stock/products/' + productId,
|
||||||
function(productDetails)
|
function(productDetails) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.Reload(productDetails.product.id, productDetails.quantity_unit_stock.id);
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(productDetails.quantity_unit_stock.id);
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
Grocy.Components.ProductPicker.ShowCustomError(__t('Products with tare weight enabled are currently not supported for transfer'));
|
||||||
Grocy.Components.ProductPicker.GetPicker().parent().find(".invalid-feedback").text(__t('Products with tare weight enabled are currently not supported for transfer'));
|
|
||||||
Grocy.Components.ProductPicker.Clear();
|
Grocy.Components.ProductPicker.Clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#location_id_from").find("option").remove().end().append("<option></option>");
|
$("#location_id_from").find("option").remove().end().append("<option></option>");
|
||||||
Grocy.Api.Get("stock/products/" + productId + '/locations',
|
Grocy.Api.Get("stock/products/" + productId + '/locations',
|
||||||
function(stockLocations)
|
function(stockLocations) {
|
||||||
{
|
|
||||||
var setDefault = 0;
|
var setDefault = 0;
|
||||||
stockLocations.forEach(stockLocation =>
|
stockLocations.forEach(stockLocation => {
|
||||||
{
|
if (productDetails.location.id == stockLocation.location_id) {
|
||||||
if (productDetails.location.id == stockLocation.location_id)
|
|
||||||
{
|
|
||||||
$("#location_id_from").append($("<option>", {
|
$("#location_id_from").append($("<option>", {
|
||||||
value: stockLocation.location_id,
|
value: stockLocation.location_id,
|
||||||
text: stockLocation.location_name + " (" + __t("Default location") + ")",
|
text: stockLocation.location_name + " (" + __t("Default location") + ")",
|
||||||
|
|
@ -177,9 +150,7 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
$("#location_id_from").val(productDetails.location.id);
|
$("#location_id_from").val(productDetails.location.id);
|
||||||
$("#location_id_from").trigger('change');
|
$("#location_id_from").trigger('change');
|
||||||
setDefault = 1;
|
setDefault = 1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#location_id_from").append($("<option>", {
|
$("#location_id_from").append($("<option>", {
|
||||||
value: stockLocation.location_id,
|
value: stockLocation.location_id,
|
||||||
text: stockLocation.location_name,
|
text: stockLocation.location_name,
|
||||||
|
|
@ -187,44 +158,35 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setDefault == 0)
|
if (setDefault == 0) {
|
||||||
{
|
|
||||||
$("#location_id_from").val(stockLocation.location_id);
|
$("#location_id_from").val(stockLocation.location_id);
|
||||||
$("#location_id_from").trigger('change');
|
$("#location_id_from").trigger('change');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (GetUriParam("locationId") != null)
|
if (GetUriParam("locationId") != null) {
|
||||||
{
|
|
||||||
$("#location_id_from").val(GetUriParam("locationId"));
|
$("#location_id_from").val(GetUriParam("locationId"));
|
||||||
$("#location_id_from").trigger("change");
|
$("#location_id_from").trigger("change");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (document.getElementById("product_id").getAttribute("barcode") != "null")
|
if (document.getElementById("product_id").getAttribute("barcode") != "null") {
|
||||||
{
|
|
||||||
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + document.getElementById("product_id").getAttribute("barcode"),
|
||||||
function(barcodeResult)
|
function(barcodeResult) {
|
||||||
{
|
if (barcodeResult != null) {
|
||||||
if (barcodeResult != null)
|
|
||||||
{
|
|
||||||
var barcode = barcodeResult[0];
|
var barcode = barcodeResult[0];
|
||||||
|
|
||||||
if (barcode != null)
|
if (barcode != null) {
|
||||||
{
|
if (barcode.amount != null && !barcode.amount.isEmpty()) {
|
||||||
if (barcode.amount != null && !barcode.amount.isEmpty())
|
|
||||||
{
|
|
||||||
$("#display_amount").val(barcode.amount);
|
$("#display_amount").val(barcode.amount);
|
||||||
$("#display_amount").select();
|
$("#display_amount").trigger('select');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (barcode.qu_id != null && !barcode.qu_id.isEmpty())
|
if (barcode.qu_id != null && !barcode.qu_id.isEmpty()) {
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.SetQuantityUnit(barcode.qu_id);
|
Grocy.Components.ProductAmountPicker.SetQuantityUnit(barcode.qu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,20 +196,16 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productDetails.product.enable_tare_weight_handling == 1)
|
if (productDetails.product.enable_tare_weight_handling == 1) {
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", productDetails.product.tare_weight);
|
$("#display_amount").attr("min", productDetails.product.tare_weight);
|
||||||
$("#tare-weight-handling-info").removeClass("d-none");
|
$("#tare-weight-handling-info").removeClass("d-none");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
$("#display_amount").attr("min", Grocy.DefaultMinAmount);
|
||||||
$("#tare-weight-handling-info").addClass("d-none");
|
$("#tare-weight-handling-info").addClass("d-none");
|
||||||
}
|
}
|
||||||
|
|
@ -256,11 +214,11 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.HideCustomError();
|
Grocy.Components.ProductPicker.HideCustomError();
|
||||||
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
||||||
$('#display_amount').focus();
|
$('#display_amount').trigger('focus');
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
|
Grocy.Components.ProductPicker.HideCustomError();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -271,45 +229,35 @@ $(".input-group-productamountpicker").trigger("change");
|
||||||
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
||||||
RefreshLocaleNumberInput();
|
RefreshLocaleNumberInput();
|
||||||
|
|
||||||
$("#location_id_from").on('change', function(e)
|
$("#location_id_from").on('change', function(e) {
|
||||||
{
|
|
||||||
var locationId = $(e.target).val();
|
var locationId = $(e.target).val();
|
||||||
var sumValue = 0;
|
var sumValue = 0;
|
||||||
var stockId = null;
|
var stockId = null;
|
||||||
|
|
||||||
if (locationId == $("#location_id_to").val())
|
if (locationId == $("#location_id_to").val()) {
|
||||||
{
|
|
||||||
$("#location_id_to").val("");
|
$("#location_id_to").val("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
stockId = GetUriParam('stockId');
|
stockId = GetUriParam('stockId');
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
$("#specific_stock_entry").find("option").remove().end().append("<option></option>");
|
||||||
if ($("#use_specific_stock_entry").is(":checked") && GetUriParam("stockId") == null)
|
if ($("#use_specific_stock_entry").is(":checked") && GetUriParam("stockId") == null) {
|
||||||
{
|
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").click();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locationId)
|
if (locationId) {
|
||||||
{
|
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries',
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries',
|
||||||
function(stockEntries)
|
function(stockEntries) {
|
||||||
{
|
stockEntries.forEach(stockEntry => {
|
||||||
stockEntries.forEach(stockEntry =>
|
|
||||||
{
|
|
||||||
var openTxt = __t("Not opened");
|
var openTxt = __t("Not opened");
|
||||||
if (stockEntry.open == 1)
|
if (stockEntry.open == 1) {
|
||||||
{
|
|
||||||
openTxt = __t("Opened");
|
openTxt = __t("Opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stockEntry.location_id == locationId)
|
if (stockEntry.location_id == locationId) {
|
||||||
{
|
if ($("#specific_stock_entry option[value='" + stockEntry.stock_id + "']").length == 0) {
|
||||||
if ($("#specific_stock_entry option[value='" + stockEntry.stock_id + "']").length == 0)
|
|
||||||
{
|
|
||||||
$("#specific_stock_entry").append($("<option>", {
|
$("#specific_stock_entry").append($("<option>", {
|
||||||
value: stockEntry.stock_id,
|
value: stockEntry.stock_id,
|
||||||
amount: stockEntry.amount,
|
amount: stockEntry.amount,
|
||||||
|
|
@ -317,8 +265,7 @@ $("#location_id_from").on('change', function(e)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stockEntry.stock_id == stockId)
|
if (stockEntry.stock_id == stockId) {
|
||||||
{
|
|
||||||
$("#specific_stock_entry").val(stockId);
|
$("#specific_stock_entry").val(stockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,52 +273,43 @@ $("#location_id_from").on('change', function(e)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("#display_amount").attr("max", sumValue * $("#qu_id option:selected").attr("data-qu-factor"));
|
$("#display_amount").attr("max", sumValue * $("#qu_id option:selected").attr("data-qu-factor"));
|
||||||
if (sumValue == 0)
|
if (sumValue == 0) {
|
||||||
{
|
|
||||||
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#location_id_to").on('change', function(e)
|
$("#location_id_to").on('change', function(e) {
|
||||||
{
|
|
||||||
var locationId = $(e.target).val();
|
var locationId = $(e.target).val();
|
||||||
|
|
||||||
if (locationId == $("#location_id_from").val())
|
if (locationId == $("#location_id_from").val()) {
|
||||||
{
|
|
||||||
$("#location_id_to").parent().find(".invalid-feedback").text(__t('This cannot be the same as the "From" location'));
|
$("#location_id_to").parent().find(".invalid-feedback").text(__t('This cannot be the same as the "From" location'));
|
||||||
$("#location_id_to").val("");
|
$("#location_id_to").val("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#qu_id").on('change', function(e)
|
$("#qu_id").on('change', function(e) {
|
||||||
{
|
|
||||||
$("#display_amount").attr("max", parseFloat($('#display_amount').attr("data-stock-amount")) * $("#qu_id option:selected").attr("data-qu-factor"));
|
$("#display_amount").attr("max", parseFloat($('#display_amount').attr("data-stock-amount")) * $("#qu_id option:selected").attr("data-qu-factor"));
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#display_amount').on('focus', function(e)
|
$('#display_amount').on('focus', function(e) {
|
||||||
{
|
|
||||||
$(this).select();
|
$(this).select();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#transfer-form input').keyup(function(event)
|
$('#transfer-form input').keyup(function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#transfer-form select').change(function(event)
|
$('#transfer-form select').change(function(event) {
|
||||||
{
|
|
||||||
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
Grocy.FrontendHelpers.ValidateForm('transfer-form');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#transfer-form input').keydown(function(event)
|
$('#transfer-form input').keydown(function(event) {
|
||||||
{
|
|
||||||
if (event.keyCode === 13) //Enter
|
if (event.keyCode === 13) //Enter
|
||||||
{
|
{
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -379,58 +317,43 @@ $('#transfer-form input').keydown(function(event)
|
||||||
if (document.getElementById('transfer-form').checkValidity() === false) //There is at least one validation error
|
if (document.getElementById('transfer-form').checkValidity() === false) //There is at least one validation error
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#save-transfer-button').click();
|
$('#save-transfer-button').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#specific_stock_entry").on("change", function(e)
|
$("#specific_stock_entry").on("change", function(e) {
|
||||||
{
|
if ($(e.target).val() == "") {
|
||||||
if ($(e.target).val() == "")
|
|
||||||
{
|
|
||||||
var sumValue = 0;
|
var sumValue = 0;
|
||||||
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries',
|
Grocy.Api.Get("stock/products/" + Grocy.Components.ProductPicker.GetValue() + '/entries',
|
||||||
function(stockEntries)
|
function(stockEntries) {
|
||||||
{
|
stockEntries.forEach(stockEntry => {
|
||||||
stockEntries.forEach(stockEntry =>
|
if (stockEntry.location_id == $("#location_id_from").val() || stockEntry.location_id == "") {
|
||||||
{
|
|
||||||
if (stockEntry.location_id == $("#location_id_from").val() || stockEntry.location_id == "")
|
|
||||||
{
|
|
||||||
sumValue = sumValue + parseFloat(stockEntry.amount);
|
sumValue = sumValue + parseFloat(stockEntry.amount);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("#display_amount").attr("max", sumValue * $("#qu_id option:selected").attr("data-qu-factor"));
|
$("#display_amount").attr("max", sumValue * $("#qu_id option:selected").attr("data-qu-factor"));
|
||||||
if (sumValue == 0)
|
if (sumValue == 0) {
|
||||||
{
|
|
||||||
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
$("#display_amount").parent().find(".invalid-feedback").text(__t('There are no units available at this location'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#display_amount").attr("max", $('option:selected', this).attr('amount'));
|
$("#display_amount").attr("max", $('option:selected', this).attr('amount'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#use_specific_stock_entry").on("change", function()
|
$("#use_specific_stock_entry").on("change", function() {
|
||||||
{
|
|
||||||
var value = $(this).is(":checked");
|
var value = $(this).is(":checked");
|
||||||
|
|
||||||
if (value)
|
if (value) {
|
||||||
{
|
|
||||||
$("#specific_stock_entry").removeAttr("disabled");
|
$("#specific_stock_entry").removeAttr("disabled");
|
||||||
$("#specific_stock_entry").attr("required", "");
|
$("#specific_stock_entry").attr("required", "");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
$("#specific_stock_entry").attr("disabled", "");
|
$("#specific_stock_entry").attr("disabled", "");
|
||||||
$("#specific_stock_entry").removeAttr("required");
|
$("#specific_stock_entry").removeAttr("required");
|
||||||
$("#specific_stock_entry").val("");
|
$("#specific_stock_entry").val("");
|
||||||
|
|
@ -440,53 +363,43 @@ $("#use_specific_stock_entry").on("change", function()
|
||||||
Grocy.FrontendHelpers.ValidateForm("transfer-form");
|
Grocy.FrontendHelpers.ValidateForm("transfer-form");
|
||||||
});
|
});
|
||||||
|
|
||||||
function UndoStockBooking(bookingId)
|
function UndoStockBooking(bookingId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/bookings/' + bookingId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
toastr.success(__t("Booking successfully undone"));
|
toastr.success(__t("Booking successfully undone"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function UndoStockTransaction(transactionId)
|
function UndoStockTransaction(transactionId) {
|
||||||
{
|
|
||||||
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
Grocy.Api.Post('stock/transactions/' + transactionId.toString() + '/undo', {},
|
||||||
function(result)
|
function(result) {
|
||||||
{
|
|
||||||
toastr.success(__t("Transaction successfully undone"));
|
toastr.success(__t("Transaction successfully undone"));
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (GetUriParam("embedded") !== undefined)
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
{
|
|
||||||
var locationId = GetUriParam('locationId');
|
var locationId = GetUriParam('locationId');
|
||||||
|
|
||||||
if (typeof locationId === 'undefined')
|
if (typeof locationId === 'undefined') {
|
||||||
{
|
Grocy.Components.ProductPicker.Validate();
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
Grocy.Components.ProductPicker.Focus();
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
} else {
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
$("#location_id_from").val(locationId);
|
$("#location_id_from").val(locationId);
|
||||||
$("#location_id_from").trigger('change');
|
$("#location_id_from").trigger('change');
|
||||||
$("#use_specific_stock_entry").click();
|
$("#use_specific_stock_entry").trigger('click');
|
||||||
$("#use_specific_stock_entry").trigger('change');
|
$("#use_specific_stock_entry").trigger('change');
|
||||||
Grocy.Components.ProductPicker.GetPicker().trigger('change');
|
Grocy.Components.ProductPicker.Validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default input field
|
// Default input field
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
Grocy.Components.ProductPicker.Focus();
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'batteries')
|
@section('viewJsName', 'batteries')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button permission-MASTER_DATA_EDIT m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
<a class="btn btn-primary responsive-button permission-MASTER_DATA_EDIT m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
href="{{ $U('/battery/new?embedded') }}">
|
href="{{ $U('/battery/new?embedded') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -36,84 +31,69 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="form-check custom-control custom-checkbox">
|
<div class="form-check custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-disabled">
|
||||||
type="checkbox"
|
<label class="form-check-label custom-control-label" for="show-disabled">
|
||||||
id="show-disabled">
|
|
||||||
<label class="form-check-label custom-control-label"
|
|
||||||
for="show-disabled">
|
|
||||||
{{ $__t('Show disabled') }}
|
{{ $__t('Show disabled') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="batteries-table"
|
{{-- TODO: DataTables: dynamic data: batteries --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="batteries-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
title="{{ $__t('Table options') }}"
|
data-table-selector="#batteries-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
data-table-selector="#batteries-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Description') }}</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Used in') }}</th>
|
<th class="allow-grouping">{{ $__t('Used in') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Charge cycle interval (days)') }}</th>
|
<th class="allow-grouping">{{ $__t('Charge cycle interval (days)') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($batteries as $battery)
|
@foreach ($batteries as $battery)
|
||||||
<tr class="@if($battery->active == 0) text-muted @endif">
|
<tr class="@if ($battery->active == 0) text-muted @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm permission-MASTER_DATA_EDIT show-as-dialog-link"
|
<a class="btn btn-info btn-sm permission-MASTER_DATA_EDIT show-as-dialog-link"
|
||||||
href="{{ $U('/battery/') }}{{ $battery->id }}?embedded"
|
href="{{ $U('/battery/') }}{{ $battery->id }}?embedded" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm battery-delete-button permission-MASTER_DATA_EDIT"
|
<a class="btn btn-danger btn-sm battery-delete-button permission-MASTER_DATA_EDIT" href="#"
|
||||||
href="#"
|
data-battery-id="{{ $battery->id }}" data-battery-name="{{ $battery->name }}"
|
||||||
data-battery-id="{{ $battery->id }}"
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
data-battery-name="{{ $battery->name }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -130,15 +110,19 @@
|
||||||
{{ $battery->charge_interval_days }}
|
{{ $battery->charge_interval_days }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $battery->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$battery->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,33 +5,27 @@
|
||||||
@section('viewJsName', 'batteriesjournal')
|
@section('viewJsName', 'batteriesjournal')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button" data-toggle="collapse"
|
||||||
type="button"
|
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
data-target="#table-filter-row">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -39,10 +33,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Battery') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Battery') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: batteries --}}
|
||||||
id="battery-filter">
|
<select class="custom-control custom-select" id="battery-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($batteries as $battery)
|
@foreach ($batteries as $battery)
|
||||||
<option value="{{ $battery->id }}">{{ $battery->name }}</option>
|
<option value="{{ $battery->id }}">{{ $battery->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -53,62 +47,53 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="daterange-filter">
|
||||||
id="daterange-filter">
|
|
||||||
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
||||||
<option value="6">{{ $__n(6, '%s month', '%s months') }}</option>
|
<option value="6">{{ $__n(6, '%s month', '%s months') }}</option>
|
||||||
<option value="12">{{ $__n(1, '%s year', '%s years') }}</option>
|
<option value="12">{{ $__n(1, '%s year', '%s years') }}</option>
|
||||||
<option value="24"
|
<option value="24" selected>{{ $__n(2, '%s month', '%s years') }}</option>
|
||||||
selected>{{ $__n(2, '%s month', '%s years') }}</option>
|
|
||||||
<option value="9999">{{ $__t('All') }}</option>
|
<option value="9999">{{ $__t('All') }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="batteries-journal-table"
|
{{-- TODO: DataTables: dynamic data: battery_charge_cycles --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="batteries-journal-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#batteries-journal-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#batteries-journal-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Battery') }}</th>
|
<th class="allow-grouping">{{ $__t('Battery') }}</th>
|
||||||
<th>{{ $__t('Tracked time') }}</th>
|
<th>{{ $__t('Tracked time') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($chargeCycles as $chargeCycleEntry)
|
@foreach ($chargeCycles as $chargeCycleEntry)
|
||||||
<tr id="charge-cycle-{{ $chargeCycleEntry->id }}-row"
|
<tr id="charge-cycle-{{ $chargeCycleEntry->id }}-row"
|
||||||
class="@if($chargeCycleEntry->undone == 1) text-muted @endif">
|
class="@if ($chargeCycleEntry->undone == 1) text-muted @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-secondary btn-xs undo-battery-execution-button @if($chargeCycleEntry->undone == 1) disabled @endif permission-BATTERIES_UNDO_CHARGE_CYCLE"
|
<a class="btn btn-secondary btn-xs undo-battery-execution-button @if ($chargeCycleEntry->undone == 1) disabled @endif permission-BATTERIES_UNDO_CHARGE_CYCLE"
|
||||||
href="#"
|
href="#" data-charge-cycle-id="{{ $chargeCycleEntry->id }}" data-toggle="tooltip"
|
||||||
data-charge-cycle-id="{{ $chargeCycleEntry->id }}"
|
data-placement="left" title="{{ $__t('Undo charge cycle') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Undo charge cycle') }}">
|
|
||||||
<i class="fas fa-undo"></i>
|
<i class="fas fa-undo"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="name-anchor @if($chargeCycleEntry->undone == 1) text-strike-through @endif">{{ FindObjectInArrayByPropertyValue($batteries, 'id', $chargeCycleEntry->battery_id)->name }}</span>
|
<span
|
||||||
@if($chargeCycleEntry->undone == 1)
|
class="name-anchor @if ($chargeCycleEntry->undone == 1) text-strike-through @endif">{{ FindObjectInArrayByPropertyValue($batteries, 'id', $chargeCycleEntry->battery_id)->name }}</span>
|
||||||
|
@if ($chargeCycleEntry->undone == 1)
|
||||||
<br>
|
<br>
|
||||||
{{ $__t('Undone on') . ' ' . $chargeCycleEntry->undone_timestamp }}
|
{{ $__t('Undone on') . ' ' . $chargeCycleEntry->undone_timestamp }}
|
||||||
<time class="timeago timeago-contextual"
|
<time class="timeago timeago-contextual"
|
||||||
|
|
@ -125,5 +110,5 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,19 @@
|
||||||
@section('viewJsName', 'batteriesoverview')
|
@section('viewJsName', 'batteriesoverview')
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}" rel="stylesheet">
|
||||||
rel="stylesheet">
|
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/batteriesjournal') }}">
|
href="{{ $U('/batteriesjournal') }}">
|
||||||
{{ $__t('Journal') }}
|
{{ $__t('Journal') }}
|
||||||
|
|
@ -29,44 +25,33 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-top border-bottom my-2 py-1">
|
<div class="border-top border-bottom my-2 py-1">
|
||||||
<div id="info-overdue-batteries"
|
<div id="info-overdue-batteries" data-status-filter="overdue"
|
||||||
data-status-filter="overdue"
|
|
||||||
class="error-message status-filter-message responsive-button mr-2"></div>
|
class="error-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-due-today-batteries"
|
<div id="info-due-today-batteries" data-status-filter="duetoday"
|
||||||
data-status-filter="duetoday"
|
|
||||||
class="normal-message status-filter-message responsive-button mr-2"></div>
|
class="normal-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-due-soon-batteries"
|
<div id="info-due-soon-batteries" data-status-filter="duesoon" data-next-x-days="{{ $nextXDays }}"
|
||||||
data-status-filter="duesoon"
|
class="warning-message status-filter-message responsive-button @if ($nextXDays == 0) d-none @endif">
|
||||||
data-next-x-days="{{ $nextXDays }}"
|
</div>
|
||||||
class="warning-message status-filter-message responsive-button @if($nextXDays == 0) d-none @endif"></div>
|
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a class="btn btn-sm btn-outline-info d-md-none mt-1"
|
<a class="btn btn-sm btn-outline-info d-md-none mt-1" data-toggle="collapse" href="#table-filter-row"
|
||||||
data-toggle="collapse"
|
|
||||||
href="#table-filter-row"
|
|
||||||
role="button">
|
role="button">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info mt-1" href="#">
|
||||||
class="btn btn-sm btn-outline-info mt-1"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -74,31 +59,27 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
id="status-filter">
|
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<option value="overdue">{{ $__t('Overdue') }}</option>
|
<option value="overdue">{{ $__t('Overdue') }}</option>
|
||||||
<option value="duetoday">{{ $__t('Due today') }}</option>
|
<option value="duetoday">{{ $__t('Due today') }}</option>
|
||||||
@if($nextXDays > 0)
|
@if ($nextXDays > 0)
|
||||||
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
||||||
@endif
|
@endif
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="batteries-overview-table"
|
{{-- TODO: DataTables: dynamic data: batteries --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="batteries-overview-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#batteries-overview-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#batteries-overview-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Battery') }}</th>
|
<th>{{ $__t('Battery') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Used in') }}</th>
|
<th class="allow-grouping">{{ $__t('Used in') }}</th>
|
||||||
|
|
@ -106,41 +87,36 @@
|
||||||
<th>{{ $__t('Next planned charge cycle') }}</th>
|
<th>{{ $__t('Next planned charge cycle') }}</th>
|
||||||
<th class="d-none">Hidden status</th>
|
<th class="d-none">Hidden status</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($current as $currentBatteryEntry)
|
@foreach ($current as $currentBatteryEntry)
|
||||||
<tr id="battery-{{ $currentBatteryEntry->battery_id }}-row"
|
<tr id="battery-{{ $currentBatteryEntry->battery_id }}-row"
|
||||||
class="@if($currentBatteryEntry->due_type == 'overdue') table-danger @elseif($currentBatteryEntry->due_type == 'duetoday') table-info @elseif($currentBatteryEntry->due_type == 'duesoon') table-warning @endif">
|
class="@if ($currentBatteryEntry->due_type == 'overdue') table-danger @elseif($currentBatteryEntry->due_type == 'duetoday') table-info @elseif($currentBatteryEntry->due_type == 'duesoon') table-warning @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-success btn-sm track-charge-cycle-button permission-BATTERIES_TRACK_CHARGE_CYCLE"
|
<a class="btn btn-success btn-sm track-charge-cycle-button permission-BATTERIES_TRACK_CHARGE_CYCLE"
|
||||||
href="#"
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Track charge cycle') }}"
|
title="{{ $__t('Track charge cycle') }}"
|
||||||
data-battery-id="{{ $currentBatteryEntry->battery_id }}"
|
data-battery-id="{{ $currentBatteryEntry->battery_id }}"
|
||||||
data-battery-name="{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->name }}">
|
data-battery-name="{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->name }}">
|
||||||
<i class="fas fa-car-battery"></i>
|
<i class="fas fa-car-battery"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
||||||
<a class="dropdown-item battery-name-cell"
|
<a class="dropdown-item battery-name-cell"
|
||||||
data-battery-id="{{ $currentBatteryEntry->battery_id }}"
|
data-battery-id="{{ $currentBatteryEntry->battery_id }}" type="button"
|
||||||
type="button"
|
|
||||||
href="#">
|
href="#">
|
||||||
<span class="dropdown-item-text">{{ $__t('Battery overview') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Battery overview') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/batteriesjournal?embedded&battery=') }}{{ $currentBatteryEntry->battery_id }}">
|
href="{{ $U('/batteriesjournal?embedded&battery=') }}{{ $currentBatteryEntry->battery_id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Battery journal') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Battery journal') }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -150,15 +126,13 @@
|
||||||
<span class="dropdown-item-text">{{ $__t('Edit battery') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Edit battery') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/battery/' . $currentBatteryEntry->battery_id . '/grocycode?download=true') }}">
|
href="{{ $U('/battery/' . $currentBatteryEntry->battery_id . '/grocycode?download=true') }}">
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Battery'))) !!}
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Battery'))) !!}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
<a class="dropdown-item battery-grocycode-label-print"
|
<a class="dropdown-item battery-grocycode-label-print"
|
||||||
data-battery-id="{{ $currentBatteryEntry->battery_id }}"
|
data-battery-id="{{ $currentBatteryEntry->battery_id }}" type="button"
|
||||||
type="button"
|
|
||||||
href="#">
|
href="#">
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Battery'))) !!}
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Battery'))) !!}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -174,14 +148,16 @@
|
||||||
{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->used_in }}
|
{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->used_in }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span id="battery-{{ $currentBatteryEntry->battery_id }}-last-tracked-time">{{ $currentBatteryEntry->last_tracked_time }}</span>
|
<span
|
||||||
|
id="battery-{{ $currentBatteryEntry->battery_id }}-last-tracked-time">{{ $currentBatteryEntry->last_tracked_time }}</span>
|
||||||
<time id="battery-{{ $currentBatteryEntry->battery_id }}-last-tracked-time-timeago"
|
<time id="battery-{{ $currentBatteryEntry->battery_id }}-last-tracked-time-timeago"
|
||||||
class="timeago timeago-contextual"
|
class="timeago timeago-contextual"
|
||||||
datetime="{{ $currentBatteryEntry->last_tracked_time }}"></time>
|
datetime="{{ $currentBatteryEntry->last_tracked_time }}"></time>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if(FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->charge_interval_days > 0)
|
@if (FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->charge_interval_days > 0)
|
||||||
<span id="battery-{{ $currentBatteryEntry->battery_id }}-next-charge-time">{{ $currentBatteryEntry->next_estimated_charge_time }}</span>
|
<span
|
||||||
|
id="battery-{{ $currentBatteryEntry->battery_id }}-next-charge-time">{{ $currentBatteryEntry->next_estimated_charge_time }}</span>
|
||||||
<time id="battery-{{ $currentBatteryEntry->battery_id }}-next-charge-time-timeago"
|
<time id="battery-{{ $currentBatteryEntry->battery_id }}-next-charge-time-timeago"
|
||||||
class="timeago timeago-contextual"
|
class="timeago timeago-contextual"
|
||||||
datetime="{{ $currentBatteryEntry->next_estimated_charge_time }}"></time>
|
datetime="{{ $currentBatteryEntry->next_estimated_charge_time }}"></time>
|
||||||
|
|
@ -191,37 +167,37 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
{{ $currentBatteryEntry->due_type }}
|
{{ $currentBatteryEntry->due_type }}
|
||||||
@if($currentBatteryEntry->due_type == 'duetoday')
|
@if ($currentBatteryEntry->due_type == 'duetoday')
|
||||||
duesoon
|
duesoon
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody',
|
@include('components.userfields_tbody', [
|
||||||
array( 'userfields'=> $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $currentBatteryEntry->battery_id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$currentBatteryEntry->battery_id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="batteriesoverview-batterycard-modal" tabindex="-1">
|
||||||
id="batteriesoverview-batterycard-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@include('components.batterycard')
|
@include('components.batterycard')
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,15 @@
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<form id="batterytracking-form"
|
<form id="batterytracking-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="w-100"
|
<label class="w-100" for="battery_id">
|
||||||
for="battery_id">
|
|
||||||
{{ $__t('Battery') }}
|
{{ $__t('Battery') }}
|
||||||
<i id="barcode-lookup-hint"
|
<i id="barcode-lookup-hint" class="fas fa-barcode float-right mt-1"></i>
|
||||||
class="fas fa-barcode float-right mt-1"></i>
|
|
||||||
</label>
|
</label>
|
||||||
<select class="form-control combobox barcodescanner-input"
|
{{-- TODO: Select2: dynamic data: batteries --}}
|
||||||
id="battery_id"
|
<select class="form-control combobox barcodescanner-input" id="battery_id" name="battery_id" required data-target="@batterypicker">
|
||||||
name="battery_id"
|
|
||||||
required
|
|
||||||
data-target="@batterypicker">
|
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
@foreach($batteries as $battery)
|
@foreach($batteries as $battery)
|
||||||
<option value="{{ $battery->id }}">{{ $battery->name }}</option>
|
<option value="{{ $battery->id }}">{{ $battery->name }}</option>
|
||||||
|
|
@ -44,8 +38,7 @@
|
||||||
'invalidFeedback' => $__t('This can only be before now')
|
'invalidFeedback' => $__t('This can only be before now')
|
||||||
))
|
))
|
||||||
|
|
||||||
<button id="save-batterytracking-button"
|
<button id="save-batterytracking-button" class="btn btn-success">{{ $__t('OK') }}</button>
|
||||||
class="btn btn-success">{{ $__t('OK') }}</button>
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@
|
||||||
|
|
||||||
@php $prefillById = ''; if($mode=='edit' && !empty($chore->product_id)) { $prefillById = $chore->product_id; } @endphp
|
@php $prefillById = ''; if($mode=='edit' && !empty($chore->product_id)) { $prefillById = $chore->product_id; } @endphp
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'productsQuery' => 'order=name%3Acollate%20nocase',
|
||||||
'nextInputSelector' => '#product_amount',
|
'nextInputSelector' => '#product_amount',
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
'disallowAllProductWorkflows' => true,
|
'disallowAllProductWorkflows' => true,
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'chores')
|
@section('viewJsName', 'chores')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/chore/new') }}">
|
href="{{ $U('/chore/new') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -36,97 +31,77 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="form-check custom-control custom-checkbox">
|
<div class="form-check custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-disabled">
|
||||||
type="checkbox"
|
<label class="form-check-label custom-control-label" for="show-disabled">
|
||||||
id="show-disabled">
|
|
||||||
<label class="form-check-label custom-control-label"
|
|
||||||
for="show-disabled">
|
|
||||||
{{ $__t('Show disabled') }}
|
{{ $__t('Show disabled') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="chores-table"
|
{{-- TODO: DataTables: dynamic data: chores --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="chores-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#chores-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#chores-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Period type') }}</th>
|
<th class="allow-grouping">{{ $__t('Period type') }}</th>
|
||||||
<th>{{ $__t('Description') }}</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($chores as $chore)
|
@foreach ($chores as $chore)
|
||||||
<tr class="@if($chore->active == 0) text-muted @endif">
|
<tr class="@if ($chore->active == 0) text-muted @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm"
|
<a class="btn btn-info btn-sm" href="{{ $U('/chore/') }}{{ $chore->id }}"
|
||||||
href="{{ $U('/chore/') }}{{ $chore->id }}"
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm chore-delete-button"
|
<a class="btn btn-danger btn-sm chore-delete-button" href="#"
|
||||||
href="#"
|
data-chore-id="{{ $chore->id }}" data-chore-name="{{ $chore->name }}"
|
||||||
data-chore-id="{{ $chore->id }}"
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
data-chore-name="{{ $chore->name }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
||||||
<a class="dropdown-item merge-chores-button"
|
<a class="dropdown-item merge-chores-button" data-chore-id="{{ $chore->id }}"
|
||||||
data-chore-id="{{ $chore->id }}"
|
type="button" href="#">
|
||||||
type="button"
|
|
||||||
href="#">
|
|
||||||
<span class="dropdown-item-text">{{ $__t('Merge') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Merge') }}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -142,21 +117,23 @@
|
||||||
{{ $chore->description }}
|
{{ $chore->description }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $chore->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$chore->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="merge-chores-modal" tabindex="-1">
|
||||||
id="merge-chores-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
@ -164,44 +141,38 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="merge-chores-keep">{{ $__t('Chore to keep') }} <i class="fas fa-question-circle text-muted"
|
<label for="merge-chores-keep">{{ $__t('Chore to keep') }} <i
|
||||||
data-toggle="tooltip"
|
class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('After merging, this chore will be kept') }}"></i>
|
title="{{ $__t('After merging, this chore will be kept') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: chores --}}
|
||||||
id="merge-chores-keep">
|
<select class="custom-control custom-select" id="merge-chores-keep">
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($chores as $chore)
|
@foreach ($chores as $chore)
|
||||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="merge-chores-remove">{{ $__t('Chore to remove') }} <i class="fas fa-question-circle text-muted"
|
<label for="merge-chores-remove">{{ $__t('Chore to remove') }} <i
|
||||||
data-toggle="tooltip"
|
class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('After merging, all occurences of this chore will be replaced by the kept chore (means this chore will not exist anymore)') }}"></i>
|
title="{{ $__t('After merging, all occurences of this chore will be replaced by the kept chore (means this chore will not exist anymore)') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: chores --}}
|
||||||
id="merge-chores-remove">
|
<select class="custom-control custom-select" id="merge-chores-remove">
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($chores as $chore)
|
@foreach ($chores as $chore)
|
||||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
class="btn btn-secondary"
|
<button id="merge-chores-save-button" type="button" class="btn btn-primary"
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
|
||||||
<button id="merge-chores-save-button"
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary"
|
|
||||||
data-dismiss="modal">{{ $__t('OK') }}</button>
|
data-dismiss="modal">{{ $__t('OK') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,33 +5,27 @@
|
||||||
@section('viewJsName', 'choresjournal')
|
@section('viewJsName', 'choresjournal')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button" data-toggle="collapse"
|
||||||
type="button"
|
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
data-target="#table-filter-row">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -39,10 +33,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Chore') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Chore') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: chores --}}
|
||||||
id="chore-filter">
|
<select class="custom-control custom-select" id="chore-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($chores as $chore)
|
@foreach ($chores as $chore)
|
||||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -53,12 +47,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="daterange-filter">
|
||||||
id="daterange-filter">
|
|
||||||
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
||||||
<option value="6">{{ $__n(6, '%s month', '%s months') }}</option>
|
<option value="6">{{ $__n(6, '%s month', '%s months') }}</option>
|
||||||
<option value="12"
|
<option value="12" selected>{{ $__n(1, '%s year', '%s years') }}</option>
|
||||||
selected>{{ $__n(1, '%s year', '%s years') }}</option>
|
|
||||||
<option value="24">{{ $__n(2, '%s month', '%s years') }}</option>
|
<option value="24">{{ $__n(2, '%s month', '%s years') }}</option>
|
||||||
<option value="9999">{{ $__t('All') }}</option>
|
<option value="9999">{{ $__t('All') }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -66,56 +58,49 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="chores-journal-table"
|
{{-- TODO: DataTables: dynamic data: chores_log --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="chores-journal-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#chores-journal-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#chores-journal-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Chore') }}</th>
|
<th class="allow-grouping">{{ $__t('Chore') }}</th>
|
||||||
<th>{{ $__t('Tracked time') }}</th>
|
<th>{{ $__t('Tracked time') }}</th>
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
@if (GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($choresLog as $choreLogEntry)
|
@foreach ($choresLog as $choreLogEntry)
|
||||||
<tr id="chore-execution-{{ $choreLogEntry->id }}-row"
|
<tr id="chore-execution-{{ $choreLogEntry->id }}-row"
|
||||||
class="@if($choreLogEntry->undone == 1) text-muted @endif @if($choreLogEntry->skipped == 1) font-italic @endif">
|
class="@if ($choreLogEntry->undone == 1) text-muted @endif @if ($choreLogEntry->skipped == 1) font-italic @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-secondary btn-xs undo-chore-execution-button permission-CHORE_UNDO_EXECUTION @if($choreLogEntry->undone == 1) disabled @endif"
|
<a class="btn btn-secondary btn-xs undo-chore-execution-button permission-CHORE_UNDO_EXECUTION @if ($choreLogEntry->undone == 1) disabled @endif"
|
||||||
href="#"
|
href="#" data-execution-id="{{ $choreLogEntry->id }}" data-toggle="tooltip"
|
||||||
data-execution-id="{{ $choreLogEntry->id }}"
|
data-placement="left" title="{{ $__t('Undo chore execution') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Undo chore execution') }}">
|
|
||||||
<i class="fas fa-undo"></i>
|
<i class="fas fa-undo"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="name-anchor @if($choreLogEntry->undone == 1) text-strike-through @endif">{{ FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->name }}</span>
|
<span
|
||||||
@if($choreLogEntry->undone == 1)
|
class="name-anchor @if ($choreLogEntry->undone == 1) text-strike-through @endif">{{ FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->name }}</span>
|
||||||
|
@if ($choreLogEntry->undone == 1)
|
||||||
<br>
|
<br>
|
||||||
{{ $__t('Undone on') . ' ' . $choreLogEntry->undone_timestamp }}
|
{{ $__t('Undone on') . ' ' . $choreLogEntry->undone_timestamp }}
|
||||||
<time class="timeago timeago-contextual"
|
<time class="timeago timeago-contextual"
|
||||||
|
|
@ -124,13 +109,14 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span>{{ $choreLogEntry->tracked_time }}</span>
|
<span>{{ $choreLogEntry->tracked_time }}</span>
|
||||||
<time class="timeago timeago-contextual @if(FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->track_date_only == 1) timeago-date-only @endif"
|
<time
|
||||||
|
class="timeago timeago-contextual @if (FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->track_date_only == 1) timeago-date-only @endif"
|
||||||
datetime="{{ $choreLogEntry->tracked_time }}"></time>
|
datetime="{{ $choreLogEntry->tracked_time }}"></time>
|
||||||
@if($choreLogEntry->skipped == 1)
|
@if ($choreLogEntry->skipped == 1)
|
||||||
<span class="text-muted">{{ $__t('Skipped') }}</span>
|
<span class="text-muted">{{ $__t('Skipped') }}</span>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
@if (GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
<td>
|
<td>
|
||||||
@if ($choreLogEntry->done_by_user_id !== null && !empty($choreLogEntry->done_by_user_id))
|
@if ($choreLogEntry->done_by_user_id !== null && !empty($choreLogEntry->done_by_user_id))
|
||||||
{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $choreLogEntry->done_by_user_id)) }}
|
{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $choreLogEntry->done_by_user_id)) }}
|
||||||
|
|
@ -140,14 +126,18 @@
|
||||||
</td>
|
</td>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $choreLogEntry->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$choreLogEntry->id
|
||||||
|
),
|
||||||
|
])
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,19 @@
|
||||||
@section('viewJsName', 'choresoverview')
|
@section('viewJsName', 'choresoverview')
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}" rel="stylesheet">
|
||||||
rel="stylesheet">
|
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/choresjournal') }}">
|
href="{{ $U('/choresjournal') }}">
|
||||||
{{ $__t('Journal') }}
|
{{ $__t('Journal') }}
|
||||||
|
|
@ -29,49 +25,37 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-top border-bottom my-2 py-1">
|
<div class="border-top border-bottom my-2 py-1">
|
||||||
<div id="info-overdue-chores"
|
<div id="info-overdue-chores" data-status-filter="overdue"
|
||||||
data-status-filter="overdue"
|
|
||||||
class="error-message status-filter-message responsive-button mr-2"></div>
|
class="error-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-due-today-chores"
|
<div id="info-due-today-chores" data-status-filter="duetoday"
|
||||||
data-status-filter="duetoday"
|
|
||||||
class="normal-message status-filter-message responsive-button mr-2"></div>
|
class="normal-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-due-soon-chores"
|
<div id="info-due-soon-chores" data-status-filter="duesoon" data-next-x-days="{{ $nextXDays }}"
|
||||||
data-status-filter="duesoon"
|
class="warning-message status-filter-message responsive-message mr-2 @if ($nextXDays == 0) d-none @endif">
|
||||||
data-next-x-days="{{ $nextXDays }}"
|
</div>
|
||||||
class="warning-message status-filter-message responsive-message mr-2 @if($nextXDays == 0) d-none @endif"></div>
|
@if (GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
<div id="info-assigned-to-me-chores" data-user-filter="xx{{ GROCY_USER_ID }}xx"
|
||||||
<div id="info-assigned-to-me-chores"
|
|
||||||
data-user-filter="xx{{ GROCY_USER_ID }}xx"
|
|
||||||
class="secondary-message user-filter-message responsive-button"></div>
|
class="secondary-message user-filter-message responsive-button"></div>
|
||||||
@endif
|
@endif
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a class="btn btn-sm btn-outline-info d-md-none mt-1"
|
<a class="btn btn-sm btn-outline-info d-md-none mt-1" data-toggle="collapse" href="#table-filter-row"
|
||||||
data-toggle="collapse"
|
|
||||||
href="#table-filter-row"
|
|
||||||
role="button">
|
role="button">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info mt-1" href="#">
|
||||||
class="btn btn-sm btn-outline-info mt-1"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -79,194 +63,180 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
id="status-filter">
|
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<option value="overdue">{{ $__t('Overdue') }}</option>
|
<option value="overdue">{{ $__t('Overdue') }}</option>
|
||||||
<option value="duetoday">{{ $__t('Due today') }}</option>
|
<option value="duetoday">{{ $__t('Due today') }}</option>
|
||||||
@if($nextXDays > 0)
|
@if ($nextXDays > 0)
|
||||||
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
||||||
@endif
|
@endif
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
@if (GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Assignment') }}</span>
|
<span class="input-group-text"><i
|
||||||
|
class="fas fa-filter"></i> {{ $__t('Assignment') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: users --}}
|
||||||
id="user-filter">
|
<select class="custom-control custom-select" id="user-filter">
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($users as $user)
|
@foreach ($users as $user)
|
||||||
<option data-user-id="{{ $user->id }}"
|
<option data-user-id="{{ $user->id }}" value="xx{{ $user->id }}xx">
|
||||||
value="xx{{ $user->id }}xx">{{ $user->display_name }}</option>
|
{{ $user->display_name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="chores-overview-table"
|
{{-- TODO: DataTables: dynamic data: chores --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="chores-overview-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#chores-overview-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#chores-overview-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Chore') }}</th>
|
<th>{{ $__t('Chore') }}</th>
|
||||||
<th>{{ $__t('Next estimated tracking') }}</th>
|
<th>{{ $__t('Next estimated tracking') }}</th>
|
||||||
<th>{{ $__t('Last tracked') }}</th>
|
<th>{{ $__t('Last tracked') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS) d-none @endif allow-grouping">{{ $__t('Assigned to') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS) d-none @endif allow-grouping">
|
||||||
|
{{ $__t('Assigned to') }}</th>
|
||||||
<th class="d-none">Hidden status</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th class="d-none">Hidden assigned to user id</th>
|
<th class="d-none">Hidden assigned to user id</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($currentChores as $curentChoreEntry)
|
@foreach ($currentChores as $curentChoreEntry)
|
||||||
<tr id="chore-{{ $curentChoreEntry->chore_id }}-row"
|
<tr id="chore-{{ $curentChoreEntry->chore_id }}-row"
|
||||||
class="@if($curentChoreEntry->due_type == 'overdue') table-danger @elseif($curentChoreEntry->due_type == 'duetoday') table-info @elseif($curentChoreEntry->due_type == 'duesoon') table-warning @endif">
|
class="@if ($curentChoreEntry->due_type == 'overdue') table-danger @elseif($curentChoreEntry->due_type == 'duetoday') table-info @elseif($curentChoreEntry->due_type == 'duesoon') table-warning @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-success btn-sm track-chore-button permission-CHORE_TRACK_EXECUTION"
|
<a class="btn btn-success btn-sm track-chore-button permission-CHORE_TRACK_EXECUTION"
|
||||||
href="#"
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Track chore execution') }}"
|
title="{{ $__t('Track chore execution') }}"
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
||||||
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
||||||
<i class="fas fa-play"></i>
|
<i class="fas fa-play"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-secondary btn-sm track-chore-button skip permission-CHORE_TRACK_EXECUTION @if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type == \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY) disabled @endif"
|
<a class="btn btn-secondary btn-sm track-chore-button skip permission-CHORE_TRACK_EXECUTION @if (FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type == \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Skip next chore schedule') }}"
|
title="{{ $__t('Skip next chore schedule') }}"
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
||||||
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
||||||
<i class="fas fa-forward"></i>
|
<i class="fas fa-forward"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
||||||
<a class="dropdown-item chore-name-cell"
|
<a class="dropdown-item chore-name-cell"
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
data-chore-id="{{ $curentChoreEntry->chore_id }}" type="button" href="#">
|
||||||
type="button"
|
|
||||||
href="#">
|
|
||||||
<span class="dropdown-item-text">{{ $__t('Chore overview') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Chore overview') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/choresjournal?embedded&chore=') }}{{ $curentChoreEntry->chore_id }}">
|
href="{{ $U('/choresjournal?embedded&chore=') }}{{ $curentChoreEntry->chore_id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Chore journal') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Chore journal') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item permission-MASTER_DATA_EDIT"
|
<a class="dropdown-item permission-MASTER_DATA_EDIT" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/chore/') }}{{ $curentChoreEntry->chore_id }}">
|
href="{{ $U('/chore/') }}{{ $curentChoreEntry->chore_id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Edit chore') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Edit chore') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/chore/' . $curentChoreEntry->chore_id . '/grocycode?download=true') }}">
|
href="{{ $U('/chore/' . $curentChoreEntry->chore_id . '/grocycode?download=true') }}">
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Chore'))) !!}
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Chore'))) !!}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
<a class="dropdown-item chore-grocycode-label-print"
|
<a class="dropdown-item chore-grocycode-label-print"
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
data-chore-id="{{ $curentChoreEntry->chore_id }}" type="button" href="#">
|
||||||
type="button"
|
|
||||||
href="#">
|
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Chore'))) !!}
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Chore'))) !!}
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="chore-name-cell cursor-link"
|
<td class="chore-name-cell cursor-link" data-chore-id="{{ $curentChoreEntry->chore_id }}">
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}">
|
|
||||||
{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY)
|
@if (FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY)
|
||||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time">{{ $curentChoreEntry->next_estimated_execution_time }}</span>
|
<span
|
||||||
|
id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time">{{ $curentChoreEntry->next_estimated_execution_time }}</span>
|
||||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time-timeago"
|
<time id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time-timeago"
|
||||||
class="timeago timeago-contextual @if($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
class="timeago timeago-contextual @if ($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
||||||
datetime="{{ $curentChoreEntry->next_estimated_execution_time }}"></time>
|
datetime="{{ $curentChoreEntry->next_estimated_execution_time }}"></time>
|
||||||
@else
|
@else
|
||||||
<span>-</span>
|
<span>-</span>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time">{{ $curentChoreEntry->last_tracked_time }}</span>
|
<span
|
||||||
|
id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time">{{ $curentChoreEntry->last_tracked_time }}</span>
|
||||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time-timeago"
|
<time id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time-timeago"
|
||||||
class="timeago timeago-contextual @if($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
class="timeago timeago-contextual @if ($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
||||||
datetime="{{ $curentChoreEntry->last_tracked_time }}"></time>
|
datetime="{{ $curentChoreEntry->last_tracked_time }}"></time>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS) d-none @endif">
|
||||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-assigned-user">
|
<span id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-assigned-user">
|
||||||
@if(!empty($curentChoreEntry->next_execution_assigned_to_user_id))
|
@if (!empty($curentChoreEntry->next_execution_assigned_to_user_id))
|
||||||
{{ FindObjectInArrayByPropertyValue($users, 'id', $curentChoreEntry->next_execution_assigned_to_user_id)->display_name }}
|
{{ FindObjectInArrayByPropertyValue($users, 'id', $curentChoreEntry->next_execution_assigned_to_user_id)->display_name }}
|
||||||
@else
|
@else
|
||||||
<span>-</span>
|
<span>-</span>
|
||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td id="chore-{{ $curentChoreEntry->chore_id }}-due-filter-column"
|
<td id="chore-{{ $curentChoreEntry->chore_id }}-due-filter-column" class="d-none">
|
||||||
class="d-none">
|
|
||||||
{{ $curentChoreEntry->due_type }}
|
{{ $curentChoreEntry->due_type }}
|
||||||
@if($curentChoreEntry->due_type == 'duetoday')
|
@if ($curentChoreEntry->due_type == 'duetoday')
|
||||||
duesoon
|
duesoon
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
@if(!empty($curentChoreEntry->next_execution_assigned_to_user_id))
|
@if (!empty($curentChoreEntry->next_execution_assigned_to_user_id))
|
||||||
xx{{ $curentChoreEntry->next_execution_assigned_to_user_id }}xx
|
xx{{ $curentChoreEntry->next_execution_assigned_to_user_id }}xx
|
||||||
</td>
|
</td>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $curentChoreEntry->chore_id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$curentChoreEntry->chore_id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="choresoverview-chorecard-modal" tabindex="-1">
|
||||||
id="choresoverview-chorecard-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@include('components.chorecard')
|
@include('components.chorecard')
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,15 @@
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<form id="choretracking-form"
|
<form id="choretracking-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="w-100"
|
<label class="w-100" for="chore_id">
|
||||||
for="chore_id">
|
|
||||||
{{ $__t('Chore') }}
|
{{ $__t('Chore') }}
|
||||||
<i id="barcode-lookup-hint"
|
<i id="barcode-lookup-hint" class="fas fa-barcode float-right mt-1"></i>
|
||||||
class="fas fa-barcode float-right mt-1"></i>
|
|
||||||
</label>
|
</label>
|
||||||
<select class="form-control combobox barcodescanner-input"
|
{{-- TODO: Select2: dynamic data: chores --}}
|
||||||
id="chore_id"
|
<select class="form-control combobox barcodescanner-input" id="chore_id" name="chore_id" required data-target="@chorepicker">
|
||||||
name="chore_id"
|
|
||||||
required
|
|
||||||
data-target="@chorepicker">
|
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
@foreach($chores as $chore)
|
@foreach($chores as $chore)
|
||||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||||
|
|
@ -52,10 +46,7 @@
|
||||||
'prefillByUserId' => GROCY_USER_ID
|
'prefillByUserId' => GROCY_USER_ID
|
||||||
))
|
))
|
||||||
@else
|
@else
|
||||||
<input type="hidden"
|
<input type="hidden" id="user_id" name="user_id" value="{{ GROCY_USER_ID }}">
|
||||||
id="user_id"
|
|
||||||
name="user_id"
|
|
||||||
value="{{ GROCY_USER_ID }}">
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@include('components.userfieldsform', array(
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,17 @@
|
||||||
margin-right: 36px !important;
|
margin-right: 36px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-group-prepend #barcodescanner-start-button {
|
||||||
|
position: static;
|
||||||
|
right: unset;
|
||||||
|
margin: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group>#barcodescanner-start-button-container+.select2-hidden-accessible+.select2-container--bootstrap>.selection>.select2-selection, .input-group>#barcodescanner-start-button-container+.select2-hidden-accessible+.select2-container--bootstrap>.selection>.select2-selection.form-control {
|
||||||
|
border-top-right-radius: .25rem;
|
||||||
|
border-bottom-right-radius: .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,48 @@
|
||||||
@once
|
@once
|
||||||
@push('componentScripts')
|
@push('componentScripts')
|
||||||
<script src="{{ $U('/viewjs/components/locationpicker.js', true) }}?v={{ $version }}"></script>
|
<script src="{{ $U('/viewjs/components/locationpicker.js', true) }}?v={{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
@endonce
|
@endonce
|
||||||
|
|
||||||
@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp
|
@php
|
||||||
@php if(empty($prefillById)) { $prefillById = ''; } @endphp
|
if (empty($prefillByName)) {
|
||||||
@php if(!isset($isRequired)) { $isRequired = true; } @endphp
|
$prefillByName = '';
|
||||||
@php if(empty($hint)) { $hint = ''; } @endphp
|
}
|
||||||
@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp
|
@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
|
||||||
|
|
||||||
<div class="form-group"
|
<div class="form-group" data-next-input-selector="{{ $nextInputSelector }}"
|
||||||
data-next-input-selector="{{ $nextInputSelector }}"
|
data-prefill-by-name="{{ $prefillByName }}" data-prefill-by-id="{{ $prefillById }}">
|
||||||
data-prefill-by-name="{{ $prefillByName }}"
|
|
||||||
data-prefill-by-id="{{ $prefillById }}">
|
|
||||||
<label for="location_id">{{ $__t('Location') }}
|
<label for="location_id">{{ $__t('Location') }}
|
||||||
@if(!empty($hint))
|
@if (!empty($hint))
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $hint }}"></i>
|
title="{{ $hint }}"></i>
|
||||||
@endif
|
@endif
|
||||||
</label>
|
</label>
|
||||||
<select class="form-control location-combobox"
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
id="location_id"
|
<select class="form-control location-combobox" id="location_id" name="location_id"
|
||||||
name="location_id"
|
@if ($isRequired) required @endif>
|
||||||
@if($isRequired)
|
|
||||||
required
|
|
||||||
@endif>
|
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,74 @@
|
||||||
@once
|
@once
|
||||||
@push('componentScripts')
|
@push('componentScripts')
|
||||||
<script src="{{ $U('/viewjs/components/productpicker.js', true) }}?v={{ $version }}"></script>
|
<script src="{{ $U('/viewjs/components/productpicker.js', true) }}?v={{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
@endonce
|
@endonce
|
||||||
|
|
||||||
@php if(empty($disallowAddProductWorkflows)) { $disallowAddProductWorkflows = false; } @endphp
|
@php
|
||||||
@php if(empty($disallowAllProductWorkflows)) { $disallowAllProductWorkflows = false; } @endphp
|
if (empty($disallowAddProductWorkflows)) {
|
||||||
@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp
|
$disallowAddProductWorkflows = false;
|
||||||
@php if(empty($prefillById)) { $prefillById = ''; } @endphp
|
}
|
||||||
@php if(!isset($isRequired)) { $isRequired = true; } @endphp
|
if (empty($disallowAllProductWorkflows)) {
|
||||||
@php if(!isset($label)) { $label = 'Product'; } @endphp
|
$disallowAllProductWorkflows = false;
|
||||||
@php if(!isset($disabled)) { $disabled = false; } @endphp
|
}
|
||||||
@php if(empty($hint)) { $hint = ''; } @endphp
|
if (empty($prefillByName)) {
|
||||||
@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp
|
$prefillByName = '';
|
||||||
@php if(empty($validationMessage)) { $validationMessage = 'You have to select a product'; } @endphp
|
}
|
||||||
|
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
|
||||||
|
|
||||||
<div class="form-group"
|
<div class="form-group" data-next-input-selector="{{ $nextInputSelector }}"
|
||||||
data-next-input-selector="{{ $nextInputSelector }}"
|
|
||||||
data-disallow-add-product-workflows="{{ BoolToString($disallowAddProductWorkflows) }}"
|
data-disallow-add-product-workflows="{{ BoolToString($disallowAddProductWorkflows) }}"
|
||||||
data-disallow-all-product-workflows="{{ BoolToString($disallowAllProductWorkflows) }}"
|
data-disallow-all-product-workflows="{{ BoolToString($disallowAllProductWorkflows) }}"
|
||||||
data-prefill-by-name="{{ $prefillByName }}"
|
data-prefill-by-name="{{ $prefillByName }}" data-prefill-by-id="{{ $prefillById }}"
|
||||||
data-prefill-by-id="{{ $prefillById }}">
|
data-products-query="{{ $productsQuery }}">
|
||||||
<label class="w-100"
|
<label class="w-100" for="product_id">
|
||||||
for="product_id">
|
|
||||||
{{ $__t($label) }}
|
{{ $__t($label) }}
|
||||||
@if(!$disallowAllProductWorkflows)
|
@if (!$disallowAllProductWorkflows)
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('Type a new product name or barcode and hit TAB or ENTER to start a workflow') }}"></i>
|
title="{{ $__t('Type a new product name or barcode and hit TAB or ENTER to start a workflow') }}"></i>
|
||||||
@endif
|
@endif
|
||||||
@if(!empty($hint))
|
@if (!empty($hint))
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $hint }}"></i>
|
title="{{ $hint }}"></i>
|
||||||
@endif
|
@endif
|
||||||
<span id="barcode-lookup-disabled-hint"
|
<span id="barcode-lookup-disabled-hint" class="small text-muted d-none float-right">
|
||||||
class="small text-muted d-none float-right"> {{ $__t('Barcode lookup is disabled') }}</span>
|
{{ $__t('Barcode lookup is disabled') }}</span>
|
||||||
<i id="barcode-lookup-hint"
|
<i id="barcode-lookup-hint" class="fas fa-barcode float-right mt-1"></i>
|
||||||
class="fas fa-barcode float-right mt-1"></i>
|
|
||||||
</label>
|
</label>
|
||||||
<select class="form-control product-combobox barcodescanner-input"
|
<div class="input-group">
|
||||||
id="product_id"
|
<select class="select2 custom-control custom-select barcodescanner-input" id="product_id" name="product_id"
|
||||||
name="product_id"
|
@if ($isRequired) required @endif @if ($disabled) disabled @endif
|
||||||
@if($isRequired)
|
data-target="@productpicker"></select>
|
||||||
required
|
|
||||||
@endif
|
|
||||||
@if($disabled)
|
|
||||||
disabled
|
|
||||||
@endif
|
|
||||||
data-target="@productpicker">
|
|
||||||
<option value=""></option>
|
|
||||||
@foreach($products as $product)
|
|
||||||
@php $bc = null;
|
|
||||||
if(isset($barcodes)) {
|
|
||||||
$bc = FindObjectInArrayByPropertyValue($barcodes, 'product_id', $product->id);
|
|
||||||
}
|
|
||||||
@endphp
|
|
||||||
<option data-additional-searchdata="@if(isset($bc)){{ $bc->barcodes }}@endif,"
|
|
||||||
value="{{ $product->id }}">{{ $product->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback">{{ $__t($validationMessage) }}</div>
|
<div class="invalid-feedback">{{ $__t($validationMessage) }}</div>
|
||||||
<div id="custom-productpicker-error"
|
</div>
|
||||||
class="form-text text-danger d-none"></div>
|
<div id="custom-productpicker-error" class="form-text text-danger d-none"></div>
|
||||||
<div id="flow-info-InplaceAddBarcodeToExistingProduct"
|
<div id="flow-info-InplaceAddBarcodeToExistingProduct" class="form-text text-info small d-none"><strong><span
|
||||||
class="form-text text-info small d-none"><strong><span id="InplaceAddBarcodeToExistingProduct"></span></strong> {{ $__t('will be added to the list of barcodes for the selected product on submit') }}</div>
|
id="InplaceAddBarcodeToExistingProduct"></span></strong>
|
||||||
|
{{ $__t('will be added to the list of barcodes for the selected product on submit') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.barcodescanner')
|
@include('components.barcodescanner')
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,49 @@
|
||||||
@once
|
@once
|
||||||
@push('componentScripts')
|
@push('componentScripts')
|
||||||
<script src="{{ $U('/viewjs/components/recipepicker.js', true) }}?v={{ $version }}"></script>
|
<script src="{{ $U('/viewjs/components/recipepicker.js', true) }}?v={{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
@endonce
|
@endonce
|
||||||
|
|
||||||
@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp
|
@php
|
||||||
@php if(empty($prefillById)) { $prefillById = ''; } @endphp
|
if (empty($prefillByName)) {
|
||||||
@php if(!isset($isRequired)) { $isRequired = true; } @endphp
|
$prefillByName = '';
|
||||||
@php if(empty($hint)) { $hint = ''; } @endphp
|
}
|
||||||
@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp
|
@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
|
||||||
|
|
||||||
<div class="form-group"
|
<div class="form-group" data-next-input-selector="{{ $nextInputSelector }}"
|
||||||
data-next-input-selector="{{ $nextInputSelector }}"
|
data-prefill-by-name="{{ $prefillByName }}" data-prefill-by-id="{{ $prefillById }}">
|
||||||
data-prefill-by-name="{{ $prefillByName }}"
|
<label class="w-100" for="recipe_id">{{ $__t('Recipe') }}
|
||||||
data-prefill-by-id="{{ $prefillById }}">
|
@if (!empty($hint))
|
||||||
<label class="w-100"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
for="recipe_id">{{ $__t('Recipe') }}
|
|
||||||
@if(!empty($hint))
|
|
||||||
<i class="fas fa-question-circle text-muted"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $hint }}"></i>
|
title="{{ $hint }}"></i>
|
||||||
@endif
|
@endif
|
||||||
<i class="fas fa-barcode float-right mt-1"></i>
|
<i class="fas fa-barcode float-right mt-1"></i>
|
||||||
</label>
|
</label>
|
||||||
<select class="form-control recipe-combobox barcodescanner-input"
|
{{-- TODO: Select2: dynamic data: recipes --}}
|
||||||
id="recipe_id"
|
<select class="form-control recipe-combobox barcodescanner-input" id="recipe_id" name="recipe_id"
|
||||||
name="recipe_id"
|
data-target="@recipepicker" @if ($isRequired) required @endif>
|
||||||
data-target="@recipepicker"
|
|
||||||
@if($isRequired)
|
|
||||||
required
|
|
||||||
@endif>
|
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
@foreach($recipes as $recipe)
|
@foreach ($recipes as $recipe)
|
||||||
<option value="{{ $recipe->id }}">{{ $recipe->name }}</option>
|
<option value="{{ $recipe->id }}">{{ $recipe->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,45 @@
|
||||||
@once
|
@once
|
||||||
@push('componentScripts')
|
@push('componentScripts')
|
||||||
<script src="{{ $U('/viewjs/components/shoppinglocationpicker.js', true) }}?v={{ $version }}"></script>
|
<script src="{{ $U('/viewjs/components/shoppinglocationpicker.js', true) }}?v={{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
@endonce
|
@endonce
|
||||||
|
|
||||||
@php if(empty($prefillByName)) { $prefillByName = ''; } @endphp
|
@php
|
||||||
@php if(empty($prefillById)) { $prefillById = ''; } @endphp
|
if (empty($prefillByName)) {
|
||||||
@php if(!isset($isRequired)) { $isRequired = false; } @endphp
|
$prefillByName = '';
|
||||||
@php if(empty($hint)) { $hint = ''; } @endphp
|
}
|
||||||
@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp
|
@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
|
||||||
|
|
||||||
<div class="form-group"
|
<div class="form-group" data-next-input-selector="{{ $nextInputSelector }}"
|
||||||
data-next-input-selector="{{ $nextInputSelector }}"
|
data-prefill-by-name="{{ $prefillByName }}" data-prefill-by-id="{{ $prefillById }}">
|
||||||
data-prefill-by-name="{{ $prefillByName }}"
|
<label for="shopping_location_id">{{ $__t($label) }} <span
|
||||||
data-prefill-by-id="{{ $prefillById }}">
|
@if (!empty($hintId)) id="{{ $hintId }}" @endif
|
||||||
<label for="shopping_location_id">{{ $__t($label) }} <span @if(!empty($hintId))id="{{ $hintId }}"
|
|
||||||
@endif
|
|
||||||
class="small text-muted">{{ $hint }}</span></label>
|
class="small text-muted">{{ $hint }}</span></label>
|
||||||
<select class="form-control shopping-location-combobox"
|
{{-- TODO: Select2: dynamic data: shopping_locations --}}
|
||||||
id="shopping_location_id"
|
<select class="form-control shopping-location-combobox" id="shopping_location_id" name="shopping_location_id"
|
||||||
name="shopping_location_id"
|
@if ($isRequired) required @endif>
|
||||||
@if($isRequired)
|
|
||||||
required
|
|
||||||
@endif>
|
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
@foreach($shoppinglocations as $shoppinglocation)
|
@foreach ($shoppinglocations as $shoppinglocation)
|
||||||
<option value="{{ $shoppinglocation->id }}">{{ $shoppinglocation->name }}</option>
|
<option value="{{ $shoppinglocation->id }}">{{ $shoppinglocation->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,34 @@
|
||||||
@once
|
@once
|
||||||
@push('componentScripts')
|
@push('componentScripts')
|
||||||
<script src="{{ $U('/viewjs/components/userpicker.js', true) }}?v={{ $version }}"></script>
|
<script src="{{ $U('/viewjs/components/userpicker.js', true) }}?v={{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
@endonce
|
@endonce
|
||||||
|
|
||||||
@php if(empty($prefillByUsername)) { $prefillByUsername = ''; } @endphp
|
@php
|
||||||
@php if(empty($prefillByUserId)) { $prefillByUserId = ''; } @endphp
|
if (empty($prefillByUsername)) {
|
||||||
@php if(!isset($nextInputSelector)) { $nextInputSelector = ''; } @endphp
|
$prefillByUsername = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@php
|
||||||
|
if (empty($prefillByUserId)) {
|
||||||
|
$prefillByUserId = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@php
|
||||||
|
if (!isset($nextInputSelector)) {
|
||||||
|
$nextInputSelector = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
|
||||||
<div class="form-group"
|
<div class="form-group" data-next-input-selector="{{ $nextInputSelector }}"
|
||||||
data-next-input-selector="{{ $nextInputSelector }}"
|
data-prefill-by-username="{{ $prefillByUsername }}" data-prefill-by-user-id="{{ $prefillByUserId }}">
|
||||||
data-prefill-by-username="{{ $prefillByUsername }}"
|
|
||||||
data-prefill-by-user-id="{{ $prefillByUserId }}">
|
|
||||||
<label for="user_id">{{ $__t($label) }}</label>
|
<label for="user_id">{{ $__t($label) }}</label>
|
||||||
<select class="form-control user-combobox"
|
{{-- TODO: Select2: dynamic data: users --}}
|
||||||
id="user_id"
|
<select class="form-control user-combobox" id="user_id" name="user_id">
|
||||||
name="user_id">
|
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
@foreach($users as $user)
|
@foreach ($users as $user)
|
||||||
<option data-additional-searchdata="{{ $user->username }}"
|
<option data-additional-searchdata="{{ $user->username }}" value="{{ $user->id }}">
|
||||||
value="{{ $user->id }}">{{ GetUserDisplayName($user) }}</option>
|
{{ GetUserDisplayName($user) }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,40 +5,39 @@
|
||||||
@section('viewJsName', 'consume')
|
@section('viewJsName', 'consume')
|
||||||
|
|
||||||
@push('pageScripts')
|
@push('pageScripts')
|
||||||
<script src="{{ $U('/js/grocy_uisound.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/js/grocy_uisound.js?v=', true) }}{{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<script>
|
<script>
|
||||||
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
||||||
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
||||||
Grocy.DefaultMinAmount = '{{$DEFAULT_MIN_AMOUNT}}';
|
Grocy.DefaultMinAmount = '{{ $DEFAULT_MIN_AMOUNT }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3 hide-when-embedded"
|
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3 hide-when-embedded"
|
||||||
type="button"
|
type="button" data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
@if (!$embedded)
|
||||||
@if(!$embedded)
|
|
||||||
<button id="scan-mode-button"
|
<button id="scan-mode-button"
|
||||||
class="btn @if(boolval($userSettings['scan_mode_consume_enabled'])) btn-success @else btn-danger @endif m-1 mt-md-0 mb-md-0 float-right"
|
class="btn @if (boolval($userSettings['scan_mode_consume_enabled'])) btn-success @else btn-danger @endif m-1 mt-md-0 mb-md-0 float-right"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
title="{{ $__t('When enabled, after changing/scanning a product and if all fields could be automatically populated (by product and/or barcode defaults), the transaction is automatically submitted') }}">{{ $__t('Scan mode') }} <span id="scan-mode-status">@if(boolval($userSettings['scan_mode_consume_enabled'])) {{ $__t('on') }} @else {{ $__t('off') }} @endif</span></button>
|
title="{{ $__t('When enabled, after changing/scanning a product and if all fields could be automatically populated (by product and/or barcode defaults), the transaction is automatically submitted') }}">{{ $__t('Scan mode') }}
|
||||||
<input id="scan-mode"
|
<span id="scan-mode-status">
|
||||||
type="checkbox"
|
@if (boolval($userSettings['scan_mode_consume_enabled']))
|
||||||
class="d-none user-setting-control"
|
{{ $__t('on') }}
|
||||||
data-setting-key="scan_mode_consume_enabled"
|
@else
|
||||||
@if(boolval($userSettings['scan_mode_consume_enabled']))
|
{{ $__t('off') }}
|
||||||
checked
|
@endif
|
||||||
@endif>
|
</span></button>
|
||||||
|
<input id="scan-mode" type="checkbox" class="d-none user-setting-control"
|
||||||
|
data-setting-key="scan_mode_consume_enabled" @if (boolval($userSettings['scan_mode_consume_enabled'])) checked @endif>
|
||||||
@else
|
@else
|
||||||
<script>
|
<script>
|
||||||
Grocy.UserSettings.scan_mode_consume_enabled = false;
|
Grocy.UserSettings.scan_mode_consume_enabled = false;
|
||||||
|
|
@ -49,44 +48,41 @@
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<form id="consume-form"
|
<form id="consume-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', [
|
||||||
'products' => $products,
|
'productsQuery' => 'query%5B%5D=active%3D1&only_in_stock=1&order=name',
|
||||||
'barcodes' => $barcodes,
|
|
||||||
'nextInputSelector' => '#amount',
|
'nextInputSelector' => '#amount',
|
||||||
'disallowAddProductWorkflows' => true
|
'disallowAddProductWorkflows' => true,
|
||||||
))
|
])
|
||||||
|
|
||||||
<div id="consume-exact-amount-group"
|
<div id="consume-exact-amount-group" class="form-group d-none">
|
||||||
class="form-group d-none">
|
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="consume-exact-amount"
|
||||||
type="checkbox"
|
name="consume-exact-amount" value="1">
|
||||||
id="consume-exact-amount"
|
|
||||||
name="consume-exact-amount"
|
|
||||||
value="1">
|
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
for="consume-exact-amount">{{ $__t('Consume exact amount') }}
|
for="consume-exact-amount">{{ $__t('Consume exact amount') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.productamountpicker', array(
|
@include('components.productamountpicker', [
|
||||||
'value' => 1,
|
'value' => 1,
|
||||||
'additionalHtmlContextHelp' => '<div id="tare-weight-handling-info"
|
'additionalHtmlContextHelp' =>
|
||||||
class="text-info font-italic d-none">' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '</div>'
|
'<div id="tare-weight-handling-info" class="text-info font-italic d-none">' .
|
||||||
))
|
$__t(
|
||||||
|
'Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated'
|
||||||
|
) .
|
||||||
|
'</div>',
|
||||||
|
])
|
||||||
|
|
||||||
<div class="form-group @if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
<div class="form-group @if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
||||||
<label for="location_id">{{ $__t('Location') }}</label>
|
<label for="location_id">{{ $__t('Location') }}</label>
|
||||||
<select required
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
class="custom-control custom-select location-combobox"
|
<select required class="custom-control custom-select location-combobox" id="location_id"
|
||||||
id="location_id"
|
|
||||||
name="location_id">
|
name="location_id">
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -95,52 +91,41 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="spoiled" name="spoiled"
|
||||||
type="checkbox"
|
|
||||||
id="spoiled"
|
|
||||||
name="spoiled"
|
|
||||||
value="1">
|
value="1">
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label" for="spoiled">{{ $__t('Spoiled') }}
|
||||||
for="spoiled">{{ $__t('Spoiled') }}
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="use_specific_stock_entry"
|
||||||
type="checkbox"
|
name="use_specific_stock_entry" value="1">
|
||||||
id="use_specific_stock_entry"
|
|
||||||
name="use_specific_stock_entry"
|
|
||||||
value="1">
|
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
for="use_specific_stock_entry">{{ $__t('Use a specific stock item') }}
|
for="use_specific_stock_entry">{{ $__t('Use a specific stock item') }}
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
data-trigger="hover click"
|
||||||
title="{{ $__t('The first item in this list would be picked by the default rule which is "Opened first, then first due first, then first in first out"') }}"></i>
|
title="{{ $__t('The first item in this list would be picked by the default rule which is "Opened first, then first due first, then first in first out"') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<select disabled
|
<select disabled class="custom-control custom-select mt-2" id="specific_stock_entry"
|
||||||
class="custom-control custom-select mt-2"
|
|
||||||
id="specific_stock_entry"
|
|
||||||
name="specific_stock_entry">
|
name="specific_stock_entry">
|
||||||
<option></option>
|
<option></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (GROCY_FEATURE_FLAG_RECIPES)
|
@if (GROCY_FEATURE_FLAG_RECIPES)
|
||||||
@include('components.recipepicker', array(
|
@include('components.recipepicker', [
|
||||||
'recipes' => $recipes,
|
'recipes' => $recipes,
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
'hint' => $__t('This is for statistical purposes only')
|
'hint' => $__t('This is for statistical purposes only'),
|
||||||
))
|
])
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<button id="save-consume-button"
|
<button id="save-consume-button" class="btn btn-success">{{ $__t('OK') }}</button>
|
||||||
class="btn btn-success">{{ $__t('OK') }}</button>
|
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
||||||
<button id="save-mark-as-open-button"
|
<button id="save-mark-as-open-button"
|
||||||
class="btn btn-secondary permission-STOCK_OPEN">{{ $__t('Mark as opened') }}</button>
|
class="btn btn-secondary permission-STOCK_OPEN">{{ $__t('Mark as opened') }}</button>
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -151,5 +136,5 @@
|
||||||
<div class="col-12 col-md-6 col-xl-4 hide-when-embedded">
|
<div class="col-12 col-md-6 col-xl-4 hide-when-embedded">
|
||||||
@include('components.productcard')
|
@include('components.productcard')
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'equipment')
|
@section('viewJsName', 'equipment')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-4 pb-3">
|
<div class="col-12 col-md-4 pb-3">
|
||||||
<div class="title-related-links border-bottom mb-2 py-1">
|
<div class="title-related-links border-bottom mb-2 py-1">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/equipment/new') }}">
|
href="{{ $U('/equipment/new') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -32,69 +27,57 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="equipment-table"
|
{{-- TODO: DataTables: dynamic data: equipment --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="equipment-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#equipment-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#equipment-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($equipment as $equipmentItem)
|
@foreach ($equipment as $equipmentItem)
|
||||||
<tr data-equipment-id="{{ $equipmentItem->id }}">
|
<tr data-equipment-id="{{ $equipmentItem->id }}">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm hide-when-embedded hide-on-fullscreen-card"
|
<a class="btn btn-info btn-sm hide-when-embedded hide-on-fullscreen-card"
|
||||||
href="{{ $U('/equipment/') }}{{ $equipmentItem->id }}"
|
href="{{ $U('/equipment/') }}{{ $equipmentItem->id }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right hide-on-fullscreen-card hide-when-embedded">
|
<div
|
||||||
<a class="dropdown-item equipment-delete-button"
|
class="table-inline-menu dropdown-menu dropdown-menu-right hide-on-fullscreen-card hide-when-embedded">
|
||||||
type="button"
|
<a class="dropdown-item equipment-delete-button" type="button" href="#"
|
||||||
href="#"
|
|
||||||
data-equipment-id="{{ $equipmentItem->id }}"
|
data-equipment-id="{{ $equipmentItem->id }}"
|
||||||
data-equipment-name="{{ $equipmentItem->name }}">
|
data-equipment-name="{{ $equipmentItem->name }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Delete this item') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Delete this item') }}</span>
|
||||||
|
|
@ -106,10 +89,14 @@
|
||||||
{{ $equipmentItem->name }}
|
{{ $equipmentItem->name }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $equipmentItem->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$equipmentItem->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
@ -120,70 +107,54 @@
|
||||||
<div class="col-12 col-md-8">
|
<div class="col-12 col-md-8">
|
||||||
<ul class="nav nav-tabs grocy-tabs">
|
<ul class="nav nav-tabs grocy-tabs">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active"
|
<a class="nav-link active" data-toggle="tab"
|
||||||
data-toggle="tab"
|
|
||||||
href="#instruction-manual-tab">{{ $__t('Instruction manual') }}</a>
|
href="#instruction-manual-tab">{{ $__t('Instruction manual') }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link"
|
<a class="nav-link" data-toggle="tab" href="#description-tab">{{ $__t('Notes') }}</a>
|
||||||
data-toggle="tab"
|
|
||||||
href="#description-tab">{{ $__t('Notes') }}</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content grocy-tabs">
|
<div class="tab-content grocy-tabs">
|
||||||
<div class="tab-pane fade show active"
|
<div class="tab-pane fade show active" id="instruction-manual-tab">
|
||||||
id="instruction-manual-tab">
|
<div id="selectedEquipmentInstructionManualCard" class="card">
|
||||||
<div id="selectedEquipmentInstructionManualCard"
|
|
||||||
class="card">
|
|
||||||
<div class="card-header card-header-fullscreen">
|
<div class="card-header card-header-fullscreen">
|
||||||
<span class="selected-equipment-name"></span>
|
<span class="selected-equipment-name"></span>
|
||||||
<a id="selectedEquipmentInstructionManualToggleFullscreenButton"
|
<a id="selectedEquipmentInstructionManualToggleFullscreenButton"
|
||||||
class="btn btn-sm btn-outline-secondary py-0 float-right mr-1"
|
class="btn btn-sm btn-outline-secondary py-0 float-right mr-1" href="#"
|
||||||
href="#"
|
data-toggle="tooltip" title="{{ $__t('Expand to fullscreen') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Expand to fullscreen') }}">
|
|
||||||
<i class="fas fa-expand-arrows-alt"></i>
|
<i class="fas fa-expand-arrows-alt"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="selectedEquipmentInstructionManualDownloadButton"
|
<a id="selectedEquipmentInstructionManualDownloadButton"
|
||||||
class="btn btn-sm btn-outline-secondary py-0 float-right mr-1"
|
class="btn btn-sm btn-outline-secondary py-0 float-right mr-1" href="#" target="_blank"
|
||||||
href="#"
|
data-toggle="tooltip" title="{{ $__t('Download file') }}">
|
||||||
target="_blank"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Download file') }}">
|
|
||||||
<i class="fas fa-file-download"></i>
|
<i class="fas fa-file-download"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body py-0 px-0">
|
<div class="card-body py-0 px-0">
|
||||||
<p id="selected-equipment-has-no-instruction-manual-hint"
|
<p id="selected-equipment-has-no-instruction-manual-hint"
|
||||||
class="text-muted font-italic d-none pt-3 pl-3">{{ $__t('The selected equipment has no instruction manual') }}</p>
|
class="text-muted font-italic d-none pt-3 pl-3">
|
||||||
<embed id="selected-equipment-instruction-manual"
|
{{ $__t('The selected equipment has no instruction manual') }}</p>
|
||||||
class="embed-responsive embed-responsive-4by3"
|
<embed id="selected-equipment-instruction-manual" class="embed-responsive embed-responsive-4by3"
|
||||||
src=""
|
src="" type="application/pdf">
|
||||||
type="application/pdf">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane fade"
|
<div class="tab-pane fade" id="description-tab">
|
||||||
id="description-tab">
|
<div id="selectedEquipmentDescriptionCard" class="card">
|
||||||
<div id="selectedEquipmentDescriptionCard"
|
|
||||||
class="card">
|
|
||||||
<div class="card-header card-header-fullscreen">
|
<div class="card-header card-header-fullscreen">
|
||||||
<span class="selected-equipment-name"></span>
|
<span class="selected-equipment-name"></span>
|
||||||
<a id="selectedEquipmentDescriptionToggleFullscreenButton"
|
<a id="selectedEquipmentDescriptionToggleFullscreenButton"
|
||||||
class="btn btn-sm btn-outline-secondary py-0 float-right"
|
class="btn btn-sm btn-outline-secondary py-0 float-right" href="#" data-toggle="tooltip"
|
||||||
href="#"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Expand to fullscreen') }}">
|
title="{{ $__t('Expand to fullscreen') }}">
|
||||||
<i class="fas fa-expand-arrows-alt"></i>
|
<i class="fas fa-expand-arrows-alt"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div id="description-tab-content"
|
<div id="description-tab-content" class="mb-0"></div>
|
||||||
class="mb-0"></div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@
|
||||||
novalidate>
|
novalidate>
|
||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase',
|
||||||
'barcodes' => $barcodes,
|
|
||||||
'nextInputSelector' => '#new_amount'
|
'nextInputSelector' => '#new_amount'
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,10 @@
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
<link href="{{ $U('/node_modules/@fontsource/noto-sans/latin.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/@fontsource/noto-sans/latin.css?v=', true) }}{{ $version }}"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
|
<link href="{{ $U('/node_modules/select2/dist/css/select2.min.css?v=', true) }}{{ $version }}"
|
||||||
|
rel="stylesheet">
|
||||||
|
<link href="{{ $U('/node_modules/select2-theme-bootstrap4/dist/select2-bootstrap.min.css?v=', true) }}{{ $version }}"
|
||||||
|
rel="stylesheet">
|
||||||
<link href="{{ $U('/css/grocy.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/css/grocy.css?v=', true) }}{{ $version }}"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
<link href="{{ $U('/css/grocy_night_mode.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/css/grocy_night_mode.css?v=', true) }}{{ $version }}"
|
||||||
|
|
@ -706,6 +710,7 @@
|
||||||
@if(!empty($__t('bootstrap-select_locale') && $__t('bootstrap-select_locale') != 'x'))<script src="{{ $U('/node_modules', true) }}/bootstrap-select/dist/js/i18n/defaults-{{ $__t('bootstrap-select_locale') }}.js?v={{ $version }}"></script>@endif
|
@if(!empty($__t('bootstrap-select_locale') && $__t('bootstrap-select_locale') != 'x'))<script src="{{ $U('/node_modules', true) }}/bootstrap-select/dist/js/i18n/defaults-{{ $__t('bootstrap-select_locale') }}.js?v={{ $version }}"></script>@endif
|
||||||
<script src="{{ $U('/node_modules/jquery-lazy/jquery.lazy.min.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/node_modules/jquery-lazy/jquery.lazy.min.js?v=', true) }}{{ $version }}"></script>
|
||||||
<script src="{{ $U('/node_modules/nosleep.js/dist/NoSleep.min.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/node_modules/nosleep.js/dist/NoSleep.min.js?v=', true) }}{{ $version }}"></script>
|
||||||
|
<script src="{{ $U('/node_modules/select2/dist/js/select2.min.js?v=', true) }}{{ $version }}"></script>
|
||||||
|
|
||||||
<script src="{{ $U('/js/extensions.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/js/extensions.js?v=', true) }}{{ $version }}"></script>
|
||||||
<script src="{{ $U('/js/grocy.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/js/grocy.js?v=', true) }}{{ $version }}"></script>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
@section('viewJsName', 'locationcontentsheet')
|
@section('viewJsName', 'locationcontentsheet')
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<style>
|
<style>
|
||||||
@media print {
|
@media print {
|
||||||
.page:not(:last-child) {
|
.page:not(:last-child) {
|
||||||
page-break-after: always !important;
|
page-break-after: always !important;
|
||||||
|
|
@ -24,46 +24,39 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="title-related-links d-print-none">
|
<div class="title-related-links d-print-none">
|
||||||
<h2 class="title">
|
<h2 class="title">
|
||||||
@yield('title')
|
@yield('title')
|
||||||
<i class="fas fa-question-circle text-muted small"
|
<i class="fas fa-question-circle text-muted small" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('Here you can print a page per location with the current stock, maybe to hang it there and note the consumed things on it') }}"></i>
|
title="{{ $__t('Here you can print a page per location with the current stock, maybe to hang it there and note the consumed things on it') }}"></i>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button" data-toggle="collapse"
|
||||||
type="button"
|
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
data-target="#related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right print-all-locations-button"
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right print-all-locations-button"
|
||||||
href="#">
|
href="#">
|
||||||
{{ $__t('Print') . ' (' . $__t('all locations') . ')' }}
|
{{ $__t('Print') . ' (' . $__t('all locations') . ')' }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2 d-print-none">
|
<hr class="my-2 d-print-none">
|
||||||
|
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<h1 class="pt-4 text-center">
|
<h1 class="pt-4 text-center">
|
||||||
<img src="{{ $U('/img/grocy_logo.svg?v=', true) }}{{ $version }}"
|
<img src="{{ $U('/img/grocy_logo.svg?v=', true) }}{{ $version }}" height="30"
|
||||||
height="30"
|
|
||||||
class="d-none d-print-flex mx-auto">
|
class="d-none d-print-flex mx-auto">
|
||||||
{{ $location->name }}
|
{{ $location->name }}
|
||||||
<a class="btn btn-outline-dark btn-sm responsive-button print-single-location-button d-print-none"
|
<a class="btn btn-outline-dark btn-sm responsive-button print-single-location-button d-print-none" href="#">
|
||||||
href="#">
|
|
||||||
{{ $__t('Print') . ' (' . $__t('this location') . ')' }}
|
{{ $__t('Print') . ' (' . $__t('this location') . ')' }}
|
||||||
</a>
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
@ -73,6 +66,7 @@
|
||||||
</h6>
|
</h6>
|
||||||
<div class="row w-75">
|
<div class="row w-75">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
{{-- TODO: DataTables: dynamic data: stock --}}
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
@ -83,14 +77,21 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@php $currentStockEntriesForLocation = FindAllObjectsInArrayByPropertyValue($currentStockLocationContent, 'location_id', $location->id); @endphp
|
@php $currentStockEntriesForLocation = FindAllObjectsInArrayByPropertyValue($currentStockLocationContent, 'location_id', $location->id); @endphp
|
||||||
@foreach($currentStockEntriesForLocation as $currentStockEntry)
|
@foreach ($currentStockEntriesForLocation as $currentStockEntry)
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__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) }}</span>
|
<span
|
||||||
<span class="small font-italic">@if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif</span>
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span>
|
||||||
|
<span
|
||||||
|
id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__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) }}</span>
|
||||||
|
<span class="small font-italic">
|
||||||
|
@if ($currentStockEntry->amount_opened > 0)
|
||||||
|
{{ $__t('%s opened', $currentStockEntry->amount_opened) }}
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class=""></td>
|
<td class=""></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -99,6 +100,6 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'locations')
|
@section('viewJsName', 'locations')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
href="{{ $U('/location/new?embedded') }}">
|
href="{{ $U('/location/new?embedded') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -36,72 +31,59 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="locations-table"
|
{{-- TODO: DataTables: dynamic data: locations --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="locations-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#locations-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#locations-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Description') }}</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/location/') }}{{ $location->id }}?embedded"
|
href="{{ $U('/location/') }}{{ $location->id }}?embedded" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm location-delete-button"
|
<a class="btn btn-danger btn-sm location-delete-button" href="#"
|
||||||
href="#"
|
data-location-id="{{ $location->id }}" data-location-name="{{ $location->name }}"
|
||||||
data-location-id="{{ $location->id }}"
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
data-location-name="{{ $location->name }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -112,15 +94,19 @@
|
||||||
{{ $location->description }}
|
{{ $location->description }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $location->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$location->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,35 +5,29 @@
|
||||||
@section('viewJsName', 'manageapikeys')
|
@section('viewJsName', 'manageapikeys')
|
||||||
|
|
||||||
@push('pageScripts')
|
@push('pageScripts')
|
||||||
<script src="{{ $U('/node_modules/bwip-js/dist/bwip-js-min.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/node_modules/bwip-js/dist/bwip-js-min.js?v=', true) }}{{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}" rel="stylesheet">
|
||||||
rel="stylesheet">
|
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/manageapikeys/new') }}">
|
href="{{ $U('/manageapikeys/new') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -41,46 +35,37 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="apikeys-table"
|
{{-- TODO: DataTables: dynamic data: API keys --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="apikeys-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#apikeys-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#apikeys-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('API key') }}</th>
|
<th>{{ $__t('API key') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('User') }}</th>
|
<th class="allow-grouping">{{ $__t('User') }}</th>
|
||||||
|
|
@ -91,22 +76,17 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($apiKeys as $apiKey)
|
@foreach ($apiKeys as $apiKey)
|
||||||
<tr id="apiKeyRow_{{ $apiKey->id }}">
|
<tr id="apiKeyRow_{{ $apiKey->id }}">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-danger btn-sm apikey-delete-button"
|
<a class="btn btn-danger btn-sm apikey-delete-button" href="#"
|
||||||
href="#"
|
data-apikey-id="{{ $apiKey->id }}" data-apikey-apikey="{{ $apiKey->api_key }}"
|
||||||
data-apikey-id="{{ $apiKey->id }}"
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
data-apikey-apikey="{{ $apiKey->api_key }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-info btn-sm apikey-show-qr-button"
|
<a class="btn btn-info btn-sm apikey-show-qr-button" href="#"
|
||||||
href="#"
|
|
||||||
data-apikey-key="{{ $apiKey->api_key }}"
|
data-apikey-key="{{ $apiKey->api_key }}"
|
||||||
data-apikey-type="{{ $apiKey->key_type }}"
|
data-apikey-type="{{ $apiKey->key_type }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Show a QR-Code for this API key') }}">
|
title="{{ $__t('Show a QR-Code for this API key') }}">
|
||||||
<i class="fas fa-qrcode"></i>
|
<i class="fas fa-qrcode"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -119,13 +99,13 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $apiKey->expires }}
|
{{ $apiKey->expires }}
|
||||||
<time class="timeago timeago-contextual"
|
<time class="timeago timeago-contextual" datetime="{{ $apiKey->expires }}"></time>
|
||||||
datetime="{{ $apiKey->expires }}"></time>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if(empty($apiKey->last_used)){{ $__t('never') }}@else{{ $apiKey->last_used }}@endif
|
@if (empty($apiKey->last_used))
|
||||||
<time class="timeago timeago-contextual"
|
{{ $__t('never') }}@else{{ $apiKey->last_used }}
|
||||||
datetime="{{ $apiKey->last_used }}"></time>
|
@endif
|
||||||
|
<time class="timeago timeago-contextual" datetime="{{ $apiKey->last_used }}"></time>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $apiKey->row_created_timestamp }}
|
{{ $apiKey->row_created_timestamp }}
|
||||||
|
|
@ -140,5 +120,5 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,19 @@
|
||||||
@section('viewJsName', 'mealplan')
|
@section('viewJsName', 'mealplan')
|
||||||
|
|
||||||
@push('pageScripts')
|
@push('pageScripts')
|
||||||
<script src="{{ $U('/node_modules/fullcalendar/dist/fullcalendar.min.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/node_modules/fullcalendar/dist/fullcalendar.min.js?v=', true) }}{{ $version }}"></script>
|
||||||
@if(!empty($__t('fullcalendar_locale') && $__t('fullcalendar_locale') != 'x'))<script src="{{ $U('/node_modules', true) }}/fullcalendar/dist/locale/{{ $__t('fullcalendar_locale') }}.js?v={{ $version }}"></script>@endif
|
@if (!empty($__t('fullcalendar_locale') && $__t('fullcalendar_locale') != 'x'))
|
||||||
|
<script
|
||||||
|
src="{{ $U('/node_modules', true) }}/fullcalendar/dist/locale/{{ $__t('fullcalendar_locale') }}.js?v={{ $version }}">
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/fullcalendar/dist/fullcalendar.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/fullcalendar/dist/fullcalendar.min.css?v=', true) }}{{ $version }}"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.fc-event-container {
|
.fc-event-container {
|
||||||
border-bottom: 1px solid !important;
|
border-bottom: 1px solid !important;
|
||||||
border-color: #d6d6d6 !important;
|
border-color: #d6d6d6 !important;
|
||||||
|
|
@ -71,12 +75,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<script>
|
<script>
|
||||||
var fullcalendarEventSources = {!! json_encode(array($fullcalendarEventSources)) !!}
|
var fullcalendarEventSources = {!! json_encode([$fullcalendarEventSources]) !!}
|
||||||
var internalRecipes = {!! json_encode($internalRecipes) !!}
|
var internalRecipes = {!! json_encode($internalRecipes) !!}
|
||||||
var recipesResolved = {!! json_encode($recipesResolved) !!}
|
var recipesResolved = {!! json_encode($recipesResolved) !!}
|
||||||
|
|
||||||
|
|
@ -84,24 +88,20 @@
|
||||||
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
||||||
|
|
||||||
Grocy.MealPlanFirstDayOfWeek = '{{ GROCY_MEAL_PLAN_FIRST_DAY_OF_WEEK }}';
|
Grocy.MealPlanFirstDayOfWeek = '{{ GROCY_MEAL_PLAN_FIRST_DAY_OF_WEEK }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right d-print-none">
|
<div class="float-right d-print-none">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 d-print-none"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 d-print-none" id="related-links">
|
||||||
id="related-links">
|
<a id="print-meal-plan-button" class="btn btn-outline-dark m-1 mt-md-0 mb-md-0 float-right">
|
||||||
<a id="print-meal-plan-button"
|
|
||||||
class="btn btn-outline-dark m-1 mt-md-0 mb-md-0 float-right">
|
|
||||||
{{ $__t('Print') }}
|
{{ $__t('Print') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
||||||
|
|
@ -111,220 +111,173 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
@foreach($usedMealplanSections as $mealplanSection)
|
@foreach ($usedMealplanSections as $mealplanSection)
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="calendar"
|
<div class="calendar" data-section-id="{{ $mealplanSection->id }}"
|
||||||
data-section-id="{{ $mealplanSection->id }}"
|
|
||||||
data-section-name="{{ $mealplanSection->name }}<br><span class='small text-muted'>{{ $mealplanSection->time_info }}</span>"
|
data-section-name="{{ $mealplanSection->name }}<br><span class='small text-muted'>{{ $mealplanSection->time_info }}</span>"
|
||||||
data-primary-section="{{ BoolToString($loop->first) }}"
|
data-primary-section="{{ BoolToString($loop->first) }}" {{-- $loop->last doesn't work however, is always null... --}}
|
||||||
{{--
|
|
||||||
$loop->last doesn't work however, is always null...
|
|
||||||
--}}
|
|
||||||
data-last-section="{{ BoolToString(array_values(array_slice($usedMealplanSections->fetchAll(), -1))[0]->id == $mealplanSection->id) }}">
|
data-last-section="{{ BoolToString(array_values(array_slice($usedMealplanSections->fetchAll(), -1))[0]->id == $mealplanSection->id) }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
{{-- Default empty calendar/section when no single meal plan entry is in the given date range --}}
|
{{-- Default empty calendar/section when no single meal plan entry is in the given date range --}}
|
||||||
@if($usedMealplanSections->count() === 0)
|
@if ($usedMealplanSections->count() === 0)
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="calendar"
|
<div class="calendar" data-section-id="-1" data-section-name="" data-primary-section="true"
|
||||||
data-section-id="-1"
|
|
||||||
data-section-name=""
|
|
||||||
data-primary-section="true"
|
|
||||||
data-last-section="true">
|
data-last-section="true">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="add-recipe-modal" tabindex="-1">
|
||||||
id="add-recipe-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 id="add-recipe-modal-title"
|
<h4 id="add-recipe-modal-title" class="modal-title w-100"></h4>
|
||||||
class="modal-title w-100"></h4>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="add-recipe-form"
|
<form id="add-recipe-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@include('components.recipepicker', array(
|
@include('components.recipepicker', [
|
||||||
'recipes' => $recipes,
|
'recipes' => $recipes,
|
||||||
'isRequired' => true,
|
'isRequired' => true,
|
||||||
'nextInputSelector' => '#recipe_servings'
|
'nextInputSelector' => '#recipe_servings',
|
||||||
))
|
])
|
||||||
|
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'recipe_servings',
|
'id' => 'recipe_servings',
|
||||||
'label' => 'Servings',
|
'label' => 'Servings',
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
'value' => '1',
|
'value' => '1',
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="period_type">{{ $__t('Section') }}</label>
|
<label for="period_type">{{ $__t('Section') }}</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: meal_plan_sections --}}
|
||||||
id="section_id_recipe"
|
<select class="custom-control custom-select" id="section_id_recipe" name="section_id_recipe"
|
||||||
name="section_id_recipe"
|
|
||||||
required>
|
required>
|
||||||
@foreach($mealplanSections as $mealplanSection)
|
@foreach ($mealplanSections as $mealplanSection)
|
||||||
<option value="{{ $mealplanSection->id }}">{{ $mealplanSection->name }}</option>
|
<option value="{{ $mealplanSection->id }}">{{ $mealplanSection->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="hidden"
|
<input type="hidden" id="day" name="day" value="">
|
||||||
id="day"
|
<input type="hidden" name="type" value="recipe">
|
||||||
name="day"
|
|
||||||
value="">
|
|
||||||
<input type="hidden"
|
|
||||||
name="type"
|
|
||||||
value="recipe">
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
class="btn btn-secondary"
|
<button id="save-add-recipe-button" data-dismiss="modal"
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
|
||||||
<button id="save-add-recipe-button"
|
|
||||||
data-dismiss="modal"
|
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="add-note-modal" tabindex="-1">
|
||||||
id="add-note-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 id="add-note-modal-title"
|
<h4 id="add-note-modal-title" class="modal-title w-100"></h4>
|
||||||
class="modal-title w-100"></h4>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="add-note-form"
|
<form id="add-note-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="note">{{ $__t('Note') }}</label>
|
<label for="note">{{ $__t('Note') }}</label>
|
||||||
<textarea class="form-control"
|
<textarea class="form-control" rows="2" id="note" name="note"></textarea>
|
||||||
rows="2"
|
|
||||||
id="note"
|
|
||||||
name="note"></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="period_type">{{ $__t('Section') }}</label>
|
<label for="period_type">{{ $__t('Section') }}</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: meal_plan_sections --}}
|
||||||
id="section_id_note"
|
<select class="custom-control custom-select" id="section_id_note" name="section_id_note"
|
||||||
name="section_id_note"
|
|
||||||
required>
|
required>
|
||||||
@foreach($mealplanSections as $mealplanSection)
|
@foreach ($mealplanSections as $mealplanSection)
|
||||||
<option value="{{ $mealplanSection->id }}">{{ $mealplanSection->name }}</option>
|
<option value="{{ $mealplanSection->id }}">{{ $mealplanSection->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="hidden"
|
<input type="hidden" name="type" value="note">
|
||||||
name="type"
|
|
||||||
value="note">
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
class="btn btn-secondary"
|
<button id="save-add-note-button" data-dismiss="modal"
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
|
||||||
<button id="save-add-note-button"
|
|
||||||
data-dismiss="modal"
|
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="add-product-modal" tabindex="-1">
|
||||||
id="add-product-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 id="add-product-modal-title"
|
<h4 id="add-product-modal-title" class="modal-title w-100"></h4>
|
||||||
class="modal-title w-100"></h4>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="add-product-form"
|
<form id="add-product-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', [
|
||||||
'products' => $products,
|
'productsQuery' => 'order=name%3Acollate%20nocase',
|
||||||
'nextInputSelector' => '#amount'
|
'nextInputSelector' => '#amount',
|
||||||
))
|
])
|
||||||
|
|
||||||
@include('components.productamountpicker', array(
|
@include('components.productamountpicker', [
|
||||||
'value' => 1,
|
'value' => 1,
|
||||||
'additionalGroupCssClasses' => 'mb-0'
|
'additionalGroupCssClasses' => 'mb-0',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="period_type">{{ $__t('Section') }}</label>
|
<label for="period_type">{{ $__t('Section') }}</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: meal_plan_sections --}}
|
||||||
id="section_id_product"
|
<select class="custom-control custom-select" id="section_id_product" name="section_id_product"
|
||||||
name="section_id_product"
|
|
||||||
required>
|
required>
|
||||||
@foreach($mealplanSections as $mealplanSection)
|
@foreach ($mealplanSections as $mealplanSection)
|
||||||
<option value="{{ $mealplanSection->id }}">{{ $mealplanSection->name }}</option>
|
<option value="{{ $mealplanSection->id }}">{{ $mealplanSection->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="hidden"
|
<input type="hidden" name="type" value="product">
|
||||||
name="type"
|
|
||||||
value="product">
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
class="btn btn-secondary"
|
<button id="save-add-product-button" data-dismiss="modal"
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
|
||||||
<button id="save-add-product-button"
|
|
||||||
data-dismiss="modal"
|
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="copy-day-modal" tabindex="-1">
|
||||||
id="copy-day-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 id="copy-day-modal-title"
|
<h4 id="copy-day-modal-title" class="modal-title w-100"></h4>
|
||||||
class="modal-title w-100"></h4>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="copy-day-form"
|
<form id="copy-day-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@include('components.datetimepicker', array(
|
@include('components.datetimepicker', [
|
||||||
'id' => 'copy_to_date',
|
'id' => 'copy_to_date',
|
||||||
'label' => 'Day',
|
'label' => 'Day',
|
||||||
'format' => 'YYYY-MM-DD',
|
'format' => 'YYYY-MM-DD',
|
||||||
|
|
@ -333,37 +286,30 @@
|
||||||
'limitStartToNow' => false,
|
'limitStartToNow' => false,
|
||||||
'isRequired' => true,
|
'isRequired' => true,
|
||||||
'additionalCssClasses' => 'date-only-datetimepicker',
|
'additionalCssClasses' => 'date-only-datetimepicker',
|
||||||
'invalidFeedback' => $__t('A date is required')
|
'invalidFeedback' => $__t('A date is required'),
|
||||||
))
|
])
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
class="btn btn-secondary"
|
<button id="save-copy-day-button" data-dismiss="modal"
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
|
||||||
<button id="save-copy-day-button"
|
|
||||||
data-dismiss="modal"
|
|
||||||
class="btn btn-primary">{{ $__t('Copy') }}</button>
|
class="btn btn-primary">{{ $__t('Copy') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="mealplan-productcard-modal" tabindex="-1">
|
||||||
id="mealplan-productcard-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@include('components.productcard')
|
@include('components.productcard')
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'mealplansections')
|
@section('viewJsName', 'mealplansections')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
href="{{ $U('/mealplansection/new?embedded') }}">
|
href="{{ $U('/mealplansection/new?embedded') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -32,46 +27,37 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="mealplansections-table"
|
{{-- TODO: DataTables: dynamic data: meal_plan_sections --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="mealplansections-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#mealplansections-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#mealplansections-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Sort number') }}</th>
|
<th>{{ $__t('Sort number') }}</th>
|
||||||
|
|
@ -79,20 +65,17 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($mealplanSections as $mealplanSection)
|
@foreach ($mealplanSections as $mealplanSection)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/mealplansection/') }}{{ $mealplanSection->id }}?embedded"
|
href="{{ $U('/mealplansection/') }}{{ $mealplanSection->id }}?embedded"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm mealplansection-delete-button"
|
<a class="btn btn-danger btn-sm mealplansection-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-mealplansection-id="{{ $mealplanSection->id }}"
|
data-mealplansection-id="{{ $mealplanSection->id }}"
|
||||||
data-mealplansection-name="{{ $mealplanSection->name }}"
|
data-mealplansection-name="{{ $mealplanSection->name }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -111,5 +94,5 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,34 @@
|
||||||
@extends('layout.default')
|
@extends('layout.default')
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
@section('title', $__t('Edit Barcode'))
|
@section('title', $__t('Edit Barcode'))
|
||||||
@else
|
@else
|
||||||
@section('title', $__t('Create Barcode'))
|
@section('title', $__t('Create Barcode'))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@section('viewJsName', 'productbarcodeform')
|
@section('viewJsName', 'productbarcodeform')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<script>
|
<script>
|
||||||
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
||||||
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<h2>
|
<h2>
|
||||||
<span class="text-muted small">{{ $__t('Barcode for product') }} <strong>{{ $product->name }}</strong></span>
|
<span class="text-muted small">{{ $__t('Barcode for product') }}
|
||||||
|
<strong>{{ $product->name }}</strong></span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-12">
|
<div class="col-lg-6 col-12">
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -35,79 +36,69 @@
|
||||||
Grocy.EditObjectProduct = {!! json_encode($product) !!};
|
Grocy.EditObjectProduct = {!! json_encode($product) !!};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditObjectId = {{ $barcode->id }};
|
Grocy.EditObjectId = {{ $barcode->id }};
|
||||||
Grocy.EditObject = {!! json_encode($barcode) !!};
|
Grocy.EditObject = {!! json_encode($barcode) !!};
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form id="barcode-form"
|
<form id="barcode-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<input type="hidden"
|
<input type="hidden" name="product_id" value="{{ $product->id }}">
|
||||||
name="product_id"
|
|
||||||
value="{{ $product->id }}">
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">{{ $__t('Barcode') }} <i class="fas fa-barcode"></i></label>
|
<label for="name">{{ $__t('Barcode') }} <i class="fas fa-barcode"></i></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text"
|
<input type="text" class="form-control barcodescanner-input" required id="barcode" name="barcode"
|
||||||
class="form-control barcodescanner-input"
|
value="@if ($mode == 'edit') {{ $barcode->barcode }} @endif"
|
||||||
required
|
|
||||||
id="barcode"
|
|
||||||
name="barcode"
|
|
||||||
value="@if($mode == 'edit'){{ $barcode->barcode }}@endif"
|
|
||||||
data-target="#barcode">
|
data-target="#barcode">
|
||||||
@include('components.barcodescanner')
|
@include('components.barcodescanner')
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $barcode->amount; } else { $value = ''; } @endphp
|
@php
|
||||||
@include('components.productamountpicker', array(
|
if ($mode == 'edit') {
|
||||||
|
$value = $barcode->amount;
|
||||||
|
} else {
|
||||||
|
$value = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('components.productamountpicker', [
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'isRequired' => false
|
'isRequired' => false,
|
||||||
))
|
])
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="shopping_location_id_id">{{ $__t('Store') }}</label>
|
<label for="shopping_location_id_id">{{ $__t('Store') }}</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: shopping_locations --}}
|
||||||
id="shopping_location_id"
|
<select class="custom-control custom-select" id="shopping_location_id" name="shopping_location_id">
|
||||||
name="shopping_location_id">
|
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($shoppinglocations as $store)
|
@foreach ($shoppinglocations as $store)
|
||||||
<option @if($mode=='edit'
|
<option @if ($mode == 'edit' && $store->id == $barcode->shopping_location_id) selected="selected" @endif
|
||||||
&&
|
value="{{ $store->id }}">{{ $store->name }}</option>
|
||||||
$store->id == $barcode->shopping_location_id) selected="selected" @endif value="{{ $store->id }}">{{ $store->name }}</option>
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<input type="hidden"
|
<input type="hidden" name="shopping_location_id" id="shopping_location_id" value="1">
|
||||||
name="shopping_location_id"
|
|
||||||
id="shopping_location_id"
|
|
||||||
value="1">
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="note">{{ $__t('Note') }}</label>
|
<label for="note">{{ $__t('Note') }}</label>
|
||||||
<input type="text"
|
<input type="text" class="form-control" id="note" name="note"
|
||||||
class="form-control"
|
value="@if ($mode == 'edit') {{ $barcode->note }} @endif">
|
||||||
id="note"
|
|
||||||
name="note"
|
|
||||||
value="@if($mode == 'edit'){{ $barcode->note }}@endif">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@include('components.userfieldsform', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'entity' => 'product_barcodes'
|
'entity' => 'product_barcodes',
|
||||||
))
|
])
|
||||||
|
|
||||||
<button id="save-barcode-button"
|
<button id="save-barcode-button" class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'productgroups')
|
@section('viewJsName', 'productgroups')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button show-as-dialog-link m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-primary responsive-button show-as-dialog-link m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/productgroup/new?embedded') }}">
|
href="{{ $U('/productgroup/new?embedded') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -36,71 +31,59 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="productgroups-table"
|
{{-- TODO: DataTables: dynamic data: product_groups --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="productgroups-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#productgroups-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#productgroups-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Description') }}</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
<th>{{ $__t('Product count') }}</th>
|
<th>{{ $__t('Product count') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($productGroups as $productGroup)
|
@foreach ($productGroups as $productGroup)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/productgroup/') }}{{ $productGroup->id }}?embedded"
|
href="{{ $U('/productgroup/') }}{{ $productGroup->id }}?embedded"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm product-group-delete-button"
|
<a class="btn btn-danger btn-sm product-group-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-group-id="{{ $productGroup->id }}"
|
data-group-id="{{ $productGroup->id }}"
|
||||||
data-group-name="{{ $productGroup->name }}"
|
data-group-name="{{ $productGroup->name }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -119,15 +102,19 @@
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $productGroup->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$productGroup->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'products')
|
@section('viewJsName', 'products')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/product/new') }}">
|
href="{{ $U('/product/new') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -40,21 +35,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex mb-3" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -62,10 +53,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product group') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product group') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: product_groups --}}
|
||||||
id="product-group-filter">
|
<select class="custom-control custom-select" id="product-group-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($productGroups as $productGroup)
|
@foreach ($productGroups as $productGroup)
|
||||||
<option value="{{ $productGroup->id }}">{{ $productGroup->name }}</option>
|
<option value="{{ $productGroup->id }}">{{ $productGroup->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -73,155 +64,58 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-2">
|
<div class="col-12 col-md-6 col-xl-2">
|
||||||
<div class="form-check custom-control custom-checkbox">
|
<div class="form-check custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-disabled">
|
||||||
type="checkbox"
|
<label class="form-check-label custom-control-label" for="show-disabled">
|
||||||
id="show-disabled">
|
|
||||||
<label class="form-check-label custom-control-label"
|
|
||||||
for="show-disabled">
|
|
||||||
{{ $__t('Show disabled') }}
|
{{ $__t('Show disabled') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-2">
|
<div class="col-12 col-md-6 col-xl-2">
|
||||||
<div class="form-check custom-control custom-checkbox">
|
<div class="form-check custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-only-in-stock">
|
||||||
type="checkbox"
|
<label class="form-check-label custom-control-label" for="show-only-in-stock">
|
||||||
id="show-only-in-stock">
|
|
||||||
<label class="form-check-label custom-control-label"
|
|
||||||
for="show-only-in-stock">
|
|
||||||
{{ $__t('Show only in-stock products') }}
|
{{ $__t('Show only in-stock products') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="products-table"
|
<table id="products-table" class="table table-sm table-striped nowrap w-100">
|
||||||
class="table table-sm table-striped nowrap w-100">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#products-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#products-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}
|
||||||
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Min. stock amount') }}</th>
|
<th class="allow-grouping">{{ $__t('Min. stock amount') }}</th>
|
||||||
<th class="">{{ $__t('Default quantity unit purchase') }}</th>
|
<th class="">{{ $__t('Default quantity unit purchase') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Quantity unit stock') }}</th>
|
<th class="allow-grouping">{{ $__t('Quantity unit stock') }}</th>
|
||||||
<th class="">{{ $__t('Product group') }}</th>
|
<th class="">{{ $__t('Product group') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">{{ $__t('Default store') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">
|
||||||
|
{{ $__t('Default store') }}</th>
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody></tbody>
|
||||||
@foreach($products as $product)
|
|
||||||
<tr class="@if($product->active == 0) text-muted @endif">
|
|
||||||
<td class="fit-content border-right">
|
|
||||||
<a class="btn btn-info btn-sm"
|
|
||||||
href="{{ $U('/product/') }}{{ $product->id }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
|
||||||
</a>
|
|
||||||
<a class="btn btn-danger btn-sm product-delete-button"
|
|
||||||
href="#"
|
|
||||||
data-product-id="{{ $product->id }}"
|
|
||||||
data-product-name="{{ $product->name }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</a>
|
|
||||||
<div class="dropdown d-inline-block">
|
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
|
||||||
</button>
|
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
|
||||||
<a class="dropdown-item"
|
|
||||||
type="button"
|
|
||||||
href="{{ $U('/product/new?copy-of=') }}{{ $product->id }}">
|
|
||||||
<span class="dropdown-item-text">{{ $__t('Copy') }}</span>
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-item merge-products-button"
|
|
||||||
data-product-id="{{ $product->id }}"
|
|
||||||
type="button"
|
|
||||||
href="#">
|
|
||||||
<span class="dropdown-item-text">{{ $__t('Merge') }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ $product->name }}
|
|
||||||
@if(!empty($product->picture_file_name))
|
|
||||||
<i class="fas fa-image text-muted"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('This product has a picture') }}"></i>
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
|
||||||
@php
|
|
||||||
$location = FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id);
|
|
||||||
@endphp
|
|
||||||
@if($location != null)
|
|
||||||
{{ $location->name }}
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $product->min_stock_amount }}</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_purchase)->name }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_stock)->name }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
@if(!empty($product->product_group_id)) {{ FindObjectInArrayByPropertyValue($productGroups, 'id', $product->product_group_id)->name }} @endif
|
|
||||||
</td>
|
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
|
||||||
@php
|
|
||||||
$store = FindObjectInArrayByPropertyValue($shoppingLocations, 'id', $product->shopping_location_id);
|
|
||||||
@endphp
|
|
||||||
@if($store != null)
|
|
||||||
{{ $store->name }}
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
|
||||||
'userfields' => $userfields,
|
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $product->id)
|
|
||||||
))
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="merge-products-modal" tabindex="-1">
|
||||||
id="merge-products-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
@ -229,44 +123,30 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="merge-products-keep">{{ $__t('Product to keep') }} <i class="fas fa-question-circle text-muted"
|
<label for="merge-products-keep">{{ $__t('Product to keep') }} <i
|
||||||
data-toggle="tooltip"
|
class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('After merging, this product will be kept') }}"></i>
|
title="{{ $__t('After merging, this product will be kept') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
<select class="custom-control custom-select"
|
<select class="select2 custom-control custom-select" id="merge-products-keep"></select>
|
||||||
id="merge-products-keep">
|
|
||||||
<option></option>
|
|
||||||
@foreach($products as $product)
|
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="merge-products-remove">{{ $__t('Product to remove') }} <i class="fas fa-question-circle text-muted"
|
<label for="merge-products-remove">{{ $__t('Product to remove') }} <i
|
||||||
data-toggle="tooltip"
|
class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('After merging, all occurences of this product will be replaced by "Product to keep" (means this product will not exist anymore)') }}"></i>
|
title="{{ $__t('After merging, all occurences of this product will be replaced by "Product to keep" (means this product will not exist anymore)') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
<select class="custom-control custom-select"
|
<select class="select2 custom-control custom-select" id="merge-products-remove"></select>
|
||||||
id="merge-products-remove">
|
|
||||||
<option></option>
|
|
||||||
@foreach($products as $product)
|
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
class="btn btn-secondary"
|
<button id="merge-products-save-button" type="button" class="btn btn-primary"
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
|
||||||
<button id="merge-products-save-button"
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary"
|
|
||||||
data-dismiss="modal">{{ $__t('OK') }}</button>
|
data-dismiss="modal">{{ $__t('OK') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var userfields = {!! json_encode($userfields) !!};
|
||||||
|
</script>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,7 @@
|
||||||
novalidate>
|
novalidate>
|
||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase',
|
||||||
'barcodes' => $barcodes,
|
|
||||||
'nextInputSelector' => '#display_amount'
|
'nextInputSelector' => '#display_amount'
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,61 @@
|
||||||
@extends('layout.default')
|
@extends('layout.default')
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
@section('title', $__t('Edit QU conversion'))
|
@section('title', $__t('Edit QU conversion'))
|
||||||
@else
|
@else
|
||||||
@section('title', $__t('Create QU conversion'))
|
@section('title', $__t('Create QU conversion'))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@section('viewJsName', 'quantityunitconversionform')
|
@section('viewJsName', 'quantityunitconversionform')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<h2>
|
<h2>
|
||||||
@if($product != null)
|
@if ($product != null)
|
||||||
<span class="text-muted small">{{ $__t('Override for product') }} <strong>{{ $product->name }}</strong></span>
|
<span class="text-muted small">{{ $__t('Override for product') }}
|
||||||
|
<strong>{{ $product->name }}</strong></span>
|
||||||
@else
|
@else
|
||||||
<span class="text-muted small">{{ $__t('Default for QU') }} <strong>{{ $defaultQuUnit->name }}</strong></span>
|
<span class="text-muted small">{{ $__t('Default for QU') }}
|
||||||
|
<strong>{{ $defaultQuUnit->name }}</strong></span>
|
||||||
@endif
|
@endif
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-12">
|
<div class="col-lg-6 col-12">
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditMode = '{{ $mode }}';
|
Grocy.EditMode = '{{ $mode }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditObjectId = {{ $quConversion->id }};
|
Grocy.EditObjectId = {{ $quConversion->id }};
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form id="quconversion-form"
|
<form id="quconversion-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@if($product != null)
|
@if ($product != null)
|
||||||
<input type="hidden"
|
<input type="hidden" name="product_id" value="{{ $product->id }}">
|
||||||
name="product_id"
|
|
||||||
value="{{ $product->id }}">
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="from_qu_id">{{ $__t('Quantity unit from') }}</label>
|
<label for="from_qu_id">{{ $__t('Quantity unit from') }}</label>
|
||||||
<select required
|
{{-- TODO: Select2: dynamic data: quantity_units --}}
|
||||||
class="custom-control custom-select input-group-qu"
|
<select required class="custom-control custom-select input-group-qu" id="from_qu_id" name="from_qu_id">
|
||||||
id="from_qu_id"
|
|
||||||
name="from_qu_id">
|
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($quantityunits as $quantityunit)
|
@foreach ($quantityunits as $quantityunit)
|
||||||
<option @if(($product
|
<option @if (($product != null && $quantityunit->id == $product->qu_id_stock) || ($defaultQuUnit != null && $quantityunit->id == $defaultQuUnit->id)) ) selected="selected" @endif
|
||||||
!=null
|
value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">
|
||||||
&&
|
{{ $quantityunit->name }}</option>
|
||||||
$quantityunit->id == $product->qu_id_stock) || ($defaultQuUnit != null && $quantityunit->id == $defaultQuUnit->id))) selected="selected" @endif value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">{{ $quantityunit->name }}</option>
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
||||||
|
|
@ -67,22 +63,26 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="to_qu_id">{{ $__t('Quantity unit to') }}</label>
|
<label for="to_qu_id">{{ $__t('Quantity unit to') }}</label>
|
||||||
<select required
|
{{-- TODO: Select2: dynamic data: quantity_units --}}
|
||||||
class="custom-control custom-select input-group-qu"
|
<select required class="custom-control custom-select input-group-qu" id="to_qu_id" name="to_qu_id">
|
||||||
id="to_qu_id"
|
|
||||||
name="to_qu_id">
|
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($quantityunits as $quantityunit)
|
@foreach ($quantityunits as $quantityunit)
|
||||||
<option @if($mode=='edit'
|
<option @if ($mode == 'edit' && $quantityunit->id == $quConversion->to_qu_id) selected="selected" @endif
|
||||||
&&
|
value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">
|
||||||
$quantityunit->id == $quConversion->to_qu_id) selected="selected" @endif value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">{{ $quantityunit->name }}</option>
|
{{ $quantityunit->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $quConversion->factor; } else { $value = 1; } @endphp
|
@php
|
||||||
@include('components.numberpicker', array(
|
if ($mode == 'edit') {
|
||||||
|
$value = $quConversion->factor;
|
||||||
|
} else {
|
||||||
|
$value = 1;
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('components.numberpicker', [
|
||||||
'id' => 'factor',
|
'id' => 'factor',
|
||||||
'label' => 'Factor',
|
'label' => 'Factor',
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
|
|
@ -90,33 +90,27 @@
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'additionalHtmlElements' => '<p id="qu-conversion-info"
|
'additionalHtmlElements' => '<p id="qu-conversion-info"
|
||||||
class="form-text text-info d-none"></p>',
|
class="form-text text-info d-none"></p>',
|
||||||
'additionalCssClasses' => 'input-group-qu locale-number-input locale-number-quantity-amount'
|
'additionalCssClasses' => 'input-group-qu locale-number-input locale-number-quantity-amount',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group @if($mode == 'edit') d-none @endif">
|
<div class="form-group @if ($mode == 'edit') d-none @endif">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input checked
|
<input checked class="form-check-input custom-control-input" type="checkbox" id="create_inverse"
|
||||||
class="form-check-input custom-control-input"
|
name="create_inverse:skip" value="1">
|
||||||
type="checkbox"
|
|
||||||
id="create_inverse"
|
|
||||||
name="create_inverse:skip"
|
|
||||||
value="1">
|
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
for="create_inverse">{{ $__t('Create inverse QU conversion') }}</label>
|
for="create_inverse">{{ $__t('Create inverse QU conversion') }}</label>
|
||||||
</div>
|
</div>
|
||||||
<span id="qu-conversion-inverse-info"
|
<span id="qu-conversion-inverse-info" class="form-text text-info d-none"></span>
|
||||||
class="form-text text-info d-none"></span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@include('components.userfieldsform', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'entity' => 'quantity_unit_conversions'
|
'entity' => 'quantity_unit_conversions',
|
||||||
))
|
])
|
||||||
|
|
||||||
<button id="save-quconversion-button"
|
<button id="save-quconversion-button" class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,52 @@
|
||||||
@extends('layout.default')
|
@extends('layout.default')
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
@section('title', $__t('Edit quantity unit'))
|
@section('title', $__t('Edit quantity unit'))
|
||||||
@else
|
@else
|
||||||
@section('title', $__t('Create quantity unit'))
|
@section('title', $__t('Create quantity unit'))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@section('viewJsName', 'quantityunitform')
|
@section('viewJsName', 'quantityunitform')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-12">
|
<div class="col-lg-6 col-12">
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditMode = '{{ $mode }}';
|
Grocy.EditMode = '{{ $mode }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditObjectId = {{ $quantityUnit->id }};
|
Grocy.EditObjectId = {{ $quantityUnit->id }};
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form id="quantityunit-form"
|
<form id="quantityunit-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">{{ $__t('Name') }} <span class="small text-muted">{{ $__t('in singular form') }}</span></label>
|
<label for="name">{{ $__t('Name') }} <span
|
||||||
<input type="text"
|
class="small text-muted">{{ $__t('in singular form') }}</span></label>
|
||||||
class="form-control"
|
<input type="text" class="form-control" required id="name" name="name"
|
||||||
required
|
value="@if ($mode == 'edit') {{ $quantityUnit->name }} @endif">
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
value="@if($mode == 'edit'){{ $quantityUnit->name }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name_plural">{{ $__t('Name') }} <span class="small text-muted">{{ $__t('in plural form') }}</span></label>
|
<label for="name_plural">{{ $__t('Name') }} <span
|
||||||
<input type="text"
|
class="small text-muted">{{ $__t('in plural form') }}</span></label>
|
||||||
class="form-control"
|
<input type="text" class="form-control" id="name_plural" name="name_plural"
|
||||||
id="name_plural"
|
value="@if ($mode == 'edit') {{ $quantityUnit->name_plural }} @endif">
|
||||||
name="name_plural"
|
|
||||||
value="@if($mode == 'edit'){{ $quantityUnit->name_plural }}@endif">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($pluralCount > 2)
|
@if ($pluralCount > 2)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="plural_forms">
|
<label for="plural_forms">
|
||||||
{{ $__t('Plural forms') }}<br>
|
{{ $__t('Plural forms') }}<br>
|
||||||
|
|
@ -62,34 +56,37 @@
|
||||||
{{ $__t('Plural rule') }}: {{ $pluralRule }}
|
{{ $__t('Plural rule') }}: {{ $pluralRule }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea class="form-control"
|
<textarea class="form-control" rows="3" id="plural_forms" name="plural_forms">
|
||||||
rows="3"
|
@if ($mode == 'edit')
|
||||||
id="plural_forms"
|
{{ $quantityUnit->plural_forms }}
|
||||||
name="plural_forms">@if($mode == 'edit'){{ $quantityUnit->plural_forms }}@endif</textarea>
|
@endif
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="description">{{ $__t('Description') }}</label>
|
<label for="description">{{ $__t('Description') }}</label>
|
||||||
<textarea class="form-control"
|
<textarea class="form-control" rows="2" id="description" name="description">
|
||||||
rows="2"
|
@if ($mode == 'edit')
|
||||||
id="description"
|
{{ $quantityUnit->description }}
|
||||||
name="description">@if($mode == 'edit'){{ $quantityUnit->description }}@endif</textarea>
|
@endif
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@include('components.userfieldsform', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'entity' => 'quantity_units'
|
'entity' => 'quantity_units',
|
||||||
))
|
])
|
||||||
|
|
||||||
<small class="my-2 form-text text-muted @if($mode == 'edit') d-none @endif">{{ $__t('Save & continue to add conversions') }}</small>
|
<small
|
||||||
|
class="my-2 form-text text-muted @if ($mode == 'edit') d-none @endif">{{ $__t('Save & continue to add conversions') }}</small>
|
||||||
|
|
||||||
<button class="save-quantityunit-button btn btn-success mb-2"
|
<button class="save-quantityunit-button btn btn-success mb-2"
|
||||||
data-location="continue">{{ $__t('Save & continue') }}</button>
|
data-location="continue">{{ $__t('Save & continue') }}</button>
|
||||||
<button class="save-quantityunit-button btn btn-info mb-2"
|
<button class="save-quantityunit-button btn btn-info mb-2"
|
||||||
data-location="return">{{ $__t('Save & return to quantity units') }}</button>
|
data-location="return">{{ $__t('Save & return to quantity units') }}</button>
|
||||||
|
|
||||||
@if(intval($pluralCount) > 2)
|
@if (intval($pluralCount) > 2)
|
||||||
<button id="test-quantityunit-plural-forms-button"
|
<button id="test-quantityunit-plural-forms-button"
|
||||||
class="btn btn-secondary">{{ $__t('Test plural forms') }}</button>
|
class="btn btn-secondary">{{ $__t('Test plural forms') }}</button>
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -97,63 +94,57 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-lg-6 col-12 @if($mode == 'create') d-none @endif">
|
<div class="col-lg-6 col-12 @if ($mode == 'create') d-none @endif">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h4>
|
<h4>
|
||||||
{{ $__t('Default conversions') }}
|
{{ $__t('Default conversions') }}
|
||||||
<small id="qu-conversion-headline-info"
|
<small id="qu-conversion-headline-info" class="text-muted font-italic"></small>
|
||||||
class="text-muted font-italic"></small>
|
|
||||||
</h4>
|
</h4>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-outline-primary btn-sm m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
<a class="btn btn-outline-primary btn-sm m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
href="{{ $U('/quantityunitconversion/new?embedded&qu-unit=' . $quantityUnit->id ) }}">
|
href="{{ $U('/quantityunitconversion/new?embedded&qu-unit=' . $quantityUnit->id) }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="qu-conversions-table"
|
{{-- TODO: DataTables: dynamic data: quantity_unit_conversions --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="qu-conversions-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#qu-conversions-table" href="#"><i
|
||||||
title="{{ $__t('Table options') }}"
|
class="fas fa-eye"></i></a>
|
||||||
data-table-selector="#qu-conversions-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Factor') }}</th>
|
<th>{{ $__t('Factor') }}</th>
|
||||||
<th>{{ $__t('Unit') }}</th>
|
<th>{{ $__t('Unit') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@if($mode == "edit")
|
@if ($mode == 'edit')
|
||||||
@foreach($defaultQuConversions as $defaultQuConversion)
|
@foreach ($defaultQuConversions as $defaultQuConversion)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-sm btn-info show-as-dialog-link"
|
<a class="btn btn-sm btn-info show-as-dialog-link"
|
||||||
href="{{ $U('/quantityunitconversion/' . $defaultQuConversion->id . '?embedded&qu-unit=' . $quantityUnit->id ) }}"
|
href="{{ $U('/quantityunitconversion/' . $defaultQuConversion->id . '?embedded&qu-unit=' . $quantityUnit->id) }}"
|
||||||
data-qu-conversion-id="{{ $defaultQuConversion->id }}">
|
data-qu-conversion-id="{{ $defaultQuConversion->id }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-danger qu-conversion-delete-button"
|
<a class="btn btn-sm btn-danger qu-conversion-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-qu-conversion-id="{{ $defaultQuConversion->id }}">
|
data-qu-conversion-id="{{ $defaultQuConversion->id }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $defaultQuConversion->factor }}</span>
|
<span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $defaultQuConversion->factor }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ FindObjectInArrayByPropertyValue($quantityUnits, 'id', $defaultQuConversion->to_qu_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($quantityUnits, 'id', $defaultQuConversion->to_qu_id)->name }}
|
||||||
|
|
@ -166,5 +157,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,51 +5,47 @@
|
||||||
@section('viewJsName', 'quantityunitpluraltesting')
|
@section('viewJsName', 'quantityunitpluraltesting')
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}" rel="stylesheet">
|
||||||
rel="stylesheet">
|
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-12">
|
<div class="col-lg-6 col-12">
|
||||||
<form id="quantityunitpluraltesting-form"
|
<form id="quantityunitpluraltesting-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="qu_id">{{ $__t('Quantity unit') }}</label>
|
<label for="qu_id">{{ $__t('Quantity unit') }}</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: quantity_units --}}
|
||||||
id="qu_id"
|
<select class="custom-control custom-select" id="qu_id" name="qu_id">
|
||||||
name="qu_id">
|
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($quantityUnits as $quantityUnit)
|
@foreach ($quantityUnits as $quantityUnit)
|
||||||
<option value="{{ $quantityUnit->id }}"
|
<option value="{{ $quantityUnit->id }}" data-singular-form="{{ $quantityUnit->name }}"
|
||||||
data-singular-form="{{ $quantityUnit->name }}"
|
|
||||||
data-plural-form="{{ $quantityUnit->name_plural }}">{{ $quantityUnit->name }}</option>
|
data-plural-form="{{ $quantityUnit->name_plural }}">{{ $quantityUnit->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'amount',
|
'id' => 'amount',
|
||||||
'label' => 'Amount',
|
'label' => 'Amount',
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
'value' => 1,
|
'value' => 1,
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount',
|
||||||
))
|
])
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<h2><strong>{{ $__t('Result') }}:</strong> <span id="result"></span></h2>
|
<h2><strong>{{ $__t('Result') }}:</strong> <span id="result"></span></h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'quantityunits')
|
@section('viewJsName', 'quantityunits')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/quantityunit/new') }}">
|
href="{{ $U('/quantityunit/new') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -36,70 +31,57 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="quantityunits-table"
|
{{-- TODO: DataTables: dynamic data: quantity_units --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="quantityunits-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#quantityunits-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#quantityunits-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Description') }}</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($quantityunits as $quantityunit)
|
@foreach ($quantityunits as $quantityunit)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm"
|
<a class="btn btn-info btn-sm" href="{{ $U('/quantityunit/') }}{{ $quantityunit->id }}"
|
||||||
href="{{ $U('/quantityunit/') }}{{ $quantityunit->id }}"
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm quantityunit-delete-button"
|
<a class="btn btn-danger btn-sm quantityunit-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-quantityunit-id="{{ $quantityunit->id }}"
|
data-quantityunit-id="{{ $quantityunit->id }}"
|
||||||
data-quantityunit-name="{{ $quantityunit->name }}"
|
data-quantityunit-name="{{ $quantityunit->name }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -111,15 +93,19 @@
|
||||||
{{ $quantityunit->description }}
|
{{ $quantityunit->description }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $quantityunit->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$quantityunit->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
@extends('layout.default')
|
@extends('layout.default')
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
@section('title', $__t('Edit recipe'))
|
@section('title', $__t('Edit recipe'))
|
||||||
@else
|
@else
|
||||||
@section('title', $__t('Create recipe'))
|
@section('title', $__t('Create recipe'))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@section('viewJsName', 'recipeform')
|
@section('viewJsName', 'recipeform')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
|
|
||||||
|
|
@ -19,87 +19,90 @@
|
||||||
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditObjectId = {{ $recipe->id }};
|
Grocy.EditObjectId = {{ $recipe->id }};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if(!empty($recipe->picture_file_name))
|
@if (!empty($recipe->picture_file_name))
|
||||||
<script>
|
<script>
|
||||||
Grocy.RecipePictureFileName = '{{ $recipe->picture_file_name }}';
|
Grocy.RecipePictureFileName = '{{ $recipe->picture_file_name }}';
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-7 pb-3">
|
<div class="col-12 col-md-7 pb-3">
|
||||||
<form id="recipe-form"
|
<form id="recipe-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">{{ $__t('Name') }}</label>
|
<label for="name">{{ $__t('Name') }}</label>
|
||||||
<input type="text"
|
<input type="text" class="form-control" required id="name" name="name"
|
||||||
class="form-control"
|
value="@if ($mode == 'edit') {{ $recipe->name }} @endif">
|
||||||
required
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
value="@if($mode == 'edit'){{ $recipe->name }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $recipe->base_servings; } else { $value = 1; } @endphp
|
@php
|
||||||
@include('components.numberpicker', array(
|
if ($mode == 'edit') {
|
||||||
|
$value = $recipe->base_servings;
|
||||||
|
} else {
|
||||||
|
$value = 1;
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('components.numberpicker', [
|
||||||
'id' => 'base_servings',
|
'id' => 'base_servings',
|
||||||
'label' => 'Servings',
|
'label' => 'Servings',
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'hint' => $__t('The ingredients listed here result in this amount of servings'),
|
'hint' => $__t('The ingredients listed here result in this amount of servings'),
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input @if($mode=='edit'
|
<input @if ($mode == 'edit' && $recipe->not_check_shoppinglist == 1) checked @endif
|
||||||
&&
|
class="form-check-input custom-control-input" type="checkbox" id="not_check_shoppinglist"
|
||||||
$recipe->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">
|
name="not_check_shoppinglist" value="1">
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label" for="not_check_shoppinglist">
|
||||||
for="not_check_shoppinglist">
|
|
||||||
{{ $__t('Do not check against the shopping list when adding missing items to it') }}
|
{{ $__t('Do not check against the shopping list when adding missing items to it') }}
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('By default the amount to be added to the shopping list is "needed amount - stock amount - shopping list amount" - when this is enabled, it is only checked against the stock amount, not against what is already on the shopping list') }}"></i>
|
title="{{ $__t('By default the amount to be added to the shopping list is "needed amount - stock amount - shopping list amount" - when this is enabled, it is only checked against the stock amount, not against what is already on the shopping list') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', [
|
||||||
'products' => $products,
|
'productsQuery' => 'order=name%3Acollate%20nocase',
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
'label' => 'Produces product',
|
'label' => 'Produces product',
|
||||||
'prefillById' => $mode == 'edit' ? $recipe->product_id : '',
|
'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'),
|
'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,
|
'disallowAllProductWorkflows' => true,
|
||||||
))
|
])
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@include('components.userfieldsform', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'entity' => 'recipes'
|
'entity' => 'recipes',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="description">{{ $__t('Preparation') }}</label>
|
<label for="description">{{ $__t('Preparation') }}</label>
|
||||||
<textarea id="description"
|
<textarea id="description" class="form-control wysiwyg-editor" name="description">
|
||||||
class="form-control wysiwyg-editor"
|
@if ($mode == 'edit')
|
||||||
name="description">@if($mode == 'edit'){{ $recipe->description }}@endif</textarea>
|
{{ $recipe->description }}
|
||||||
|
@endif
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<small class="my-2 form-text text-muted @if($mode == 'edit') d-none @endif">{{ $__t('Save & continue to add ingredients and included recipes') }}</small>
|
<small
|
||||||
|
class="my-2 form-text text-muted @if ($mode == 'edit') d-none @endif">{{ $__t('Save & continue to add ingredients and included recipes') }}</small>
|
||||||
|
|
||||||
<button class="save-recipe btn btn-success mb-2"
|
<button class="save-recipe btn btn-success mb-2"
|
||||||
data-location="continue">{{ $__t('Save & continue') }}</button>
|
data-location="continue">{{ $__t('Save & continue') }}</button>
|
||||||
|
|
@ -109,40 +112,33 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 col-md-5 pb-3 @if($mode == 'create') d-none @endif">
|
<div class="col-12 col-md-5 pb-3 @if ($mode == 'create') d-none @endif">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h4>
|
<h4>
|
||||||
{{ $__t('Ingredients list') }}
|
{{ $__t('Ingredients list') }}
|
||||||
</h4>
|
</h4>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a id="recipe-pos-add-button"
|
<a id="recipe-pos-add-button"
|
||||||
class="btn btn-outline-primary btn-sm recipe-pos-add-button m-1 mt-md-0 mb-md-0 float-right"
|
class="btn btn-outline-primary btn-sm recipe-pos-add-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
type="button"
|
type="button" href="#">
|
||||||
href="#">
|
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="recipes-pos-table"
|
{{-- TODO: DataTables: dynamic data: recipes_pos --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="recipes-pos-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#recipes-pos-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#recipes-pos-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Product') }}</th>
|
<th>{{ $__t('Product') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
|
|
@ -151,19 +147,16 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@if($mode == "edit")
|
@if ($mode == 'edit')
|
||||||
@foreach($recipePositions as $recipePosition)
|
@foreach ($recipePositions as $recipePosition)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-sm btn-info recipe-pos-edit-button"
|
<a class="btn btn-sm btn-info recipe-pos-edit-button" type="button" href="#"
|
||||||
type="button"
|
|
||||||
href="#"
|
|
||||||
data-recipe-pos-id="{{ $recipePosition->id }}"
|
data-recipe-pos-id="{{ $recipePosition->id }}"
|
||||||
data-product-id="{{ $recipePosition->product_id }}">
|
data-product-id="{{ $recipePosition->product_id }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-danger recipe-pos-delete-button"
|
<a class="btn btn-sm btn-danger recipe-pos-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-recipe-pos-id="{{ $recipePosition->id }}"
|
data-recipe-pos-id="{{ $recipePosition->id }}"
|
||||||
data-recipe-pos-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }}">
|
data-recipe-pos-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
|
|
@ -178,8 +171,7 @@
|
||||||
// but some users decide to edit the database manually and
|
// but some users decide to edit the database manually and
|
||||||
// enter something like "4 or 5" in the amount column (brilliant)
|
// 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
|
// => So at least don't crash this view by just assuming 0 if that's the case
|
||||||
if (!is_numeric($recipePosition->amount))
|
if (!is_numeric($recipePosition->amount)) {
|
||||||
{
|
|
||||||
$recipePosition->amount = 0;
|
$recipePosition->amount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,27 +179,29 @@
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
||||||
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $recipePosition->qu_id);
|
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $recipePosition->qu_id);
|
||||||
if ($productQuConversion && $recipePosition->only_check_single_unit_in_stock == 0)
|
if ($productQuConversion && $recipePosition->only_check_single_unit_in_stock == 0) {
|
||||||
{
|
|
||||||
$recipePosition->amount = $recipePosition->amount * $productQuConversion->factor;
|
$recipePosition->amount = $recipePosition->amount * $productQuConversion->factor;
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
@if(!empty($recipePosition->variable_amount))
|
@if (!empty($recipePosition->variable_amount))
|
||||||
{{ $recipePosition->variable_amount }}
|
{{ $recipePosition->variable_amount }}
|
||||||
@else
|
@else
|
||||||
<span class="locale-number locale-number-quantity-amount">@if($recipePosition->amount == round($recipePosition->amount)){{ round($recipePosition->amount) }}@else{{ $recipePosition->amount }}@endif</span>
|
<span class="locale-number locale-number-quantity-amount">
|
||||||
|
@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) }}
|
</span>
|
||||||
|
@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))
|
@if (!empty($recipePosition->variable_amount))
|
||||||
<div class="small text-muted font-italic">{{ $__t('Variable amount') }}</div>
|
<div class="small text-muted font-italic">{{ $__t('Variable amount') }}
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="fit-content">
|
<td class="fit-content">
|
||||||
<a class="btn btn-sm btn-info recipe-pos-show-note-button @if(empty($recipePosition->note)) disabled @endif"
|
<a class="btn btn-sm btn-info recipe-pos-show-note-button @if (empty($recipePosition->note)) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip" data-placement="top"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="top"
|
|
||||||
title="{{ $__t('Show notes') }}"
|
title="{{ $__t('Show notes') }}"
|
||||||
data-recipe-pos-note="{{ $recipePosition->note }}">
|
data-recipe-pos-note="{{ $recipePosition->note }}">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
|
|
@ -230,50 +224,42 @@
|
||||||
<h4>
|
<h4>
|
||||||
{{ $__t('Included recipes') }}
|
{{ $__t('Included recipes') }}
|
||||||
</h4>
|
</h4>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a id="recipe-include-add-button"
|
<a id="recipe-include-add-button"
|
||||||
class="btn btn-outline-primary btn-sm m-1 mt-md-0 mb-md-0 float-right"
|
class="btn btn-outline-primary btn-sm m-1 mt-md-0 mb-md-0 float-right" href="#">
|
||||||
href="#">
|
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table id="recipes-includes-table"
|
{{-- TODO: DataTables: dynamic data: recipes_nestings_resolved --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="recipes-includes-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#recipes-includes-table" href="#"><i
|
||||||
title="{{ $__t('Table options') }}"
|
class="fas fa-eye"></i></a>
|
||||||
data-table-selector="#recipes-includes-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Recipe') }}</th>
|
<th>{{ $__t('Recipe') }}</th>
|
||||||
<th>{{ $__t('Servings') }}</th>
|
<th>{{ $__t('Servings') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@if($mode == "edit")
|
@if ($mode == 'edit')
|
||||||
@foreach($recipeNestings as $recipeNesting)
|
@foreach ($recipeNestings as $recipeNesting)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-sm btn-info recipe-include-edit-button"
|
<a class="btn btn-sm btn-info recipe-include-edit-button" href="#"
|
||||||
href="#"
|
|
||||||
data-recipe-include-id="{{ $recipeNesting->id }}"
|
data-recipe-include-id="{{ $recipeNesting->id }}"
|
||||||
data-recipe-included-recipe-id="{{ $recipeNesting->includes_recipe_id }}"
|
data-recipe-included-recipe-id="{{ $recipeNesting->includes_recipe_id }}"
|
||||||
data-recipe-included-recipe-servings="{{ $recipeNesting->servings }}">
|
data-recipe-included-recipe-servings="{{ $recipeNesting->servings }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-danger recipe-include-delete-button"
|
<a class="btn btn-sm btn-danger recipe-include-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-recipe-include-id="{{ $recipeNesting->id }}"
|
data-recipe-include-id="{{ $recipeNesting->id }}"
|
||||||
data-recipe-include-name="{{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }}">
|
data-recipe-include-name="{{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
|
|
@ -302,17 +288,14 @@
|
||||||
<div class="form-group w-75 m-0">
|
<div class="form-group w-75 m-0">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="custom-file">
|
<div class="custom-file">
|
||||||
<input type="file"
|
<input type="file" class="custom-file-input" id="recipe-picture" accept="image/*">
|
||||||
class="custom-file-input"
|
|
||||||
id="recipe-picture"
|
|
||||||
accept="image/*">
|
|
||||||
<label id="recipe-picture-label"
|
<label id="recipe-picture-label"
|
||||||
class="custom-file-label @if(empty($recipe->picture_file_name)) d-none @endif"
|
class="custom-file-label @if (empty($recipe->picture_file_name)) d-none @endif"
|
||||||
for="recipe-picture">
|
for="recipe-picture">
|
||||||
{{ $recipe->picture_file_name }}
|
{{ $recipe->picture_file_name }}
|
||||||
</label>
|
</label>
|
||||||
<label id="recipe-picture-label-none"
|
<label id="recipe-picture-label-none"
|
||||||
class="custom-file-label @if(!empty($recipe->picture_file_name)) d-none @endif"
|
class="custom-file-label @if (!empty($recipe->picture_file_name)) d-none @endif"
|
||||||
for="recipe-picture">
|
for="recipe-picture">
|
||||||
{{ $__t('No file selected') }}
|
{{ $__t('No file selected') }}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -324,15 +307,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if(!empty($recipe->picture_file_name))
|
@if (!empty($recipe->picture_file_name))
|
||||||
<img id="current-recipe-picture"
|
<img id="current-recipe-picture"
|
||||||
data-src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture&best_fit_width=400') }}"
|
data-src="{{ $U('/api/files/recipepictures/' .base64_encode($recipe->picture_file_name) .'?force_serve_as=picture&best_fit_width=400') }}"
|
||||||
class="img-fluid img-thumbnail mt-2 lazy mb-5">
|
class="img-fluid img-thumbnail mt-2 lazy mb-5">
|
||||||
<p id="delete-current-recipe-picture-on-save-hint"
|
<p id="delete-current-recipe-picture-on-save-hint"
|
||||||
class="form-text text-muted font-italic d-none mb-5">{{ $__t('The current picture will be deleted on save') }}</p>
|
class="form-text text-muted font-italic d-none mb-5">
|
||||||
|
{{ $__t('The current picture will be deleted on save') }}</p>
|
||||||
@else
|
@else
|
||||||
<p id="no-current-recipe-picture-hint"
|
<p id="no-current-recipe-picture-hint" class="form-text text-muted font-italic mb-5">
|
||||||
class="form-text text-muted font-italic mb-5">{{ $__t('No picture available') }}</p>
|
{{ $__t('No picture available') }}</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -342,13 +326,11 @@
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h4>
|
<h4>
|
||||||
<span class="ls-n1">{{ $__t('grocycode') }}</span>
|
<span class="ls-n1">{{ $__t('grocycode') }}</span>
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
title="{{ $__t('grocycode is a unique referer to this %s in your grocy instance - print it onto a label and scan it like any other barcode',$__t('Recipe')) }}"></i>
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('grocycode is a unique referer to this %s in your grocy instance - print it onto a label and scan it like any other barcode', $__t('Recipe')) }}"></i>
|
|
||||||
</h4>
|
</h4>
|
||||||
<p>
|
<p>
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<img src="{{ $U('/recipe/' . $recipe->id . '/grocycode?size=60') }}"
|
<img src="{{ $U('/recipe/' . $recipe->id . '/grocycode?size=60') }}"
|
||||||
class="float-lg-left">
|
class="float-lg-left">
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -356,10 +338,9 @@
|
||||||
<p>
|
<p>
|
||||||
<a class="btn btn-outline-primary btn-sm"
|
<a class="btn btn-outline-primary btn-sm"
|
||||||
href="{{ $U('/recipe/' . $recipe->id . '/grocycode?download=true') }}">{{ $__t('Download') }}</a>
|
href="{{ $U('/recipe/' . $recipe->id . '/grocycode?download=true') }}">{{ $__t('Download') }}</a>
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
<a class="btn btn-outline-primary btn-sm recipe-grocycode-label-print"
|
<a class="btn btn-outline-primary btn-sm recipe-grocycode-label-print"
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-id="{{ $recipe->id }}" href="#">
|
||||||
href="#">
|
|
||||||
{{ $__t('Print on label printer') }}
|
{{ $__t('Print on label printer') }}
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -369,46 +350,39 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="recipe-include-editform-modal" tabindex="-1">
|
||||||
id="recipe-include-editform-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 id="recipe-include-editform-title"
|
<h4 id="recipe-include-editform-title" class="modal-title w-100"></h4>
|
||||||
class="modal-title w-100"></h4>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form id="recipe-include-form"
|
<form id="recipe-include-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@include('components.recipepicker', array(
|
@include('components.recipepicker', [
|
||||||
'recipes' => $recipes,
|
'recipes' => $recipes,
|
||||||
'isRequired' => true
|
'isRequired' => true,
|
||||||
))
|
])
|
||||||
|
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'includes_servings',
|
'id' => 'includes_servings',
|
||||||
'label' => 'Servings',
|
'label' => 'Servings',
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
'value' => '1',
|
'value' => '1',
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount',
|
||||||
))
|
])
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
class="btn btn-secondary"
|
<button id="save-recipe-include-button" data-dismiss="modal"
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
|
||||||
<button id="save-recipe-include-button"
|
|
||||||
data-dismiss="modal"
|
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
novalidate>
|
novalidate>
|
||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', array(
|
||||||
'products' => $products,
|
'productsQuery' => ($recipePosId === 'new' ? 'query%5B%5D=active%3D1&' : '') . 'order=name%3Acollate%20nocase',
|
||||||
'nextInputSelector' => '#amount'
|
'nextInputSelector' => '#amount'
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,41 +5,36 @@
|
||||||
@section('viewJsName', 'recipes')
|
@section('viewJsName', 'recipes')
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<style>
|
<style>
|
||||||
.card-img-top {
|
.card-img-top {
|
||||||
max-height: 250px !important;
|
max-height: 250px !important;
|
||||||
object-fit: cover !important;
|
object-fit: cover !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<script>
|
<script>
|
||||||
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
||||||
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="@if(boolval($userSettings['recipes_show_list_side_by_side']) || $embedded) col-12 col-md-6 @else col @endif d-print-none">
|
<div class="@if (boolval($userSettings['recipes_show_list_side_by_side']) || $embedded) col-12 col-md-6 @else col @endif d-print-none">
|
||||||
<div class="title-related-links border-bottom mb-2 py-1">
|
<div class="title-related-links border-bottom mb-2 py-1">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/recipe/new') }}">
|
href="{{ $U('/recipe/new') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -47,17 +42,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-5 col-xl-5">
|
<div class="col-12 col-md-5 col-xl-5">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -66,11 +57,11 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
id="status-filter">
|
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<option value="Xenoughinstock">{{ $__t('Enough in stock') }}</option>
|
<option value="Xenoughinstock">{{ $__t('Enough in stock') }}</option>
|
||||||
<option value="enoughinstockwithshoppinglist">{{ $__t('Not enough in stock, but already on the shopping list') }}</option>
|
<option value="enoughinstockwithshoppinglist">
|
||||||
|
{{ $__t('Not enough in stock, but already on the shopping list') }}</option>
|
||||||
<option value="notenoughinstock">{{ $__t('Not enough in stock') }}</option>
|
<option value="notenoughinstock">{{ $__t('Not enough in stock') }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -78,9 +69,7 @@
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right mt-1">
|
<div class="float-right mt-1">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -89,90 +78,74 @@
|
||||||
|
|
||||||
<ul class="nav nav-tabs grocy-tabs">
|
<ul class="nav nav-tabs grocy-tabs">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active"
|
<a class="nav-link active" id="list-tab" data-toggle="tab" href="#list">{{ $__t('List') }}</a>
|
||||||
id="list-tab"
|
|
||||||
data-toggle="tab"
|
|
||||||
href="#list">{{ $__t('List') }}</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link"
|
<a class="nav-link" id="gallery-tab" data-toggle="tab"
|
||||||
id="gallery-tab"
|
|
||||||
data-toggle="tab"
|
|
||||||
href="#gallery">{{ $__t('Gallery') }}</a>
|
href="#gallery">{{ $__t('Gallery') }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content grocy-tabs">
|
<div class="tab-content grocy-tabs">
|
||||||
<div class="tab-pane show active"
|
<div class="tab-pane show active" id="list">
|
||||||
id="list">
|
{{-- TODO: DataTables: dynamic data: recipes --}}
|
||||||
<table id="recipes-table"
|
<table id="recipes-table" class="table table-sm table-striped nowrap w-100">
|
||||||
class="table table-sm table-striped nowrap w-100">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#recipes-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#recipes-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Desired servings') }}</th>
|
<th class="allow-grouping">{{ $__t('Desired servings') }}</th>
|
||||||
<th data-shadow-rowgroup-column="7"
|
<th data-shadow-rowgroup-column="7"
|
||||||
class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif allow-grouping">{{ $__t('Requirements fulfilled') }}</th>
|
class="@if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif allow-grouping">
|
||||||
|
{{ $__t('Requirements fulfilled') }}</th>
|
||||||
<th class="d-none">Hidden status for sorting of "Requirements fulfilled" column</th>
|
<th class="d-none">Hidden status for sorting of "Requirements fulfilled" column</th>
|
||||||
<th class="d-none">Hidden status for filtering by status</th>
|
<th class="d-none">Hidden status for filtering by status</th>
|
||||||
<th class="d-none">Hidden recipe ingredient product names</th>
|
<th class="d-none">Hidden recipe ingredient product names</th>
|
||||||
<th class="d-none">Hidden status for grouping by status</th>
|
<th class="d-none">Hidden status for grouping by status</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($recipes as $recipe)
|
@foreach ($recipes as $recipe)
|
||||||
<tr id="recipe-row-{{ $recipe->id }}"
|
<tr id="recipe-row-{{ $recipe->id }}" data-recipe-id="{{ $recipe->id }}">
|
||||||
data-recipe-id="{{ $recipe->id }}">
|
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm hide-when-embedded hide-on-fullscreen-card"
|
<a class="btn btn-info btn-sm hide-when-embedded hide-on-fullscreen-card"
|
||||||
href="{{ $U('/recipe/') }}{{ $recipe->id }}"
|
href="{{ $U('/recipe/') }}{{ $recipe->id }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right hide-on-fullscreen-card hide-when-embedded">
|
<div
|
||||||
<a class="dropdown-item recipe-delete"
|
class="table-inline-menu dropdown-menu dropdown-menu-right hide-on-fullscreen-card hide-when-embedded">
|
||||||
type="button"
|
<a class="dropdown-item recipe-delete" type="button" href="#"
|
||||||
href="#"
|
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-id="{{ $recipe->id }}"
|
||||||
data-recipe-name="{{ $recipe->name }}">
|
data-recipe-name="{{ $recipe->name }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Delete this item') }}</span>
|
<span
|
||||||
|
class="dropdown-item-text">{{ $__t('Delete this item') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item recipe-copy"
|
<a class="dropdown-item recipe-copy" type="button" href="#"
|
||||||
type="button"
|
|
||||||
href="#"
|
|
||||||
data-recipe-id="{{ $recipe->id }}">
|
data-recipe-id="{{ $recipe->id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Copy recipe') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Copy recipe') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/recipe/' . $recipe->id . '/grocycode?download=true') }}">
|
href="{{ $U('/recipe/' . $recipe->id . '/grocycode?download=true') }}">
|
||||||
<span class="dropdown-item-text">{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Recipe'))) !!}</span>
|
<span class="dropdown-item-text">{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Recipe'))) !!}</span>
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
<a class="dropdown-item recipe-grocycode-label-print"
|
<a class="dropdown-item recipe-grocycode-label-print"
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-id="{{ $recipe->id }}" type="button" href="#">
|
||||||
type="button"
|
|
||||||
href="#">
|
|
||||||
<span class="dropdown-item-text">{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Recipe'))) !!}</span>
|
<span class="dropdown-item-text">{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Recipe'))) !!}</span>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
|
|
@ -185,29 +158,56 @@
|
||||||
<td>
|
<td>
|
||||||
{{ $recipe->desired_servings }}
|
{{ $recipe->desired_servings }}
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
|
||||||
@if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
|
@if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1)
|
||||||
<span class="timeago-contextual">@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</span>
|
<i class="fas fa-check text-success"></i>
|
||||||
|
@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)
|
||||||
|
<i class="fas fa-exclamation text-warning"></i>@else<i
|
||||||
|
class="fas fa-times text-danger"></i>
|
||||||
|
@endif
|
||||||
|
<span class="timeago-contextual">
|
||||||
|
@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
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
{{ FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count }}
|
{{ FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->missing_products_count }}
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
@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
|
@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
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
@foreach(FindAllObjectsInArrayByPropertyValue($recipePositionsResolved, 'recipe_id', $recipe->id) as $recipePos)
|
@foreach (FindAllObjectsInArrayByPropertyValue($recipePositionsResolved, 'recipe_id', $recipe->id) as $recipePos)
|
||||||
{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePos->product_id)->name . ' ' }}
|
{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePos->product_id)->name . ' ' }}
|
||||||
@endforeach
|
@endforeach
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
@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
|
@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
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $recipe->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$recipe->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
@ -215,37 +215,42 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane show"
|
<div class="tab-pane show" id="gallery">
|
||||||
id="gallery">
|
|
||||||
<div class="card-columns no-gutters">
|
<div class="card-columns no-gutters">
|
||||||
@foreach($recipes as $recipe)
|
@foreach ($recipes as $recipe)
|
||||||
<a class="discrete-link recipe-gallery-item @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1) recipe-enoughinstock @elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) recipe-enoughinstockwithshoppinglist @else recipe-notenoughinstock @endif"
|
<a class="discrete-link recipe-gallery-item @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1) recipe-enoughinstock @elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) recipe-enoughinstockwithshoppinglist @else recipe-notenoughinstock @endif"
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-id="{{ $recipe->id }}" href="#">
|
||||||
href="#">
|
<div id="RecipeGalleryCard-{{ $recipe->id }}" class="card recipe-card">
|
||||||
<div id="RecipeGalleryCard-{{ $recipe->id }}"
|
@if (!empty($recipe->picture_file_name))
|
||||||
class="card recipe-card">
|
<img data-src="{{ $U('/api/files/recipepictures/' .base64_encode($recipe->picture_file_name) .'?force_serve_as=picture&best_fit_width=400') }}"
|
||||||
@if(!empty($recipe->picture_file_name))
|
|
||||||
<img data-src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture&best_fit_width=400') }}"
|
|
||||||
class="card-img-top lazy">
|
class="card-img-top lazy">
|
||||||
@endif
|
@endif
|
||||||
<div class="card-body text-center">
|
<div class="card-body text-center">
|
||||||
<h5 class="card-title mb-1">{{ $recipe->name }}</h5>
|
<h5 class="card-title mb-1">{{ $recipe->name }}</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
@if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
|
@if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 1)
|
||||||
<span class="timeago-contextual">@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</span>
|
<i class="fas fa-check text-success"></i>
|
||||||
|
@elseif(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)
|
||||||
|
<i class="fas fa-exclamation text-warning"></i>@else<i
|
||||||
|
class="fas fa-times text-danger"></i>
|
||||||
|
@endif
|
||||||
|
<span class="timeago-contextual">
|
||||||
|
@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
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="card-text mt-2">
|
<p class="card-text mt-2">
|
||||||
<a class="btn btn-xs btn-outline-danger hide-when-embedded hide-on-fullscreen-card recipe-delete"
|
<a class="btn btn-xs btn-outline-danger hide-when-embedded hide-on-fullscreen-card recipe-delete"
|
||||||
href="#"
|
href="#" data-recipe-id="{{ $recipe->id }}"
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-name="{{ $recipe->name }}" data-toggle="tooltip"
|
||||||
data-recipe-name="{{ $recipe->name }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-outline-info btn-xs hide-when-embedded hide-on-fullscreen-card"
|
<a class="btn btn-outline-info btn-xs hide-when-embedded hide-on-fullscreen-card"
|
||||||
href="{{ $U('/recipe/') }}{{ $recipe->id }}"
|
href="{{ $U('/recipe/') }}{{ $recipe->id }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -259,22 +264,20 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($selectedRecipe !== null && (boolval($userSettings['recipes_show_list_side_by_side']) || $embedded))
|
@if ($selectedRecipe !== null && (boolval($userSettings['recipes_show_list_side_by_side']) || $embedded))
|
||||||
@php
|
@php
|
||||||
$allRecipes = $selectedRecipeSubRecipes;
|
$allRecipes = $selectedRecipeSubRecipes;
|
||||||
array_unshift($allRecipes, $selectedRecipe);
|
array_unshift($allRecipes, $selectedRecipe);
|
||||||
@endphp
|
@endphp
|
||||||
<div class="col-12 col-md-6 print-view">
|
<div class="col-12 col-md-6 print-view">
|
||||||
<div id="selectedRecipeCard"
|
<div id="selectedRecipeCard" class="card grocy-card">
|
||||||
class="card grocy-card">
|
@if (count($allRecipes) > 1)
|
||||||
@if(count($allRecipes) > 1)
|
|
||||||
<div class="card-header card-header-fullscreen d-print-none">
|
<div class="card-header card-header-fullscreen d-print-none">
|
||||||
<ul class="nav nav-tabs grocy-tabs card-header-tabs">
|
<ul class="nav nav-tabs grocy-tabs card-header-tabs">
|
||||||
@foreach($allRecipes as $index=>$recipe)
|
@foreach ($allRecipes as $index => $recipe)
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link @if($index == 0) active @endif"
|
<a class="nav-link @if ($index == 0) active @endif"
|
||||||
data-toggle="tab"
|
data-toggle="tab" href="#recipe-{{ $index + 1 }}">{{ $recipe->name }}</a>
|
||||||
href="#recipe-{{ $index + 1 }}">{{ $recipe->name }}</a>
|
|
||||||
</li>
|
</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -282,45 +285,39 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="tab-content grocy-tabs print break">
|
<div class="tab-content grocy-tabs print break">
|
||||||
@foreach($allRecipes as $index=>$recipe)
|
@foreach ($allRecipes as $index => $recipe)
|
||||||
<div class="tab-pane @if($index == 0) active @endif"
|
<div class="tab-pane @if ($index == 0) active @endif"
|
||||||
id="recipe-{{ $index + 1 }}"
|
id="recipe-{{ $index + 1 }}" role="tabpanel">
|
||||||
role="tabpanel">
|
@if (!empty($recipe->picture_file_name))
|
||||||
@if(!empty($recipe->picture_file_name))
|
|
||||||
<img class="card-img-top lazy"
|
<img class="card-img-top lazy"
|
||||||
src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture') }}">
|
src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture') }}">
|
||||||
@endif
|
@endif
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="shadow p-4 mb-5 bg-white rounded mt-n5 d-print-none @if(empty($recipe->picture_file_name)) d-none @endif">
|
<div
|
||||||
|
class="shadow p-4 mb-5 bg-white rounded mt-n5 d-print-none @if (empty($recipe->picture_file_name)) d-none @endif">
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<h3 class="card-title mb-0">{{ $recipe->name }}</h3>
|
<h3 class="card-title mb-0">{{ $recipe->name }}</h3>
|
||||||
<div class="card-icons d-flex flex-wrap justify-content-end flex-shrink-1">
|
<div class="card-icons d-flex flex-wrap justify-content-end flex-shrink-1">
|
||||||
<a class="btn @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif recipe-consume @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 0) disabled @endif"
|
<a class="btn @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif recipe-consume @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 0) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Consume all ingredients needed by this recipe') }}"
|
title="{{ $__t('Consume all ingredients needed by this recipe') }}"
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-id="{{ $recipe->id }}"
|
||||||
data-recipe-name="{{ $recipe->name }}">
|
data-recipe-name="{{ $recipe->name }}">
|
||||||
<i class="fas fa-utensils"></i>
|
<i class="fas fa-utensils"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif recipe-shopping-list @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) disabled @endif"
|
<a class="btn @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif recipe-shopping-list @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Put missing products on shopping list') }}"
|
title="{{ $__t('Put missing products on shopping list') }}"
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-id="{{ $recipe->id }}"
|
||||||
data-recipe-name="{{ $recipe->name }}">
|
data-recipe-name="{{ $recipe->name }}">
|
||||||
<i class="fas fa-cart-plus"></i>
|
<i class="fas fa-cart-plus"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn recipe-fullscreen hide-when-embedded"
|
<a class="btn recipe-fullscreen hide-when-embedded"
|
||||||
id="selectedRecipeToggleFullscreenButton"
|
id="selectedRecipeToggleFullscreenButton" href="#" data-toggle="tooltip"
|
||||||
href="#"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Expand to fullscreen') }}">
|
title="{{ $__t('Expand to fullscreen') }}">
|
||||||
<i class="fas fa-expand-arrows-alt"></i>
|
<i class="fas fa-expand-arrows-alt"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn recipe-print"
|
<a class="btn recipe-print" href="#" data-toggle="tooltip"
|
||||||
href="#"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Print') }}">
|
title="{{ $__t('Print') }}">
|
||||||
<i class="fas fa-print"></i>
|
<i class="fas fa-print"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -328,34 +325,30 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-4 @if(!empty($recipe->picture_file_name)) d-none @else d-flex @endif d-print-block justify-content-between align-items-center">
|
<div
|
||||||
|
class="mb-4 @if (!empty($recipe->picture_file_name)) d-none @else d-flex @endif d-print-block justify-content-between align-items-center">
|
||||||
<h1 class="card-title mb-0">{{ $recipe->name }}</h1>
|
<h1 class="card-title mb-0">{{ $recipe->name }}</h1>
|
||||||
<div class="card-icons d-flex flex-wrap justify-content-end flex-shrink-1 d-print-none">
|
<div
|
||||||
<a class="btn recipe-consume @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 0) disabled @endif"
|
class="card-icons d-flex flex-wrap justify-content-end flex-shrink-1 d-print-none">
|
||||||
href="#"
|
<a class="btn recipe-consume @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled == 0) disabled @endif"
|
||||||
data-toggle="tooltip"
|
href="#" data-toggle="tooltip"
|
||||||
title="{{ $__t('Consume all ingredients needed by this recipe') }}"
|
title="{{ $__t('Consume all ingredients needed by this recipe') }}"
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-id="{{ $recipe->id }}"
|
||||||
data-recipe-name="{{ $recipe->name }}">
|
data-recipe-name="{{ $recipe->name }}">
|
||||||
<i class="fas fa-utensils"></i>
|
<i class="fas fa-utensils"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn recipe-shopping-list @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) disabled @endif"
|
<a class="btn recipe-shopping-list @if (FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Put missing products on shopping list') }}"
|
title="{{ $__t('Put missing products on shopping list') }}"
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
data-recipe-id="{{ $recipe->id }}"
|
||||||
data-recipe-name="{{ $recipe->name }}">
|
data-recipe-name="{{ $recipe->name }}">
|
||||||
<i class="fas fa-cart-plus"></i>
|
<i class="fas fa-cart-plus"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class=" btnrecipe-fullscreen hide-when-embedded"
|
<a class=" btnrecipe-fullscreen hide-when-embedded" href="#"
|
||||||
href="#"
|
data-toggle="tooltip" title="{{ $__t('Expand to fullscreen') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Expand to fullscreen') }}">
|
|
||||||
<i class="fas fa-expand-arrows-alt"></i>
|
<i class="fas fa-expand-arrows-alt"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn recipe-print PrintRecipe"
|
<a class="btn recipe-print PrintRecipe" href="#" data-toggle="tooltip"
|
||||||
href="#"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Print') }}">
|
title="{{ $__t('Print') }}">
|
||||||
<i class="fas fa-print"></i>
|
<i class="fas fa-print"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -368,31 +361,31 @@
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="row ml-1">
|
<div class="row ml-1">
|
||||||
@if(!empty($calories) && intval($calories) > 0)
|
@if (!empty($calories) && intval($calories) > 0)
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<label>{{ $__t('Energy (kcal)') }}</label>
|
<label>{{ $__t('Energy (kcal)') }}</label>
|
||||||
<i class="fas fa-question-circle text-muted d-print-none"
|
<i class="fas fa-question-circle text-muted d-print-none"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('per serving') }}"></i>
|
title="{{ $__t('per serving') }}"></i>
|
||||||
<h3 class="locale-number locale-number-generic pt-0">{{ $calories }}</h3>
|
<h3 class="locale-number locale-number-generic pt-0">{{ $calories }}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<label>{{ $__t('Costs') }}
|
<label>{{ $__t('Costs') }}
|
||||||
<i class="fas fa-question-circle text-muted d-print-none"
|
<i class="fas fa-question-circle text-muted d-print-none"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('Based on the prices of the default consume rule (Opened first, then first due first, then first in first out) for in-stock ingredients and on the last price for missing ones') }}"></i>
|
title="{{ $__t('Based on the prices of the default consume rule (Opened first, then first due first, then first in first out) for in-stock ingredients and on the last price for missing ones') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
<h3 class="locale-number locale-number-currency pt-0">{{ $costs }}</h3>
|
<h3 class="locale-number locale-number-currency pt-0">{{ $costs }}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if($index == 0)
|
@if ($index == 0)
|
||||||
<div class="col-4 d-print-none">
|
<div class="col-4 d-print-none">
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'servings-scale',
|
'id' => 'servings-scale',
|
||||||
'label' => 'Desired servings',
|
'label' => 'Desired servings',
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
|
|
@ -400,8 +393,9 @@
|
||||||
'value' => $recipe->desired_servings,
|
'value' => $recipe->desired_servings,
|
||||||
'additionalAttributes' => 'data-recipe-id="' . $recipe->id . '"',
|
'additionalAttributes' => 'data-recipe-id="' . $recipe->id . '"',
|
||||||
'hint' => $__t('Base: %s', $recipe->base_servings),
|
'hint' => $__t('Base: %s', $recipe->base_servings),
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
'additionalCssClasses' =>
|
||||||
))
|
'locale-number-input locale-number-quantity-amount',
|
||||||
|
])
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -410,30 +404,26 @@
|
||||||
$recipePositionsFiltered = FindAllObjectsInArrayByPropertyValue($allRecipePositions[$recipe->id], 'recipe_id', $recipe->id);
|
$recipePositionsFiltered = FindAllObjectsInArrayByPropertyValue($allRecipePositions[$recipe->id], 'recipe_id', $recipe->id);
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<ul class="nav nav-tabs grocy-tabs mb-3 d-print-none"
|
<ul class="nav nav-tabs grocy-tabs mb-3 d-print-none" role="tablist">
|
||||||
role="tablist">
|
@if (count($recipePositionsFiltered) > 0)
|
||||||
@if(count($recipePositionsFiltered) > 0)
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active"
|
<a class="nav-link active" data-toggle="tab"
|
||||||
data-toggle="tab"
|
|
||||||
href="#ingredients-{{ $index }}"
|
href="#ingredients-{{ $index }}"
|
||||||
role="tab">{{ $__t('Ingredients') }}</a>
|
role="tab">{{ $__t('Ingredients') }}</a>
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
@if(!empty($recipe->description))
|
@if (!empty($recipe->description))
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link @if(count($recipePositionsFiltered) == 0) active @endif"
|
<a class="nav-link @if (count($recipePositionsFiltered) == 0) active @endif"
|
||||||
data-toggle="tab"
|
data-toggle="tab" href="#prep-{{ $index }}"
|
||||||
href="#prep-{{ $index }}"
|
|
||||||
role="tab">{{ $__t('Preparation') }}</a>
|
role="tab">{{ $__t('Preparation') }}</a>
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content grocy-tabs p-2 print">
|
<div class="tab-content grocy-tabs p-2 print">
|
||||||
@if(count($recipePositionsFiltered) > 0)
|
@if (count($recipePositionsFiltered) > 0)
|
||||||
<div class="tab-pane active"
|
<div class="tab-pane active" id="ingredients-{{ $index }}"
|
||||||
id="ingredients-{{ $index }}"
|
|
||||||
role="tabpanel">
|
role="tabpanel">
|
||||||
<div class="mb-2 mt-3 d-none d-print-block">
|
<div class="mb-2 mt-3 d-none d-print-block">
|
||||||
<h3 class="mb-0">{{ $__t('Ingredients') }}</h3>
|
<h3 class="mb-0">{{ $__t('Ingredients') }}</h3>
|
||||||
|
|
@ -445,48 +435,77 @@
|
||||||
$hasIngredientGroups = false;
|
$hasIngredientGroups = false;
|
||||||
$hasProductGroups = false;
|
$hasProductGroups = false;
|
||||||
@endphp
|
@endphp
|
||||||
@foreach($recipePositionsFiltered as $selectedRecipePosition)
|
@foreach ($recipePositionsFiltered as $selectedRecipePosition)
|
||||||
@if($lastIngredientGroup != $selectedRecipePosition->ingredient_group && !empty($selectedRecipePosition->ingredient_group))
|
@if ($lastIngredientGroup != $selectedRecipePosition->ingredient_group && !empty($selectedRecipePosition->ingredient_group))
|
||||||
@php $hasIngredientGroups = true; @endphp
|
@php $hasIngredientGroups = true; @endphp
|
||||||
<h5 class="mb-2 mt-2 ml-1"><strong>{{ $selectedRecipePosition->ingredient_group }}</strong></h5>
|
<h5 class="mb-2 mt-2 ml-1">
|
||||||
|
<strong>{{ $selectedRecipePosition->ingredient_group }}</strong>
|
||||||
|
</h5>
|
||||||
@endif
|
@endif
|
||||||
@if(boolval($userSettings['recipe_ingredients_group_by_product_group']) && $lastProductGroup != $selectedRecipePosition->product_group && !empty($selectedRecipePosition->product_group))
|
@if (boolval($userSettings['recipe_ingredients_group_by_product_group']) && $lastProductGroup != $selectedRecipePosition->product_group && !empty($selectedRecipePosition->product_group))
|
||||||
@php $hasProductGroups = true; @endphp
|
@php $hasProductGroups = true; @endphp
|
||||||
<h6 class="mb-2 mt-2 @if($hasIngredientGroups) ml-3 @else ml-1 @endif"><strong>{{ $selectedRecipePosition->product_group }}</strong></h6>
|
<h6
|
||||||
|
class="mb-2 mt-2 @if ($hasIngredientGroups) ml-3 @else ml-1 @endif">
|
||||||
|
<strong>{{ $selectedRecipePosition->product_group }}</strong>
|
||||||
|
</h6>
|
||||||
@endif
|
@endif
|
||||||
<li class="list-group-item px-0 @if($hasIngredientGroups && $hasProductGroups) ml-4 @elseif($hasIngredientGroups || $hasProductGroups) ml-2 @else ml-0 @endif">
|
<li
|
||||||
@if($selectedRecipePosition->product_active == 0)
|
class="list-group-item px-0 @if ($hasIngredientGroups && $hasProductGroups) ml-4 @elseif($hasIngredientGroups || $hasProductGroups) ml-2 @else ml-0 @endif">
|
||||||
<div class="small text-muted font-italic">{{ $__t('Disabled') }}</div>
|
@if ($selectedRecipePosition->product_active == 0)
|
||||||
|
<div class="small text-muted font-italic">
|
||||||
|
{{ $__t('Disabled') }}</div>
|
||||||
@endif
|
@endif
|
||||||
@php
|
@php
|
||||||
$product = FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id);
|
$product = FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id);
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
||||||
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $selectedRecipePosition->qu_id);
|
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $selectedRecipePosition->qu_id);
|
||||||
if ($productQuConversion && $selectedRecipePosition->only_check_single_unit_in_stock == 0)
|
if ($productQuConversion && $selectedRecipePosition->only_check_single_unit_in_stock == 0) {
|
||||||
{
|
|
||||||
$selectedRecipePosition->recipe_amount = $selectedRecipePosition->recipe_amount * $productQuConversion->factor;
|
$selectedRecipePosition->recipe_amount = $selectedRecipePosition->recipe_amount * $productQuConversion->factor;
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
@if(!empty($selectedRecipePosition->recipe_variable_amount))
|
@if (!empty($selectedRecipePosition->recipe_variable_amount))
|
||||||
{{ $selectedRecipePosition->recipe_variable_amount }}
|
{{ $selectedRecipePosition->recipe_variable_amount }}
|
||||||
@else
|
@else
|
||||||
<span class="locale-number locale-number-quantity-amount">@if($selectedRecipePosition->recipe_amount == round($selectedRecipePosition->recipe_amount, 2)){{ round($selectedRecipePosition->recipe_amount, 2) }}@else{{ $selectedRecipePosition->recipe_amount }}@endif</span>
|
<span class="locale-number locale-number-quantity-amount">
|
||||||
|
@if ($selectedRecipePosition->recipe_amount == round($selectedRecipePosition->recipe_amount, 2))
|
||||||
|
{{ round($selectedRecipePosition->recipe_amount, 2) }}@else{{ $selectedRecipePosition->recipe_amount }}
|
||||||
@endif
|
@endif
|
||||||
{{ $__n($selectedRecipePosition->recipe_amount, FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name_plural) }} {{ FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id)->name }}
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK)
|
|
||||||
<span class="d-print-none">
|
|
||||||
@if($selectedRecipePosition->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif($selectedRecipePosition->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
|
|
||||||
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->need_fulfilled == 1) {{ $__t('Enough in stock') }} @else {{ $__t('Not enough in stock, %1$s missing, %2$s already on shopping list', round($selectedRecipePosition->missing_amount, 2), round($selectedRecipePosition->amount_on_shopping_list, 2)) }} @endif</span>
|
|
||||||
</span>
|
</span>
|
||||||
@endif
|
@endif
|
||||||
@if($selectedRecipePosition->need_fulfilled == 1 && GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) <span class="float-right font-italic ml-2 locale-number locale-number-currency">{{ $selectedRecipePosition->costs }}</span> @endif
|
{{ $__n($selectedRecipePosition->recipe_amount,FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name,FindObjectInArrayByPropertyValue($quantityUnits, 'id', $selectedRecipePosition->qu_id)->name_plural) }}
|
||||||
<span class="float-right font-italic"><span class="locale-number locale-number-generic">{{ $selectedRecipePosition->calories }}</span> {{ $__t('Calories') }}</span>
|
{{ FindObjectInArrayByPropertyValue($products, 'id', $selectedRecipePosition->product_id)->name }}
|
||||||
@if(!empty($selectedRecipePosition->recipe_variable_amount))
|
@if (GROCY_FEATURE_FLAG_STOCK)
|
||||||
<div class="small text-muted font-italic">{{ $__t('Variable amount') }}</div>
|
<span class="d-print-none">
|
||||||
|
@if ($selectedRecipePosition->need_fulfilled == 1)
|
||||||
|
<i class="fas fa-check text-success"></i>
|
||||||
|
@elseif($selectedRecipePosition->need_fulfilled_with_shopping_list == 1)
|
||||||
|
<i
|
||||||
|
class="fas fa-exclamation text-warning"></i>@else<i
|
||||||
|
class="fas fa-times text-danger"></i>
|
||||||
|
@endif
|
||||||
|
<span class="timeago-contextual">
|
||||||
|
@if (FindObjectInArrayByPropertyValue($recipePositionsResolved, 'recipe_pos_id', $selectedRecipePosition->id)->need_fulfilled == 1)
|
||||||
|
{{ $__t('Enough in stock') }}
|
||||||
|
@else
|
||||||
|
{{ $__t('Not enough in stock, %1$s missing, %2$s already on shopping list',round($selectedRecipePosition->missing_amount, 2),round($selectedRecipePosition->amount_on_shopping_list, 2)) }}
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
@if ($selectedRecipePosition->need_fulfilled == 1 && GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
|
<span
|
||||||
|
class="float-right font-italic ml-2 locale-number locale-number-currency">{{ $selectedRecipePosition->costs }}</span>
|
||||||
|
@endif
|
||||||
|
<span class="float-right font-italic"><span
|
||||||
|
class="locale-number locale-number-generic">{{ $selectedRecipePosition->calories }}</span>
|
||||||
|
{{ $__t('Calories') }}</span>
|
||||||
|
@if (!empty($selectedRecipePosition->recipe_variable_amount))
|
||||||
|
<div class="small text-muted font-italic">
|
||||||
|
{{ $__t('Variable amount') }}</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(!empty($selectedRecipePosition->note))
|
@if (!empty($selectedRecipePosition->note))
|
||||||
<div class="text-muted">{!! nl2br($selectedRecipePosition->note) !!}</div>
|
<div class="text-muted">{!! nl2br($selectedRecipePosition->note) !!}</div>
|
||||||
@endif
|
@endif
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -496,13 +515,12 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="tab-pane @if(count($recipePositionsFiltered) == 0) active @endif"
|
<div class="tab-pane @if (count($recipePositionsFiltered) == 0) active @endif"
|
||||||
id="prep-{{ $index }}"
|
id="prep-{{ $index }}" role="tabpanel">
|
||||||
role="tabpanel">
|
|
||||||
<div class="mb-2 d-none d-print-block">
|
<div class="mb-2 d-none d-print-block">
|
||||||
<h3 class="mb-0">{{ $__t('Preparation') }}</h3>
|
<h3 class="mb-0">{{ $__t('Preparation') }}</h3>
|
||||||
</div>
|
</div>
|
||||||
@if(!empty($recipe->description))
|
@if (!empty($recipe->description))
|
||||||
{!! $recipe->description !!}
|
{!! $recipe->description !!}
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -510,16 +528,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="missing-recipe-pos-list"
|
<div id="missing-recipe-pos-list" class="list-group d-none mt-3">
|
||||||
class="list-group d-none mt-3">
|
@foreach ($recipePositionsResolved as $recipePos)
|
||||||
@foreach($recipePositionsResolved as $recipePos)
|
@if (in_array($recipePos->recipe_id, $includedRecipeIdsAbsolute) && $recipePos->missing_amount > 0)
|
||||||
@if(in_array($recipePos->recipe_id, $includedRecipeIdsAbsolute) && $recipePos->missing_amount > 0)
|
|
||||||
<a href="#"
|
<a href="#"
|
||||||
class="list-group-item list-group-item-action list-group-item-primary missing-recipe-pos-select-button">
|
class="list-group-item list-group-item-action list-group-item-primary missing-recipe-pos-select-button">
|
||||||
<div class="form-check form-check-inline">
|
<div class="form-check form-check-inline">
|
||||||
<input class="form-check-input missing-recipe-pos-product-checkbox"
|
<input class="form-check-input missing-recipe-pos-product-checkbox"
|
||||||
type="checkbox"
|
type="checkbox" data-product-id="{{ $recipePos->product_id }}"
|
||||||
data-product-id="{{ $recipePos->product_id }}"
|
|
||||||
checked>
|
checked>
|
||||||
</div>
|
</div>
|
||||||
{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePos->product_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePos->product_id)->name }}
|
||||||
|
|
@ -532,5 +548,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,23 @@
|
||||||
@section('viewJsName', 'shoppinglist')
|
@section('viewJsName', 'shoppinglist')
|
||||||
|
|
||||||
@push('pageScripts')
|
@push('pageScripts')
|
||||||
<script src="{{ $U('/node_modules/bwip-js/dist/bwip-js-min.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/node_modules/bwip-js/dist/bwip-js-min.js?v=', true) }}{{ $version }}">
|
||||||
<script src="{{ $U('/viewjs/purchase.js?v=', true) }}{{ $version }}"></script>
|
</script>
|
||||||
|
<script src="{{ $U('/viewjs/purchase.js?v=', true) }}{{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}" rel="stylesheet">
|
||||||
rel="stylesheet">
|
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row d-print-none hide-on-fullscreen-card">
|
<div class="row d-print-none hide-on-fullscreen-card">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title mr-2 order-0">
|
<h2 class="title mr-2 order-0">
|
||||||
@yield('title')
|
@yield('title')
|
||||||
</h2>
|
</h2>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
<h2 class="mb-0 mr-auto order-3 order-md-1 width-xs-sm-100">
|
<h2 class="mb-0 mr-auto order-3 order-md-1 width-xs-sm-100">
|
||||||
<span class="text-muted small">{!! $__t('%s total value', '<span class="locale-number locale-number-currency">' . SumArrayValue($listItems, 'last_price_total') . '</span>') !!}</span>
|
<span class="text-muted small">{!! $__t('%s total value', '<span class="locale-number locale-number-currency">' . SumArrayValue($listItems, 'last_price_total') . '</span>') !!}</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
@ -31,27 +31,23 @@
|
||||||
href="{{ $U('/shoppinglistitem/new?embedded&list=' . $selectedShoppingListId) }}">
|
href="{{ $U('/shoppinglistitem/new?embedded&list=' . $selectedShoppingListId) }}">
|
||||||
{{ $__t('Add item') }}
|
{{ $__t('Add item') }}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
@if (GROCY_FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS)
|
||||||
@if(GROCY_FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS)
|
|
||||||
<div class="my-auto float-right">
|
<div class="my-auto float-right">
|
||||||
<select class="custom-control custom-select custom-select-sm"
|
{{-- TODO: Select2: dynamic data: shopping_lists --}}
|
||||||
id="selected-shopping-list">
|
<select class="custom-control custom-select custom-select-sm" id="selected-shopping-list">
|
||||||
@foreach($shoppingLists as $shoppingList)
|
@foreach ($shoppingLists as $shoppingList)
|
||||||
<option @if($shoppingList->id == $selectedShoppingListId) selected="selected" @endif value="{{ $shoppingList->id }}">{{ $shoppingList->name }}</option>
|
<option @if ($shoppingList->id == $selectedShoppingListId) selected="selected" @endif
|
||||||
|
value="{{ $shoppingList->id }}">{{ $shoppingList->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -64,70 +60,63 @@
|
||||||
{{ $__t('Edit shopping list') }}
|
{{ $__t('Edit shopping list') }}
|
||||||
</a>
|
</a>
|
||||||
<a id="delete-selected-shopping-list"
|
<a id="delete-selected-shopping-list"
|
||||||
class="btn btn-outline-danger responsive-button m-1 mt-md-0 mb-md-0 float-right @if($selectedShoppingListId == 1) disabled @endif"
|
class="btn btn-outline-danger responsive-button m-1 mt-md-0 mb-md-0 float-right @if ($selectedShoppingListId == 1) disabled @endif"
|
||||||
href="#">
|
href="#">
|
||||||
{{ $__t('Delete shopping list') }}
|
{{ $__t('Delete shopping list') }}
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
<input type="hidden"
|
<input type="hidden" name="selected-shopping-list" id="selected-shopping-list" value="1">
|
||||||
name="selected-shopping-list"
|
|
||||||
id="selected-shopping-list"
|
|
||||||
value="1">
|
|
||||||
@endif
|
@endif
|
||||||
<a id="print-shopping-list-button"
|
<a id="print-shopping-list-button"
|
||||||
class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right" href="#">
|
||||||
href="#">
|
|
||||||
{{ $__t('Print') }}
|
{{ $__t('Print') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="filter-container"
|
<div id="filter-container" class="border-top border-bottom my-2 py-1">
|
||||||
class="border-top border-bottom my-2 py-1">
|
<div id="table-filter-row" data-status-filter="belowminstockamount"
|
||||||
<div id="table-filter-row"
|
class="collapse normal-message status-filter-message responsive-button @if (!GROCY_FEATURE_FLAG_STOCK) d-none @else d-md-inline-block @endif">
|
||||||
data-status-filter="belowminstockamount"
|
<span class="d-block d-md-none">{{ count($missingProducts) }} <i
|
||||||
class="collapse normal-message status-filter-message responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @else d-md-inline-block @endif"><span class="d-block d-md-none">{{count($missingProducts)}} <i class="fas fa-exclamation-circle"></i></span><span class="d-none d-md-block">{{ $__n(count($missingProducts), '%s product is below defined min. stock amount', '%s products are below defined min. stock amount') }}</span></div>
|
class="fas fa-exclamation-circle"></i></span><span
|
||||||
<div id="related-links"
|
class="d-none d-md-block">{{ $__n(count($missingProducts),'%s product is below defined min. stock amount','%s products are below defined min. stock amount') }}</span>
|
||||||
class="float-right mt-1 collapse d-md-block">
|
</div>
|
||||||
|
<div id="related-links" class="float-right mt-1 collapse d-md-block">
|
||||||
<a class="btn btn-primary responsive-button btn-sm mb-1 show-as-dialog-link d-none d-md-inline-block"
|
<a class="btn btn-primary responsive-button btn-sm mb-1 show-as-dialog-link d-none d-md-inline-block"
|
||||||
href="{{ $U('/shoppinglistitem/new?embedded&list=' . $selectedShoppingListId) }}">
|
href="{{ $U('/shoppinglistitem/new?embedded&list=' . $selectedShoppingListId) }}">
|
||||||
{{ $__t('Add item') }}
|
{{ $__t('Add item') }}
|
||||||
</a>
|
</a>
|
||||||
<a id="clear-shopping-list"
|
<a id="clear-shopping-list"
|
||||||
class="btn btn-outline-danger btn-sm mb-1 responsive-button @if($listItems->count() == 0) disabled @endif"
|
class="btn btn-outline-danger btn-sm mb-1 responsive-button @if ($listItems->count() == 0) disabled @endif"
|
||||||
href="#">
|
href="#">
|
||||||
{{ $__t('Clear list') }}
|
{{ $__t('Clear list') }}
|
||||||
</a>
|
</a>
|
||||||
<a id="add-all-items-to-stock-button"
|
<a id="add-all-items-to-stock-button"
|
||||||
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
||||||
href="#">
|
href="#">
|
||||||
{{ $__t('Add all list items to stock') }}
|
{{ $__t('Add all list items to stock') }}
|
||||||
</a>
|
</a>
|
||||||
<a id="add-products-below-min-stock-amount"
|
<a id="add-products-below-min-stock-amount"
|
||||||
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
||||||
href="#">
|
href="#">
|
||||||
{{ $__t('Add products that are below defined min. stock amount') }}
|
{{ $__t('Add products that are below defined min. stock amount') }}
|
||||||
</a>
|
</a>
|
||||||
<a id="add-overdue-expired-products"
|
<a id="add-overdue-expired-products"
|
||||||
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
||||||
href="#">
|
href="#">
|
||||||
{{ $__t('Add overdue/expired products') }}
|
{{ $__t('Add overdue/expired products') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row collapse d-md-flex d-print-none hide-on-fullscreen-card"
|
<div class="row collapse d-md-flex d-print-none hide-on-fullscreen-card" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-5">
|
<div class="col-12 col-md-5">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 col-lg-5">
|
<div class="col-12 col-md-4 col-lg-5">
|
||||||
|
|
@ -135,11 +124,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
id="status-filter">
|
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<option class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
<option class="@if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif" value="belowminstockamount">
|
||||||
value="belowminstockamount">{{ $__t('Below min. stock amount') }}</option>
|
{{ $__t('Below min. stock amount') }}</option>
|
||||||
<option value="xxDONExx">{{ $__t('Only done items') }}</option>
|
<option value="xxDONExx">{{ $__t('Only done items') }}</option>
|
||||||
<option value="xxUNDONExx">{{ $__t('Only undone items') }}</option>
|
<option value="xxUNDONExx">{{ $__t('Only undone items') }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -147,137 +135,147 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="shoppinglist-main"
|
<div id="shoppinglist-main" class="row d-print-none">
|
||||||
class="row d-print-none">
|
<div class="@if (boolval($userSettings['shopping_list_show_calendar'])) col-12 col-md-8 @else col-12 @endif pb-3">
|
||||||
<div class="@if(boolval($userSettings['shopping_list_show_calendar'])) col-12 col-md-8 @else col-12 @endif pb-3">
|
{{-- TODO: DataTables: dynamic data: shopping_lists --}}
|
||||||
<table id="shoppinglist-table"
|
<table id="shoppinglist-table" class="table table-sm table-striped nowrap w-100">
|
||||||
class="table table-sm table-striped nowrap w-100">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#shoppinglist-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#shoppinglist-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product') }} / <em>{{ $__t('Note') }}</em></th>
|
<th class="allow-grouping">{{ $__t('Product') }} / <em>{{ $__t('Note') }}</em></th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product group') }}</th>
|
<th class="allow-grouping">{{ $__t('Product group') }}</th>
|
||||||
<th class="d-none">Hidden status</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price (Unit)') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price (Unit)') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price (Total)') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price (Total)') }}
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">{{ $__t('Default store') }}</th>
|
</th>
|
||||||
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">
|
||||||
|
{{ $__t('Default store') }}</th>
|
||||||
<th>{{ $__t('Barcodes') }}</th>
|
<th>{{ $__t('Barcodes') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $productUserfields
|
'userfields' => $productUserfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($listItems as $listItem)
|
@foreach ($listItems as $listItem)
|
||||||
<tr id="shoppinglistitem-{{ $listItem->id }}-row"
|
<tr id="shoppinglistitem-{{ $listItem->id }}-row"
|
||||||
class="@if(FindObjectInArrayByPropertyValue($missingProducts, 'id', $listItem->product_id) !== null) table-info @endif @if($listItem->done == 1) text-muted text-strike-through @endif">
|
class="@if (FindObjectInArrayByPropertyValue($missingProducts, 'id', $listItem->product_id) !== null) table-info @endif @if ($listItem->done == 1) text-muted text-strike-through @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-success btn-sm order-listitem-button"
|
<a class="btn btn-success btn-sm order-listitem-button" href="#"
|
||||||
href="#"
|
data-item-id="{{ $listItem->id }}" data-item-done="{{ $listItem->done }}"
|
||||||
data-item-id="{{ $listItem->id }}"
|
data-toggle="tooltip" data-placement="right"
|
||||||
data-item-done="{{ $listItem->done }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="right"
|
|
||||||
title="{{ $__t('Mark this item as done') }}">
|
title="{{ $__t('Mark this item as done') }}">
|
||||||
<i class="fas fa-check"></i>
|
<i class="fas fa-check"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-info show-as-dialog-link"
|
<a class="btn btn-sm btn-info show-as-dialog-link"
|
||||||
href="{{ $U('/shoppinglistitem/' . $listItem->id . '?embedded&list=' . $selectedShoppingListId ) }}"
|
href="{{ $U('/shoppinglistitem/' . $listItem->id . '?embedded&list=' . $selectedShoppingListId) }}"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-placement="right" title="{{ $__t('Edit this item') }}">
|
||||||
data-placement="right"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-danger shoppinglist-delete-button"
|
<a class="btn btn-sm btn-danger shoppinglist-delete-button" href="#"
|
||||||
href="#"
|
data-shoppinglist-id="{{ $listItem->id }}" data-toggle="tooltip"
|
||||||
data-shoppinglist-id="{{ $listItem->id }}"
|
data-placement="right" title="{{ $__t('Delete this item') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="right"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-primary @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif @if(empty($listItem->product_id)) disabled @else shopping-list-stock-add-workflow-list-item-button @endif"
|
<a class="btn btn-sm btn-primary @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif @if (empty($listItem->product_id)) disabled @else shopping-list-stock-add-workflow-list-item-button @endif"
|
||||||
href="{{ $U('/purchase?embedded&flow=shoppinglistitemtostock&product=') }}{{ $listItem->product_id }}&amount={{ $listItem->amount }}&listitemid={{ $listItem->id }}&quId={{ $listItem->qu_id }}"
|
href="{{ $U('/purchase?embedded&flow=shoppinglistitemtostock&product=') }}{{ $listItem->product_id }}&amount={{ $listItem->amount }}&listitemid={{ $listItem->id }}&quId={{ $listItem->qu_id }}"
|
||||||
@if(!empty($listItem->product_id)) data-toggle="tooltip" title="{{ $__t('Add this item to stock') }}" @endif>
|
@if (!empty($listItem->product_id)) data-toggle="tooltip" title="{{ $__t('Add this item to stock') }}" @endif>
|
||||||
<i class="fas fa-box"></i>
|
<i class="fas fa-box"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="product-name-cell cursor-link"
|
<td class="product-name-cell cursor-link" data-product-id="{{ $listItem->product_id }}">
|
||||||
data-product-id="{{ $listItem->product_id }}">
|
@if (!empty($listItem->product_id))
|
||||||
@if(!empty($listItem->product_id)) {{ $listItem->product_name }}<br>@endif<em>{!! nl2br($listItem->note) !!}</em>
|
{{ $listItem->product_name }}<br>
|
||||||
|
@endif
|
||||||
|
<em>
|
||||||
|
{!! nl2br($listItem->note) !!}</em>
|
||||||
</td>
|
</td>
|
||||||
@if(!empty($listItem->product_id))
|
@if (!empty($listItem->product_id))
|
||||||
@php
|
@php
|
||||||
$listItem->amount_origin_qu = $listItem->amount;
|
$listItem->amount_origin_qu = $listItem->amount;
|
||||||
$product = FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id);
|
$product = FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id);
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
||||||
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $listItem->qu_id);
|
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $listItem->qu_id);
|
||||||
if ($productQuConversion)
|
if ($productQuConversion) {
|
||||||
{
|
|
||||||
$listItem->amount = $listItem->amount * $productQuConversion->factor;
|
$listItem->amount = $listItem->amount * $productQuConversion->factor;
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
@endif
|
@endif
|
||||||
<td data-order={{
|
<td data-order={{ <td data-order=$listItem->amount }}>
|
||||||
$listItem->amount }}>
|
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}@endif
|
@if (!empty($listItem->product_id))
|
||||||
|
{{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else <span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span> @endif
|
@if (!empty($listItem->product_group_name))
|
||||||
|
{{ $listItem->product_group_name }}
|
||||||
|
@else
|
||||||
|
<span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td id="shoppinglistitem-{{ $listItem->id }}-status-info"
|
<td id="shoppinglistitem-{{ $listItem->id }}-status-info" class="d-none">
|
||||||
class="d-none">
|
@if (FindObjectInArrayByPropertyValue($missingProducts, 'id', $listItem->product_id) !== null)
|
||||||
@if(FindObjectInArrayByPropertyValue($missingProducts, 'id', $listItem->product_id) !== null) belowminstockamount @endif
|
belowminstockamount
|
||||||
@if($listItem->done == 1) xxDONExx @else xxUNDONExx @endif
|
@endif
|
||||||
|
@if ($listItem->done == 1)
|
||||||
|
xxDONExx
|
||||||
|
@else
|
||||||
|
xxUNDONExx
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
||||||
<span class="locale-number locale-number-currency">{{ $listItem->last_price_unit }}</span>
|
<span
|
||||||
|
class="locale-number locale-number-currency">{{ $listItem->last_price_unit }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
||||||
<span class="locale-number locale-number-currency">{{ $listItem->last_price_total }}</span>
|
<span
|
||||||
|
class="locale-number locale-number-currency">{{ $listItem->last_price_total }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
||||||
{{ $listItem->default_shopping_location_name }}
|
{{ $listItem->default_shopping_location_name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@foreach(explode(',', $listItem->product_barcodes) as $barcode)
|
@foreach (explode(',', $listItem->product_barcodes) as $barcode)
|
||||||
@if(!empty($barcode))
|
@if (!empty($barcode))
|
||||||
<img class="barcode img-fluid pr-2"
|
<img class="barcode img-fluid pr-2" data-barcode="{{ $barcode }}">
|
||||||
data-barcode="{{ $barcode }}">
|
|
||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $listItem->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
@include('components.userfields_tbody', array(
|
'object_id',
|
||||||
|
$listItem->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $productUserfields,
|
'userfields' => $productUserfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($productUserfieldValues, 'object_id', $listItem->product_id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$productUserfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$listItem->product_id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
@ -285,62 +283,48 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(boolval($userSettings['shopping_list_show_calendar']))
|
@if (boolval($userSettings['shopping_list_show_calendar']))
|
||||||
<div class="col-12 col-md-4 mt-md-2 d-print-none">
|
<div class="col-12 col-md-4 mt-md-2 d-print-none">
|
||||||
@include('components.calendarcard')
|
@include('components.calendarcard')
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="@if(boolval($userSettings['shopping_list_show_calendar'])) col-12 col-md-8 @else col-12 @endif d-print-none pt-2">
|
<div class="@if (boolval($userSettings['shopping_list_show_calendar'])) col-12 col-md-8 @else col-12 @endif d-print-none pt-2">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="text-larger font-weight-bold"
|
<label class="text-larger font-weight-bold" for="notes">{{ $__t('Notes') }}</label>
|
||||||
for="notes">{{ $__t('Notes') }}</label>
|
<a id="save-description-button" class="btn btn-success btn-sm ml-1 mb-2" href="#">{{ $__t('Save') }}</a>
|
||||||
<a id="save-description-button"
|
<a id="clear-description-button" class="btn btn-danger btn-sm ml-1 mb-2" href="#">{{ $__t('Clear') }}</a>
|
||||||
class="btn btn-success btn-sm ml-1 mb-2"
|
<textarea class="form-control wysiwyg-editor" id="description"
|
||||||
href="#">{{ $__t('Save') }}</a>
|
|
||||||
<a id="clear-description-button"
|
|
||||||
class="btn btn-danger btn-sm ml-1 mb-2"
|
|
||||||
href="#">{{ $__t('Clear') }}</a>
|
|
||||||
<textarea class="form-control wysiwyg-editor"
|
|
||||||
id="description"
|
|
||||||
name="description">{{ FindObjectInArrayByPropertyValue($shoppingLists, 'id', $selectedShoppingListId)->description }}</textarea>
|
name="description">{{ FindObjectInArrayByPropertyValue($shoppingLists, 'id', $selectedShoppingListId)->description }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="shopping-list-stock-add-workflow-modal" tabindex="-1">
|
||||||
id="shopping-list-stock-add-workflow-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<iframe id="shopping-list-stock-add-workflow-purchase-form-frame"
|
<iframe id="shopping-list-stock-add-workflow-purchase-form-frame" class="embed-responsive"
|
||||||
class="embed-responsive"
|
|
||||||
src=""></iframe>
|
src=""></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<span id="shopping-list-stock-add-workflow-purchase-item-count"
|
<span id="shopping-list-stock-add-workflow-purchase-item-count" class="d-none mr-auto"></span>
|
||||||
class="d-none mr-auto"></span>
|
<button id="shopping-list-stock-add-workflow-skip-button" type="button"
|
||||||
<button id="shopping-list-stock-add-workflow-skip-button"
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary">{{ $__t('Skip') }}</button>
|
class="btn btn-primary">{{ $__t('Skip') }}</button>
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-none d-print-block">
|
<div class="d-none d-print-block">
|
||||||
<div id="print-header">
|
<div id="print-header">
|
||||||
<h1 class="text-center">
|
<h1 class="text-center">
|
||||||
<img src="{{ $U('/img/grocy_logo.svg?v=', true) }}{{ $version }}"
|
<img src="{{ $U('/img/grocy_logo.svg?v=', true) }}{{ $version }}" height="30"
|
||||||
height="30"
|
|
||||||
class="d-print-flex mx-auto">
|
class="d-print-flex mx-auto">
|
||||||
{{ $__t("Shopping list") }}
|
{{ $__t('Shopping list') }}
|
||||||
</h1>
|
</h1>
|
||||||
@if (FindObjectInArrayByPropertyValue($shoppingLists, 'id', $selectedShoppingListId)->name != $__t("Shopping list"))
|
@if (FindObjectInArrayByPropertyValue($shoppingLists, 'id', $selectedShoppingListId)->name != $__t('Shopping list'))
|
||||||
<h3 class="text-center">
|
<h3 class="text-center">
|
||||||
{{ FindObjectInArrayByPropertyValue($shoppingLists, 'id', $selectedShoppingListId)->name }}
|
{{ FindObjectInArrayByPropertyValue($shoppingLists, 'id', $selectedShoppingListId)->name }}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
@ -352,44 +336,64 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="w-75 print-layout-container print-layout-type-table d-none">
|
<div class="w-75 print-layout-container print-layout-type-table d-none">
|
||||||
<div>
|
<div>
|
||||||
<table id="shopping-list-print-shadow-table"
|
{{-- TODO: DataTables: dynamic data: uihelper_shopping_list --}}
|
||||||
class="table table-sm table-striped nowrap">
|
<table id="shopping-list-print-shadow-table" class="table table-sm table-striped nowrap">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ $__t('Product') }} / <em>{{ $__t('Note') }}</em></th>
|
<th>{{ $__t('Product') }} / <em>{{ $__t('Note') }}</em></th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th>{{ $__t('Product group') }}</th>
|
<th>{{ $__t('Product group') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $productUserfields
|
'userfields' => $productUserfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach($listItems as $listItem)
|
@foreach ($listItems as $listItem)
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
@if(!empty($listItem->product_id)) {{ $listItem->product_name }}<br>@endif<em>{!! nl2br($listItem->note) !!}</em>
|
@if (!empty($listItem->product_id))
|
||||||
|
{{ $listItem->product_name }}<br>
|
||||||
|
@endif
|
||||||
|
<em>
|
||||||
|
{!! nl2br($listItem->note) !!}</em>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}@endif
|
<span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span>
|
||||||
|
@if (!empty($listItem->product_id))
|
||||||
|
{{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else <span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span> @endif
|
@if (!empty($listItem->product_group_name))
|
||||||
|
{{ $listItem->product_group_name }}
|
||||||
|
@else
|
||||||
|
<span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $listItem->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
@include('components.userfields_tbody', array(
|
'object_id',
|
||||||
|
$listItem->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $productUserfields,
|
'userfields' => $productUserfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($productUserfieldValues, 'object_id', $listItem->product_id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$productUserfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$listItem->product_id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
@ -398,10 +402,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-75 print-layout-container print-layout-type-list d-none">
|
<div class="w-75 print-layout-container print-layout-type-list d-none">
|
||||||
@foreach($listItems as $listItem)
|
@foreach ($listItems as $listItem)
|
||||||
<div class="py-0">
|
<div class="py-0">
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}@endif
|
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span>
|
||||||
@if(!empty($listItem->product_id)) {{ $listItem->product_name }}<br>@endif<em>{!! nl2br($listItem->note) !!}</em>
|
@if (!empty($listItem->product_id))
|
||||||
|
{{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}
|
||||||
|
@endif
|
||||||
|
@if (!empty($listItem->product_id))
|
||||||
|
{{ $listItem->product_name }}<br>
|
||||||
|
@endif
|
||||||
|
<em>{!! nl2br($listItem->note) !!}</em>
|
||||||
</div><br>
|
</div><br>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -411,21 +421,17 @@
|
||||||
<p id="description-for-print"></p>
|
<p id="description-for-print"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="shoppinglist-productcard-modal" tabindex="-1">
|
||||||
id="shoppinglist-productcard-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@include('components.productcard')
|
@include('components.productcard')
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -1,101 +1,112 @@
|
||||||
@extends('layout.default')
|
@extends('layout.default')
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
@section('title', $__t('Edit shopping list item'))
|
@section('title', $__t('Edit shopping list item'))
|
||||||
@else
|
@else
|
||||||
@section('title', $__t('Create shopping list item'))
|
@section('title', $__t('Create shopping list item'))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@section('viewJsName', 'shoppinglistitemform')
|
@section('viewJsName', 'shoppinglistitemform')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<script>
|
<script>
|
||||||
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
||||||
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditMode = '{{ $mode }}';
|
Grocy.EditMode = '{{ $mode }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditObjectId = {{ $listItem->id }};
|
Grocy.EditObjectId = {{ $listItem->id }};
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form id="shoppinglist-form"
|
<form id="shoppinglist-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS)
|
@if (GROCY_FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="shopping_list_id">{{ $__t('Shopping list') }}</label>
|
<label for="shopping_list_id">{{ $__t('Shopping list') }}</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: shopping_lists --}}
|
||||||
id="shopping_list_id"
|
<select class="custom-control custom-select" id="shopping_list_id" name="shopping_list_id">
|
||||||
name="shopping_list_id">
|
@foreach ($shoppingLists as $shoppingList)
|
||||||
@foreach($shoppingLists as $shoppingList)
|
<option @if ($mode == 'edit' && $shoppingList->id == $listItem->shopping_list_id) selected="selected" @endif
|
||||||
<option @if($mode=='edit'
|
value="{{ $shoppingList->id }}">{{ $shoppingList->name }}</option>
|
||||||
&&
|
|
||||||
$shoppingList->id == $listItem->shopping_list_id) selected="selected" @endif value="{{ $shoppingList->id }}">{{ $shoppingList->name }}</option>
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<input type="hidden"
|
<input type="hidden" id="shopping_list_id" name="shopping_list_id" value="1">
|
||||||
id="shopping_list_id"
|
|
||||||
name="shopping_list_id"
|
|
||||||
value="1">
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@php if($mode == 'edit') { $productId = $listItem->product_id; } else { $productId = ''; } @endphp
|
@php
|
||||||
@include('components.productpicker', array(
|
if ($mode == 'edit') {
|
||||||
'products' => $products,
|
$productId = $listItem->product_id;
|
||||||
|
} else {
|
||||||
|
$productId = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('components.productpicker', [
|
||||||
|
'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase',
|
||||||
'nextInputSelector' => '#amount',
|
'nextInputSelector' => '#amount',
|
||||||
'isRequired' => true,
|
'isRequired' => true,
|
||||||
'prefillById' => $productId,
|
'prefillById' => $productId,
|
||||||
'validationMessage' => 'A product or a note is required'
|
'validationMessage' => 'A product or a note is required',
|
||||||
))
|
])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $listItem->amount; } else { $value = 1; } @endphp
|
@php
|
||||||
@php if($mode == 'edit') { $initialQuId = $listItem->qu_id; } else { $initialQuId = ''; } @endphp
|
if ($mode == 'edit') {
|
||||||
@include('components.productamountpicker', array(
|
$value = $listItem->amount;
|
||||||
|
} else {
|
||||||
|
$value = 1;
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@php
|
||||||
|
if ($mode == 'edit') {
|
||||||
|
$initialQuId = $listItem->qu_id;
|
||||||
|
} else {
|
||||||
|
$initialQuId = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('components.productamountpicker', [
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'initialQuId' => $initialQuId,
|
'initialQuId' => $initialQuId,
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
'isRequired' => false
|
'isRequired' => false,
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="note">{{ $__t('Note') }}</label>
|
<label for="note">{{ $__t('Note') }}</label>
|
||||||
<textarea class="form-control"
|
<textarea class="form-control" required rows="10" id="note" name="note">
|
||||||
required
|
@if ($mode == 'edit')
|
||||||
rows="10"
|
{{ $listItem->note }}
|
||||||
id="note"
|
@endif
|
||||||
name="note">@if($mode == 'edit'){{ $listItem->note }}@endif</textarea>
|
</textarea>
|
||||||
<div class="invalid-feedback">{{ $__t('A product or a note is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A product or a note is required') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@include('components.userfieldsform', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'entity' => 'shopping_list'
|
'entity' => 'shopping_list',
|
||||||
))
|
])
|
||||||
|
|
||||||
<button id="save-shoppinglist-button"
|
<button id="save-shoppinglist-button" class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,21 @@
|
||||||
@section('viewJsName', 'shoppinglocations')
|
@section('viewJsName', 'shoppinglocations')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
href="{{ $U('/shoppinglocation/new?embedded') }}">
|
href="{{ $U('/shoppinglocation/new?embedded') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
|
|
@ -36,71 +31,59 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="shoppinglocations-table"
|
{{-- TODO: DataTables: dynamic data: shopping_locations --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="shoppinglocations-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#shoppinglocations-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#shoppinglocations-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Description') }}</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($shoppinglocations as $shoppinglocation)
|
@foreach ($shoppinglocations as $shoppinglocation)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/shoppinglocation/') }}{{ $shoppinglocation->id }}?embedded"
|
href="{{ $U('/shoppinglocation/') }}{{ $shoppinglocation->id }}?embedded"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm shoppinglocation-delete-button"
|
<a class="btn btn-danger btn-sm shoppinglocation-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-shoppinglocation-id="{{ $shoppinglocation->id }}"
|
data-shoppinglocation-id="{{ $shoppinglocation->id }}"
|
||||||
data-shoppinglocation-name="{{ $shoppinglocation->name }}"
|
data-shoppinglocation-name="{{ $shoppinglocation->name }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -112,15 +95,19 @@
|
||||||
{{ $shoppinglocation->description }}
|
{{ $shoppinglocation->description }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $shoppinglocation->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$shoppinglocation->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -4,269 +4,239 @@
|
||||||
@section('viewJsName', 'stockentries')
|
@section('viewJsName', 'stockentries')
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}" rel="stylesheet">
|
||||||
rel="stylesheet">
|
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@push('pageScripts')
|
@push('pageScripts')
|
||||||
<script src="{{ $U('/viewjs/purchase.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/viewjs/purchase.js?v=', true) }}{{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button" data-toggle="collapse"
|
||||||
type="button"
|
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
data-target="#table-filter-row">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', [
|
||||||
'products' => $products,
|
'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase',
|
||||||
'disallowAllProductWorkflows' => true,
|
'disallowAllProductWorkflows' => true,
|
||||||
'isRequired' => false
|
'isRequired' => false,
|
||||||
))
|
])
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right mt-3">
|
<div class="float-right mt-3">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="stockentries-table"
|
{{-- TODO: DataTables: dynamic data: stock --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="stockentries-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#stockentries-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#stockentries-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th class="d-none">Hidden product_id</th> <!-- This must be in the first column for searching -->
|
<th class="d-none">Hidden product_id</th>
|
||||||
|
<!-- This must be in the first column for searching -->
|
||||||
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif allow-grouping">{{ $__t('Due date') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif allow-grouping">{{ $__t('Due date') }}
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}</th>
|
</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">{{ $__t('Store') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Price') }}</th>
|
</th>
|
||||||
<th class="allow-grouping"
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">{{ $__t('Store') }}
|
||||||
data-shadow-rowgroup-column="9">{{ $__t('Purchased date') }}</th>
|
</th>
|
||||||
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Price') }}</th>
|
||||||
|
<th class="allow-grouping" data-shadow-rowgroup-column="9">{{ $__t('Purchased date') }}</th>
|
||||||
<th class="d-none">Hidden purchased_date</th>
|
<th class="d-none">Hidden purchased_date</th>
|
||||||
<th>{{ $__t('Timestamp') }}</th>
|
<th>{{ $__t('Timestamp') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($stockEntries as $stockEntry)
|
@foreach ($stockEntries as $stockEntry)
|
||||||
<tr id="stock-{{ $stockEntry->id }}-row"
|
<tr id="stock-{{ $stockEntry->id }}-row"
|
||||||
data-due-type="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->due_type }}"
|
data-due-type="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->due_type }}"
|
||||||
class="@if(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $stockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $stockEntry->amount > 0) @if(FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->due_type == 1) table-secondary @else table-danger @endif @elseif(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $stockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('+' . $nextXDays . ' days'))
|
class="@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $stockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $stockEntry->amount > 0) @if (FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->due_type == 1) table-secondary @else table-danger @endif
|
||||||
&&
|
@elseif(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $stockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('+' . $nextXDays . ' days')) && $stockEntry->amount > 0)
|
||||||
$stockEntry->amount > 0) table-warning @endif">
|
table-warning @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-danger btn-sm stock-consume-button"
|
<a class="btn btn-danger btn-sm stock-consume-button" href="#" data-toggle="tooltip"
|
||||||
href="#"
|
data-placement="left" title="{{ $__t('Consume this stock entry') }}"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Consume this stock entry') }}"
|
|
||||||
data-product-id="{{ $stockEntry->product_id }}"
|
data-product-id="{{ $stockEntry->product_id }}"
|
||||||
data-stock-id="{{ $stockEntry->stock_id }}"
|
data-stock-id="{{ $stockEntry->stock_id }}"
|
||||||
data-stockrow-id="{{ $stockEntry->id }}"
|
data-stockrow-id="{{ $stockEntry->id }}"
|
||||||
data-location-id="{{ $stockEntry->location_id }}"
|
data-location-id="{{ $stockEntry->location_id }}"
|
||||||
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
||||||
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
||||||
data-consume-amount="{{ $stockEntry->amount }}">
|
data-consume-amount="{{ $stockEntry->amount }}">
|
||||||
<i class="fas fa-utensils"></i>
|
<i class="fas fa-utensils"></i>
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
||||||
<a class="btn btn-success btn-sm product-open-button @if($stockEntry->open == 1 || FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->enable_tare_weight_handling == 1) disabled @endif"
|
<a class="btn btn-success btn-sm product-open-button @if ($stockEntry->open == 1 || FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->enable_tare_weight_handling == 1) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Mark this stock entry as open') }}"
|
title="{{ $__t('Mark this stock entry as open') }}"
|
||||||
data-product-id="{{ $stockEntry->product_id }}"
|
data-product-id="{{ $stockEntry->product_id }}"
|
||||||
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
||||||
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
||||||
data-stock-id="{{ $stockEntry->stock_id }}"
|
data-stock-id="{{ $stockEntry->stock_id }}"
|
||||||
data-stockrow-id="{{ $stockEntry->id }}">
|
data-stockrow-id="{{ $stockEntry->id }}">
|
||||||
<i class="fas fa-box-open"></i>
|
<i class="fas fa-box-open"></i>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/stockentry/' . $stockEntry->id . '?embedded') }}"
|
href="{{ $U('/stockentry/' . $stockEntry->id . '?embedded') }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
data-placement="left" title="{{ $__t('Edit stock entry') }}">
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Edit stock entry') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
@if(GROCY_FEATURE_FLAG_SHOPPINGLIST)
|
@if (GROCY_FEATURE_FLAG_SHOPPINGLIST)
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
href="{{ $U('/shoppinglistitem/new?embedded&updateexistingproduct&product=' . $stockEntry->product_id) }}">
|
||||||
href="{{ $U('/shoppinglistitem/new?embedded&updateexistingproduct&product=' . $stockEntry->product_id ) }}">
|
|
||||||
<i class="fas fa-shopping-cart"></i> {{ $__t('Add to shopping list') }}
|
<i class="fas fa-shopping-cart"></i> {{ $__t('Add to shopping list') }}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
@endif
|
@endif
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
href="{{ $U('/purchase?embedded&product=' . $stockEntry->product_id) }}">
|
||||||
href="{{ $U('/purchase?embedded&product=' . $stockEntry->product_id ) }}">
|
|
||||||
<i class="fas fa-cart-plus"></i> {{ $__t('Purchase') }}
|
<i class="fas fa-cart-plus"></i> {{ $__t('Purchase') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
href="{{ $U('/consume?embedded&product=' .$stockEntry->product_id .'&locationId=' .$stockEntry->location_id .'&stockId=' .$stockEntry->stock_id) }}">
|
||||||
href="{{ $U('/consume?embedded&product=' . $stockEntry->product_id . '&locationId=' . $stockEntry->location_id . '&stockId=' . $stockEntry->stock_id) }}">
|
|
||||||
<i class="fas fa-utensils"></i> {{ $__t('Consume') }}
|
<i class="fas fa-utensils"></i> {{ $__t('Consume') }}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
href="{{ $U('/transfer?embedded&product=' .$stockEntry->product_id .'&locationId=' .$stockEntry->location_id .'&stockId=' .$stockEntry->stock_id) }}">
|
||||||
href="{{ $U('/transfer?embedded&product=' . $stockEntry->product_id . '&locationId=' . $stockEntry->location_id . '&stockId=' . $stockEntry->stock_id) }}">
|
|
||||||
<i class="fas fa-exchange-alt"></i> {{ $__t('Transfer') }}
|
<i class="fas fa-exchange-alt"></i> {{ $__t('Transfer') }}
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
href="{{ $U('/inventory?embedded&product=' . $stockEntry->product_id) }}">
|
||||||
href="{{ $U('/inventory?embedded&product=' . $stockEntry->product_id ) }}">
|
|
||||||
<i class="fas fa-list"></i> {{ $__t('Inventory') }}
|
<i class="fas fa-list"></i> {{ $__t('Inventory') }}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item stock-consume-button stock-consume-button-spoiled"
|
<a class="dropdown-item stock-consume-button stock-consume-button-spoiled"
|
||||||
type="button"
|
type="button" href="#" data-product-id="{{ $stockEntry->product_id }}"
|
||||||
href="#"
|
|
||||||
data-product-id="{{ $stockEntry->product_id }}"
|
|
||||||
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
||||||
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
||||||
data-stock-id="{{ $stockEntry->stock_id }}"
|
data-stock-id="{{ $stockEntry->stock_id }}"
|
||||||
data-stockrow-id="{{ $stockEntry->id }}"
|
data-stockrow-id="{{ $stockEntry->id }}"
|
||||||
data-location-id="{{ $stockEntry->location_id }}"
|
data-location-id="{{ $stockEntry->location_id }}" data-consume-amount="1">
|
||||||
data-consume-amount="1">
|
{{ $__t('Consume this stock entry as spoiled','1 ' .FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name,FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name) }}
|
||||||
{{ $__t('Consume this stock entry as spoiled', '1 ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name) }}
|
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_RECIPES)
|
@if (GROCY_FEATURE_FLAG_RECIPES)
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/recipes?search=') }}{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}">
|
href="{{ $U('/recipes?search=') }}{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}">
|
||||||
{{ $__t('Search for recipes containing this product') }}
|
{{ $__t('Search for recipes containing this product') }}
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item product-name-cell"
|
<a class="dropdown-item product-name-cell"
|
||||||
data-product-id="{{ $stockEntry->product_id }}"
|
data-product-id="{{ $stockEntry->product_id }}" type="button" href="#">
|
||||||
type="button"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Product overview') }}
|
{{ $__t('Product overview') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/stockjournal?embedded&product=') }}{{ $stockEntry->product_id }}">
|
href="{{ $U('/stockjournal?embedded&product=') }}{{ $stockEntry->product_id }}">
|
||||||
{{ $__t('Stock journal') }}
|
{{ $__t('Stock journal') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/stockjournal/summary?embedded&product=') }}{{ $stockEntry->product_id }}">
|
href="{{ $U('/stockjournal/summary?embedded&product=') }}{{ $stockEntry->product_id }}">
|
||||||
{{ $__t('Stock journal summary') }}
|
{{ $__t('Stock journal summary') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item link-return"
|
<a class="dropdown-item link-return" type="button"
|
||||||
type="button"
|
|
||||||
data-href="{{ $U('/product/') }}{{ $stockEntry->product_id }}">
|
data-href="{{ $U('/product/') }}{{ $stockEntry->product_id }}">
|
||||||
{{ $__t('Edit product') }}
|
{{ $__t('Edit product') }}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/stockentry/' . $stockEntry->id . '/grocycode?download=true') }}">
|
href="{{ $U('/stockentry/' . $stockEntry->id . '/grocycode?download=true') }}">
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Stock entry'))) !!}
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Stock entry'))) !!}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
<a class="dropdown-item stockentry-grocycode-label-print"
|
<a class="dropdown-item stockentry-grocycode-label-print"
|
||||||
data-stock-id="{{ $stockEntry->id }}"
|
data-stock-id="{{ $stockEntry->id }}" type="button" href="#">
|
||||||
type="button"
|
|
||||||
href="#">
|
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Stock entry'))) !!}
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Stock entry'))) !!}
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<a class="dropdown-item stockentry-label-link"
|
<a class="dropdown-item stockentry-label-link" type="button" target="_blank"
|
||||||
type="button"
|
|
||||||
target="_blank"
|
|
||||||
href="{{ $U('/stockentry/' . $stockEntry->id . '/label') }}">
|
href="{{ $U('/stockentry/' . $stockEntry->id . '/label') }}">
|
||||||
{{ $__t('Open stock entry label in new window') }}
|
{{ $__t('Open stock entry label in new window') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none"
|
<td class="d-none" data-product-id="{{ $stockEntry->product_id }}">
|
||||||
data-product-id="{{ $stockEntry->product_id }}">
|
|
||||||
{{ $stockEntry->product_id }}
|
{{ $stockEntry->product_id }}
|
||||||
</td>
|
</td>
|
||||||
<td class="product-name-cell cursor-link"
|
<td class="product-name-cell cursor-link" data-product-id="{{ $stockEntry->product_id }}">
|
||||||
data-product-id="{{ $stockEntry->product_id }}">
|
|
||||||
{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}
|
||||||
</td>
|
</td>
|
||||||
<td data-order="{{ $stockEntry->amount }}">
|
<td data-order="{{ $stockEntry->amount }}">
|
||||||
<span id="stock-{{ $stockEntry->id }}-amount"
|
<span id="stock-{{ $stockEntry->id }}-amount"
|
||||||
class="locale-number locale-number-quantity-amount">{{ $stockEntry->amount }}</span> <span id="product-{{ $stockEntry->product_id }}-qu-name">{{ $__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) }}</span>
|
class="locale-number locale-number-quantity-amount">{{ $stockEntry->amount }}</span>
|
||||||
<span id="stock-{{ $stockEntry->id }}-opened-amount"
|
<span
|
||||||
class="small font-italic">@if($stockEntry->open == 1){{ $__t('Opened') }}@endif</span>
|
id="product-{{ $stockEntry->product_id }}-qu-name">{{ $__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) }}</span>
|
||||||
|
<span id="stock-{{ $stockEntry->id }}-opened-amount" class="small font-italic">
|
||||||
|
@if ($stockEntry->open == 1)
|
||||||
|
{{ $__t('Opened') }}@endif
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
|
||||||
<span id="stock-{{ $stockEntry->id }}-due-date">{{ $stockEntry->best_before_date }}</span>
|
<span
|
||||||
|
id="stock-{{ $stockEntry->id }}-due-date">{{ $stockEntry->best_before_date }}</span>
|
||||||
<time id="stock-{{ $stockEntry->id }}-due-date-timeago"
|
<time id="stock-{{ $stockEntry->id }}-due-date-timeago"
|
||||||
class="timeago timeago-contextual"
|
class="timeago timeago-contextual"
|
||||||
@if($stockEntry->best_before_date != "") datetime="{{ $stockEntry->best_before_date }} 23:59:59" @endif></time>
|
@if ($stockEntry->best_before_date != '') datetime="{{ $stockEntry->best_before_date }} 23:59:59" @endif></time>
|
||||||
</td>
|
</td>
|
||||||
<td id="stock-{{ $stockEntry->id }}-location"
|
<td id="stock-{{ $stockEntry->id }}-location"
|
||||||
class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif"
|
class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif"
|
||||||
data-location-id="{{ $stockEntry->location_id }}">
|
data-location-id="{{ $stockEntry->location_id }}">
|
||||||
{{ FindObjectInArrayByPropertyValue($locations, 'id', $stockEntry->location_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($locations, 'id', $stockEntry->location_id)->name }}
|
||||||
</td>
|
</td>
|
||||||
<td id="stock-{{ $stockEntry->id }}-shopping-location"
|
<td id="stock-{{ $stockEntry->id }}-shopping-location"
|
||||||
class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif"
|
class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif"
|
||||||
data-shopping-location-id="{{ $stockEntry->shopping_location_id }}">
|
data-shopping-location-id="{{ $stockEntry->shopping_location_id }}">
|
||||||
@if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id) !== null)
|
@if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id) !== null)
|
||||||
{{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id)->name }}
|
{{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id)->name }}
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td id="stock-{{ $stockEntry->id }}-price"
|
<td id="stock-{{ $stockEntry->id }}-price"
|
||||||
class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif"
|
class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif"
|
||||||
class="locale-number locale-number-currency"
|
class="locale-number locale-number-currency" data-price-id="{{ $stockEntry->price }}">
|
||||||
data-price-id="{{ $stockEntry->price }}">
|
|
||||||
{{ $stockEntry->price }}
|
{{ $stockEntry->price }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span id="stock-{{ $stockEntry->id }}-purchased-date">{{ $stockEntry->purchased_date }}</span>
|
<span
|
||||||
|
id="stock-{{ $stockEntry->id }}-purchased-date">{{ $stockEntry->purchased_date }}</span>
|
||||||
<time id="stock-{{ $stockEntry->id }}-purchased-date-timeago"
|
<time id="stock-{{ $stockEntry->id }}-purchased-date-timeago"
|
||||||
class="timeago timeago-contextual"
|
class="timeago timeago-contextual"
|
||||||
@if(!empty($stockEntry->purchased_date)) datetime="{{ $stockEntry->purchased_date }} 23:59:59" @endif></time>
|
@if (!empty($stockEntry->purchased_date)) datetime="{{ $stockEntry->purchased_date }} 23:59:59" @endif></time>
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">{{ $stockEntry->purchased_date }}</td>
|
<td class="d-none">{{ $stockEntry->purchased_date }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
@ -275,32 +245,32 @@
|
||||||
datetime="{{ $stockEntry->row_created_timestamp }}"></time>
|
datetime="{{ $stockEntry->row_created_timestamp }}"></time>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $stockEntry->product_id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$stockEntry->product_id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="productcard-modal" tabindex="-1">
|
||||||
id="productcard-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@include('components.productcard')
|
@include('components.productcard')
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,44 +5,35 @@
|
||||||
@section('viewJsName', 'stockjournal')
|
@section('viewJsName', 'stockjournal')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button" data-toggle="collapse"
|
||||||
type="button"
|
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
data-target="#table-filter-row">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3 hide-when-embedded"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3 hide-when-embedded" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/stockjournal/summary') }}">
|
href="{{ $U('/stockjournal/summary') }}">
|
||||||
{{ $__t('Journal summary') }}
|
{{ $__t('Journal summary') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-2">
|
<div class="col-12 col-md-6 col-xl-2">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -50,24 +41,21 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="select2 custom-control custom-select" id="product-filter">
|
||||||
id="product-filter">
|
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($products as $product)
|
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Transaction type') }}</span>
|
<span class="input-group-text"><i
|
||||||
|
class="fas fa-filter"></i> {{ $__t('Transaction type') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: static data --}}
|
||||||
id="transaction-type-filter">
|
<select class="custom-control custom-select" id="transaction-type-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($transactionTypes as $transactionType)
|
@foreach ($transactionTypes as $transactionType)
|
||||||
<option value="{{ $transactionType }}">{{ $__t($transactionType) }}</option>
|
<option value="{{ $transactionType }}">{{ $__t($transactionType) }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -78,10 +66,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Location') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Location') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
id="location-filter">
|
<select class="custom-control custom-select" id="location-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -92,10 +80,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('User') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('User') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: users --}}
|
||||||
id="user-filter">
|
<select class="custom-control custom-select" id="user-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($users as $user)
|
@foreach ($users as $user)
|
||||||
<option value="{{ $user->id }}">{{ $user->display_name }}</option>
|
<option value="{{ $user->id }}">{{ $user->display_name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -106,11 +94,9 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="daterange-filter">
|
||||||
id="daterange-filter">
|
|
||||||
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
||||||
<option value="6"
|
<option value="6" selected>{{ $__n(6, '%s month', '%s months') }}</option>
|
||||||
selected>{{ $__n(6, '%s month', '%s months') }}</option>
|
|
||||||
<option value="12">{{ $__n(1, '%s year', '%s years') }}</option>
|
<option value="12">{{ $__n(1, '%s year', '%s years') }}</option>
|
||||||
<option value="24">{{ $__n(2, '%s month', '%s years') }}</option>
|
<option value="24">{{ $__n(2, '%s month', '%s years') }}</option>
|
||||||
<option value="9999">{{ $__t('All') }}</option>
|
<option value="9999">{{ $__t('All') }}</option>
|
||||||
|
|
@ -119,54 +105,48 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right mt-1">
|
<div class="float-right mt-1">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="stock-journal-table"
|
{{-- TODO: DataTables: dynamic data: uihelper_stock_journal --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="stock-journal-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#stock-journal-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#stock-journal-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th>{{ $__t('Transaction time') }}</th>
|
<th>{{ $__t('Transaction time') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}
|
||||||
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($stockLog as $stockLogEntry)
|
@foreach ($stockLog as $stockLogEntry)
|
||||||
<tr id="stock-booking-{{ $stockLogEntry->id }}-row"
|
<tr id="stock-booking-{{ $stockLogEntry->id }}-row"
|
||||||
class="@if($stockLogEntry->undone == 1) text-muted @endif stock-booking-correlation-{{ $stockLogEntry->correlation_id }}"
|
class="@if ($stockLogEntry->undone == 1) text-muted @endif stock-booking-correlation-{{ $stockLogEntry->correlation_id }}"
|
||||||
data-correlation-id="{{ $stockLogEntry->correlation_id }}">
|
data-correlation-id="{{ $stockLogEntry->correlation_id }}">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-secondary btn-xs undo-stock-booking-button @if($stockLogEntry->undone == 1) disabled @endif"
|
<a class="btn btn-secondary btn-xs undo-stock-booking-button @if ($stockLogEntry->undone == 1) disabled @endif"
|
||||||
href="#"
|
href="#" data-booking-id="{{ $stockLogEntry->id }}" data-toggle="tooltip"
|
||||||
data-booking-id="{{ $stockLogEntry->id }}"
|
data-placement="left" title="{{ $__t('Undo transaction') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Undo transaction') }}">
|
|
||||||
<i class="fas fa-undo"></i>
|
<i class="fas fa-undo"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="name-anchor @if($stockLogEntry->undone == 1) text-strike-through @endif">{{ $stockLogEntry->product_name }}</span>
|
<span
|
||||||
@if($stockLogEntry->undone == 1)
|
class="name-anchor @if ($stockLogEntry->undone == 1) text-strike-through @endif">{{ $stockLogEntry->product_name }}</span>
|
||||||
|
@if ($stockLogEntry->undone == 1)
|
||||||
<br>
|
<br>
|
||||||
{{ $__t('Undone on') . ' ' . $stockLogEntry->undone_timestamp }}
|
{{ $__t('Undone on') . ' ' . $stockLogEntry->undone_timestamp }}
|
||||||
<time class="timeago timeago-contextual"
|
<time class="timeago timeago-contextual"
|
||||||
|
|
@ -174,7 +154,9 @@
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $stockLogEntry->amount }}</span> {{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural, true) }}
|
<span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $stockLogEntry->amount }}</span>
|
||||||
|
{{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural, true) }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $stockLogEntry->row_created_timestamp }}
|
{{ $stockLogEntry->row_created_timestamp }}
|
||||||
|
|
@ -187,7 +169,7 @@
|
||||||
<span class="font-italic text-muted">{{ $__t('Spoiled') }}</span>
|
<span class="font-italic text-muted">{{ $__t('Spoiled') }}</span>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
||||||
{{ $stockLogEntry->location_name }}
|
{{ $stockLogEntry->location_name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
@ -198,5 +180,5 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,33 +5,27 @@
|
||||||
@section('viewJsName', 'stockjournalsummary')
|
@section('viewJsName', 'stockjournalsummary')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button" data-toggle="collapse"
|
||||||
type="button"
|
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
data-target="#table-filter-row">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-2">
|
<div class="col-12 col-md-6 col-xl-2">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -39,24 +33,22 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: products --}}
|
||||||
id="product-filter">
|
<select class="select2 custom-control custom-select" id="product-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($products as $product)
|
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Transaction type') }}</span>
|
<span class="input-group-text"><i
|
||||||
|
class="fas fa-filter"></i> {{ $__t('Transaction type') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: static data --}}
|
||||||
id="transaction-type-filter">
|
<select class="custom-control custom-select" id="transaction-type-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($transactionTypes as $transactionType)
|
@foreach ($transactionTypes as $transactionType)
|
||||||
<option value="{{ $transactionType }}">{{ $__t($transactionType) }}</option>
|
<option value="{{ $transactionType }}">{{ $__t($transactionType) }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -67,10 +59,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('User') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('User') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: users --}}
|
||||||
id="user-filter">
|
<select class="custom-control custom-select" id="user-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($users as $user)
|
@foreach ($users as $user)
|
||||||
<option value="{{ $user->id }}">{{ $user->display_name }}</option>
|
<option value="{{ $user->id }}">{{ $user->display_name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -78,27 +70,23 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right mt-1">
|
<div class="float-right mt-1">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="stock-journal-summary-table"
|
{{-- TODO: DataTables: dynamic data: uihelper_stock_journal_summary --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="stock-journal-summary-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#stock-journal-summary-table" href="#"><i
|
||||||
title="{{ $__t('Table options') }}"
|
class="fas fa-eye"></i></a>
|
||||||
data-table-selector="#stock-journal-summary-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
||||||
|
|
@ -107,7 +95,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($entries as $journalEntry)
|
@foreach ($entries as $journalEntry)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right"></td>
|
<td class="fit-content border-right"></td>
|
||||||
<td>
|
<td>
|
||||||
|
|
@ -120,12 +108,14 @@
|
||||||
{{ $journalEntry->user_display_name }}
|
{{ $journalEntry->user_display_name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $journalEntry->amount }}</span> {{ $__n($journalEntry->amount, $journalEntry->qu_name, $journalEntry->qu_name_plural, true) }}
|
<span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $journalEntry->amount }}</span>
|
||||||
|
{{ $__n($journalEntry->amount, $journalEntry->qu_name, $journalEntry->qu_name_plural, true) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,33 +5,28 @@
|
||||||
@section('viewJsName', 'stockoverview')
|
@section('viewJsName', 'stockoverview')
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}" rel="stylesheet">
|
||||||
rel="stylesheet">
|
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@push('pageScripts')
|
@push('pageScripts')
|
||||||
<script src="{{ $U('/viewjs/purchase.js?v=', true) }}{{ $version }}"></script>
|
<script src="{{ $U('/viewjs/purchase.js?v=', true) }}{{ $version }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title mr-2 order-0">
|
<h2 class="title mr-2 order-0">
|
||||||
@yield('title')
|
@yield('title')
|
||||||
</h2>
|
</h2>
|
||||||
<h2 class="mb-0 mr-auto order-3 order-md-1 width-xs-sm-100">
|
<h2 class="mb-0 mr-auto order-3 order-md-1 width-xs-sm-100">
|
||||||
<span id="info-current-stock"
|
<span id="info-current-stock" class="text-muted small"></span>
|
||||||
class="text-muted small"></span>
|
|
||||||
</h2>
|
</h2>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/stockjournal') }}">
|
href="{{ $U('/stockjournal') }}">
|
||||||
{{ $__t('Journal') }}
|
{{ $__t('Journal') }}
|
||||||
|
|
@ -40,7 +35,7 @@
|
||||||
href="{{ $U('/stockentries') }}">
|
href="{{ $U('/stockentries') }}">
|
||||||
{{ $__t('Stock entries') }}
|
{{ $__t('Stock entries') }}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
href="{{ $U('/locationcontentsheet') }}">
|
href="{{ $U('/locationcontentsheet') }}">
|
||||||
{{ $__t('Location Content Sheet') }}
|
{{ $__t('Location Content Sheet') }}
|
||||||
|
|
@ -50,59 +45,46 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="border-top border-bottom my-2 py-1">
|
<div class="border-top border-bottom my-2 py-1">
|
||||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||||
<div id="info-expired-products"
|
<div id="info-expired-products" data-status-filter="expired"
|
||||||
data-status-filter="expired"
|
|
||||||
class="error-message status-filter-message responsive-button mr-2"></div>
|
class="error-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-overdue-products"
|
<div id="info-overdue-products" data-status-filter="overdue"
|
||||||
data-status-filter="overdue"
|
|
||||||
class="secondary-message status-filter-message responsive-button mr-2"></div>
|
class="secondary-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-duesoon-products"
|
<div id="info-duesoon-products" data-next-x-days="{{ $nextXDays }}" data-status-filter="duesoon"
|
||||||
data-next-x-days="{{ $nextXDays }}"
|
|
||||||
data-status-filter="duesoon"
|
|
||||||
class="warning-message status-filter-message responsive-button mr-2"></div>
|
class="warning-message status-filter-message responsive-button mr-2"></div>
|
||||||
@endif
|
@endif
|
||||||
<div id="info-missing-products"
|
<div id="info-missing-products" data-status-filter="belowminstockamount"
|
||||||
data-status-filter="belowminstockamount"
|
|
||||||
class="normal-message status-filter-message responsive-button"></div>
|
class="normal-message status-filter-message responsive-button"></div>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a class="btn btn-sm btn-outline-info d-md-none mt-1"
|
<a class="btn btn-sm btn-outline-info d-md-none mt-1" data-toggle="collapse" href="#table-filter-row"
|
||||||
data-toggle="collapse"
|
|
||||||
href="#table-filter-row"
|
|
||||||
role="button">
|
role="button">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info mt-1" href="#">
|
||||||
class="btn btn-sm btn-outline-info mt-1"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Location') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Location') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
id="location-filter">
|
<select class="custom-control custom-select" id="location-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<option value="{{ $location->name }}">{{ $location->name }}</option>
|
<option value="{{ $location->name }}">{{ $location->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -114,10 +96,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product group') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product group') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: product_groups --}}
|
||||||
id="product-group-filter">
|
<select class="custom-control custom-select" id="product-group-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($productGroups as $productGroup)
|
@foreach ($productGroups as $productGroup)
|
||||||
<option value="{{ $productGroup->name }}">{{ $productGroup->name }}</option>
|
<option value="{{ $productGroup->name }}">{{ $productGroup->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -128,10 +110,8 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
id="status-filter">
|
<option class="bg-white" value="all">{{ $__t('All') }}</option>
|
||||||
<option class="bg-white"
|
|
||||||
value="all">{{ $__t('All') }}</option>
|
|
||||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||||
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
||||||
<option value="overdue">{{ $__t('Overdue') }}</option>
|
<option value="overdue">{{ $__t('Overdue') }}</option>
|
||||||
|
|
@ -142,33 +122,31 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="stock-overview-table"
|
{{-- TODO: DataTables: dynamic data: uihelper_stock_current_overview --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="stock-overview-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#stock-overview-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#stock-overview-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Product') }}</th>
|
<th>{{ $__t('Product') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product group') }}</th>
|
<th class="allow-grouping">{{ $__t('Product group') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Value') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Value') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif allow-grouping">{{ $__t('Next due date') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif allow-grouping">
|
||||||
|
{{ $__t('Next due date') }}</th>
|
||||||
<th class="d-none">Hidden location</th>
|
<th class="d-none">Hidden location</th>
|
||||||
<th class="d-none">Hidden status</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th class="d-none">Hidden product group</th>
|
<th class="d-none">Hidden product group</th>
|
||||||
<th>{{ $__t('Calories') }} ({{ $__t('Per stock quantity unit') }})</th>
|
<th>{{ $__t('Calories') }} ({{ $__t('Per stock quantity unit') }})</th>
|
||||||
<th>{{ $__t('Calories') }}</th>
|
<th>{{ $__t('Calories') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Last purchased') }}</th>
|
<th class="allow-grouping">{{ $__t('Last purchased') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Min. stock amount') }}</th>
|
<th class="allow-grouping">{{ $__t('Min. stock amount') }}</th>
|
||||||
<th>{{ $__t('Product description') }}</th>
|
<th>{{ $__t('Product description') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Parent product') }}</th>
|
<th class="allow-grouping">{{ $__t('Parent product') }}</th>
|
||||||
|
|
@ -176,136 +154,133 @@
|
||||||
<th>{{ $__t('Product picture') }}</th>
|
<th>{{ $__t('Product picture') }}</th>
|
||||||
<th>{{ $__t('Average price') }}</th>
|
<th>{{ $__t('Average price') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($currentStock as $currentStockEntry)
|
@foreach ($currentStock as $currentStockEntry)
|
||||||
<tr id="product-{{ $currentStockEntry->product_id }}-row"
|
<tr id="product-{{ $currentStockEntry->product_id }}-row"
|
||||||
class="@if(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $currentStockEntry->amount > 0) @if($currentStockEntry->due_type == 1) table-secondary @else table-danger @endif @elseif(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('+' . $nextXDays . ' days')) && $currentStockEntry->amount > 0) table-warning @elseif ($currentStockEntry->product_missing) table-info @endif">
|
class="@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('-1 days')) && $currentStockEntry->amount > 0) @if ($currentStockEntry->due_type == 1) table-secondary @else table-danger @endif
|
||||||
|
@elseif(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING && $currentStockEntry->best_before_date < date('Y-m-d 23:59:59', strtotime('+' . $nextXDays . ' days')) && $currentStockEntry->amount > 0)
|
||||||
|
table-warning
|
||||||
|
@elseif ($currentStockEntry->product_missing)
|
||||||
|
table-info @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="permission-STOCK_CONSUME btn btn-success btn-sm product-consume-button @if($currentStockEntry->amount_aggregated < $currentStockEntry->quick_consume_amount || $currentStockEntry->enable_tare_weight_handling == 1) disabled @endif"
|
<a class="permission-STOCK_CONSUME btn btn-success btn-sm product-consume-button @if ($currentStockEntry->amount_aggregated < $currentStockEntry->quick_consume_amount || $currentStockEntry->enable_tare_weight_handling == 1) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
data-toggle="tooltip"
|
title="{{ $__t('Consume %1$s of %2$s',floatval($currentStockEntry->quick_consume_amount) . ' ' . $currentStockEntry->qu_unit_name,$currentStockEntry->product_name) }}"
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Consume %1$s of %2$s', floatval($currentStockEntry->quick_consume_amount) . ' ' . $currentStockEntry->qu_unit_name, $currentStockEntry->product_name) }}"
|
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
data-product-id="{{ $currentStockEntry->product_id }}"
|
||||||
data-product-name="{{ $currentStockEntry->product_name }}"
|
data-product-name="{{ $currentStockEntry->product_name }}"
|
||||||
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
||||||
data-consume-amount="{{ $currentStockEntry->quick_consume_amount }}">
|
data-consume-amount="{{ $currentStockEntry->quick_consume_amount }}">
|
||||||
<i class="fas fa-utensils"></i> <span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
|
<i class="fas fa-utensils"></i> <span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a id="product-{{ $currentStockEntry->product_id }}-consume-all-button"
|
<a id="product-{{ $currentStockEntry->product_id }}-consume-all-button"
|
||||||
class="permission-STOCK_CONSUME btn btn-danger btn-sm product-consume-button @if($currentStockEntry->amount_aggregated == 0) disabled @endif"
|
class="permission-STOCK_CONSUME btn btn-danger btn-sm product-consume-button @if ($currentStockEntry->amount_aggregated == 0) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip" data-placement="right"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-placement="right"
|
|
||||||
title="{{ $__t('Consume all %s which are currently in stock', $currentStockEntry->product_name) }}"
|
title="{{ $__t('Consume all %s which are currently in stock', $currentStockEntry->product_name) }}"
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
data-product-id="{{ $currentStockEntry->product_id }}"
|
||||||
data-product-name="{{ $currentStockEntry->product_name }}"
|
data-product-name="{{ $currentStockEntry->product_name }}"
|
||||||
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
||||||
data-consume-amount="@if($currentStockEntry->enable_tare_weight_handling == 1){{$currentStockEntry->tare_weight}}@else{{$currentStockEntry->amount}}@endif"
|
data-consume-amount="@if ($currentStockEntry->enable_tare_weight_handling == 1) {{ $currentStockEntry->tare_weight }}@else{{ $currentStockEntry->amount }} @endif"
|
||||||
data-original-total-stock-amount="{{$currentStockEntry->amount}}">
|
data-original-total-stock-amount="{{ $currentStockEntry->amount }}">
|
||||||
<i class="fas fa-utensils"></i> {{ $__t('All') }}
|
<i class="fas fa-utensils"></i> {{ $__t('All') }}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
||||||
<a class="btn btn-success btn-sm product-open-button @if($currentStockEntry->amount_aggregated < $currentStockEntry->quick_consume_amount || $currentStockEntry->amount_aggregated == $currentStockEntry->amount_opened_aggregated || $currentStockEntry->enable_tare_weight_handling == 1) disabled @endif"
|
<a class="btn btn-success btn-sm product-open-button @if ($currentStockEntry->amount_aggregated < $currentStockEntry->quick_consume_amount || $currentStockEntry->amount_aggregated == $currentStockEntry->amount_opened_aggregated || $currentStockEntry->enable_tare_weight_handling == 1) disabled @endif"
|
||||||
href="#"
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
data-toggle="tooltip"
|
title="{{ $__t('Mark %1$s of %2$s as open',floatval($currentStockEntry->quick_consume_amount) . ' ' . $currentStockEntry->qu_unit_name,$currentStockEntry->product_name) }}"
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Mark %1$s of %2$s as open', floatval($currentStockEntry->quick_consume_amount) . ' ' . $currentStockEntry->qu_unit_name, $currentStockEntry->product_name) }}"
|
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
data-product-id="{{ $currentStockEntry->product_id }}"
|
||||||
data-product-name="{{ $currentStockEntry->product_name }}"
|
data-product-name="{{ $currentStockEntry->product_name }}"
|
||||||
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
||||||
data-open-amount="{{ $currentStockEntry->quick_consume_amount }}">
|
data-open-amount="{{ $currentStockEntry->quick_consume_amount }}">
|
||||||
<i class="fas fa-box-open"></i> <span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
|
<i class="fas fa-box-open"></i> <span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<div class="dropdown d-inline-block">
|
<div class="dropdown d-inline-block">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
type="button"
|
|
||||||
data-toggle="dropdown">
|
data-toggle="dropdown">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
||||||
@if(GROCY_FEATURE_FLAG_SHOPPINGLIST)
|
@if (GROCY_FEATURE_FLAG_SHOPPINGLIST)
|
||||||
<a class="dropdown-item show-as-dialog-link permission-SHOPPINGLIST_ITEMS_ADD"
|
<a class="dropdown-item show-as-dialog-link permission-SHOPPINGLIST_ITEMS_ADD"
|
||||||
type="button"
|
type="button"
|
||||||
href="{{ $U('/shoppinglistitem/new?embedded&updateexistingproduct&product=' . $currentStockEntry->product_id ) }}">
|
href="{{ $U('/shoppinglistitem/new?embedded&updateexistingproduct&product=' . $currentStockEntry->product_id) }}">
|
||||||
<span class="dropdown-item-icon"><i class="fas fa-shopping-cart"></i></span> <span class="dropdown-item-text">{{ $__t('Add to shopping list') }}</span>
|
<span class="dropdown-item-icon"><i class="fas fa-shopping-cart"></i></span>
|
||||||
|
<span
|
||||||
|
class="dropdown-item-text">{{ $__t('Add to shopping list') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
@endif
|
@endif
|
||||||
<a class="dropdown-item show-as-dialog-link permission-STOCK_PURCHASE"
|
<a class="dropdown-item show-as-dialog-link permission-STOCK_PURCHASE" type="button"
|
||||||
type="button"
|
href="{{ $U('/purchase?embedded&product=' . $currentStockEntry->product_id) }}">
|
||||||
href="{{ $U('/purchase?embedded&product=' . $currentStockEntry->product_id ) }}">
|
<span class="dropdown-item-icon"><i class="fas fa-cart-plus"></i></span> <span
|
||||||
<span class="dropdown-item-icon"><i class="fas fa-cart-plus"></i></span> <span class="dropdown-item-text">{{ $__t('Purchase') }}</span>
|
class="dropdown-item-text">{{ $__t('Purchase') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link permission-STOCK_CONSUME @if($currentStockEntry->amount_aggregated <= 0) disabled @endif"
|
<a class="dropdown-item show-as-dialog-link permission-STOCK_CONSUME @if ($currentStockEntry->amount_aggregated <= 0) disabled @endif"
|
||||||
type="button"
|
type="button"
|
||||||
href="{{ $U('/consume?embedded&product=' . $currentStockEntry->product_id ) }}">
|
href="{{ $U('/consume?embedded&product=' . $currentStockEntry->product_id) }}">
|
||||||
<span class="dropdown-item-icon"><i class="fas fa-utensils"></i></span> <span class="dropdown-item-text">{{ $__t('Consume') }}</span>
|
<span class="dropdown-item-icon"><i class="fas fa-utensils"></i></span> <span
|
||||||
|
class="dropdown-item-text">{{ $__t('Consume') }}</span>
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
<a class="dropdown-item show-as-dialog-link permission-STOCK_TRANSFER @if($currentStockEntry->amount <= 0) disabled @endif"
|
<a class="dropdown-item show-as-dialog-link permission-STOCK_TRANSFER @if ($currentStockEntry->amount <= 0) disabled @endif"
|
||||||
type="button"
|
type="button"
|
||||||
href="{{ $U('/transfer?embedded&product=' . $currentStockEntry->product_id) }}">
|
href="{{ $U('/transfer?embedded&product=' . $currentStockEntry->product_id) }}">
|
||||||
<span class="dropdown-item-icon"><i class="fas fa-exchange-alt"></i></span> <span class="dropdown-item-text">{{ $__t('Transfer') }}</span>
|
<span class="dropdown-item-icon"><i class="fas fa-exchange-alt"></i></span>
|
||||||
|
<span class="dropdown-item-text">{{ $__t('Transfer') }}</span>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<a class="dropdown-item show-as-dialog-link permission-STOCK_INVENTORY"
|
<a class="dropdown-item show-as-dialog-link permission-STOCK_INVENTORY"
|
||||||
type="button"
|
type="button"
|
||||||
href="{{ $U('/inventory?embedded&product=' . $currentStockEntry->product_id ) }}">
|
href="{{ $U('/inventory?embedded&product=' . $currentStockEntry->product_id) }}">
|
||||||
<span class="dropdown-item-icon"><i class="fas fa-list"></i></span> <span class="dropdown-item-text">{{ $__t('Inventory') }}</span>
|
<span class="dropdown-item-icon"><i class="fas fa-list"></i></span> <span
|
||||||
|
class="dropdown-item-text">{{ $__t('Inventory') }}</span>
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_RECIPES)
|
@if (GROCY_FEATURE_FLAG_RECIPES)
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/recipes?search=') }}{{ $currentStockEntry->product_name }}">
|
href="{{ $U('/recipes?search=') }}{{ $currentStockEntry->product_name }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Search for recipes containing this product') }}</span>
|
<span
|
||||||
|
class="dropdown-item-text">{{ $__t('Search for recipes containing this product') }}</span>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item product-name-cell"
|
<a class="dropdown-item product-name-cell"
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
data-product-id="{{ $currentStockEntry->product_id }}" type="button"
|
||||||
type="button"
|
|
||||||
href="#">
|
href="#">
|
||||||
<span class="dropdown-item-text">{{ $__t('Product overview') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Product overview') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/stockentries?embedded&product=') }}{{ $currentStockEntry->product_id }}"
|
href="{{ $U('/stockentries?embedded&product=') }}{{ $currentStockEntry->product_id }}"
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}">
|
data-product-id="{{ $currentStockEntry->product_id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Stock entries') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Stock entries') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/stockjournal?embedded&product=') }}{{ $currentStockEntry->product_id }}">
|
href="{{ $U('/stockjournal?embedded&product=') }}{{ $currentStockEntry->product_id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Stock journal') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Stock journal') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/stockjournal/summary?embedded&product_id=') }}{{ $currentStockEntry->product_id }}">
|
href="{{ $U('/stockjournal/summary?embedded&product_id=') }}{{ $currentStockEntry->product_id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Stock journal summary') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Stock journal summary') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item permission-MASTER_DATA_EDIT link-return"
|
<a class="dropdown-item permission-MASTER_DATA_EDIT link-return" type="button"
|
||||||
type="button"
|
|
||||||
data-href="{{ $U('/product/') }}{{ $currentStockEntry->product_id }}">
|
data-href="{{ $U('/product/') }}{{ $currentStockEntry->product_id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Edit product') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Edit product') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item" type="button"
|
||||||
type="button"
|
|
||||||
href="{{ $U('/product/' . $currentStockEntry->product_id . '/grocycode?download=true') }}">
|
href="{{ $U('/product/' . $currentStockEntry->product_id . '/grocycode?download=true') }}">
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Product'))) !!}
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Product'))) !!}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
<a class="dropdown-item product-grocycode-label-print"
|
<a class="dropdown-item product-grocycode-label-print"
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
data-product-id="{{ $currentStockEntry->product_id }}" type="button"
|
||||||
type="button"
|
|
||||||
href="#">
|
href="#">
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Product'))) !!}
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Product'))) !!}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -319,25 +294,34 @@
|
||||||
<span class="d-none">{{ $currentStockEntry->product_barcodes }}</span>
|
<span class="d-none">{{ $currentStockEntry->product_barcodes }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if($currentStockEntry->product_group_name !== null){{ $currentStockEntry->product_group_name }}@endif
|
@if ($currentStockEntry->product_group_name !== null)
|
||||||
|
{{ $currentStockEntry->product_group_name }}@endif
|
||||||
</td>
|
</td>
|
||||||
<td data-order="{{ $currentStockEntry->amount }}">
|
<td data-order="{{ $currentStockEntry->amount }}">
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-amount"
|
<span id="product-{{ $currentStockEntry->product_id }}-amount"
|
||||||
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural) }}</span>
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span>
|
||||||
|
<span
|
||||||
|
id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural) }}</span>
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-opened-amount"
|
<span id="product-{{ $currentStockEntry->product_id }}-opened-amount"
|
||||||
class="small font-italic">@if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif</span>
|
class="small font-italic">
|
||||||
@if($currentStockEntry->is_aggregated_amount == 1)
|
@if ($currentStockEntry->amount_opened > 0)
|
||||||
|
{{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif
|
||||||
|
</span>
|
||||||
|
@if ($currentStockEntry->is_aggregated_amount == 1)
|
||||||
<span class="pl-1 text-secondary">
|
<span class="pl-1 text-secondary">
|
||||||
<i class="fas fa-custom-sigma-sign"></i> <span id="product-{{ $currentStockEntry->product_id }}-amount-aggregated"
|
<i class="fas fa-custom-sigma-sign"></i> <span
|
||||||
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount_aggregated }}</span> {{ $__n($currentStockEntry->amount_aggregated, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural, true) }}
|
id="product-{{ $currentStockEntry->product_id }}-amount-aggregated"
|
||||||
@if($currentStockEntry->amount_opened_aggregated > 0)<span id="product-{{ $currentStockEntry->product_id }}-opened-amount-aggregated"
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount_aggregated }}</span>
|
||||||
class="small font-italic">{{ $__t('%s opened', $currentStockEntry->amount_opened_aggregated) }}</span>@endif
|
{{ $__n($currentStockEntry->amount_aggregated,$currentStockEntry->qu_unit_name,$currentStockEntry->qu_unit_name_plural,true) }}
|
||||||
|
@if ($currentStockEntry->amount_opened_aggregated > 0)<span
|
||||||
|
id="product-{{ $currentStockEntry->product_id }}-opened-amount-aggregated"
|
||||||
|
class="small font-italic">{{ $__t('%s opened', $currentStockEntry->amount_opened_aggregated) }}</span>
|
||||||
|
@endif
|
||||||
</span>
|
</span>
|
||||||
@endif
|
@endif
|
||||||
@if(boolval($userSettings['show_icon_on_stock_overview_page_when_product_is_on_shopping_list']))
|
@if (boolval($userSettings['show_icon_on_stock_overview_page_when_product_is_on_shopping_list']))
|
||||||
@if($currentStockEntry->on_shopping_list)
|
@if ($currentStockEntry->on_shopping_list)
|
||||||
<span class="text-muted cursor-normal"
|
<span class="text-muted cursor-normal" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('This product is currently on a shopping list') }}">
|
title="{{ $__t('This product is currently on a shopping list') }}">
|
||||||
<i class="fas fa-shopping-cart"></i>
|
<i class="fas fa-shopping-cart"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -348,56 +332,63 @@
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-value"
|
<span id="product-{{ $currentStockEntry->product_id }}-value"
|
||||||
class="locale-number locale-number-currency">{{ $currentStockEntry->value }}</span>
|
class="locale-number locale-number-currency">{{ $currentStockEntry->value }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-next-due-date">{{ $currentStockEntry->best_before_date }}</span>
|
<span
|
||||||
|
id="product-{{ $currentStockEntry->product_id }}-next-due-date">{{ $currentStockEntry->best_before_date }}</span>
|
||||||
<time id="product-{{ $currentStockEntry->product_id }}-next-due-date-timeago"
|
<time id="product-{{ $currentStockEntry->product_id }}-next-due-date-timeago"
|
||||||
class="timeago timeago-contextual"
|
class="timeago timeago-contextual"
|
||||||
@if(!empty($currentStockEntry->best_before_date)) datetime="{{ $currentStockEntry->best_before_date }} 23:59:59" @endif></time>
|
@if (!empty($currentStockEntry->best_before_date)) datetime="{{ $currentStockEntry->best_before_date }} 23:59:59" @endif></time>
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
@foreach(FindAllObjectsInArrayByPropertyValue($currentStockLocations, 'product_id', $currentStockEntry->product_id) as $locationsForProduct)
|
@foreach (FindAllObjectsInArrayByPropertyValue($currentStockLocations, 'product_id', $currentStockEntry->product_id) as $locationsForProduct)
|
||||||
xx{{ FindObjectInArrayByPropertyValue($locations, 'id', $locationsForProduct->location_id)->name }}xx
|
xx{{ FindObjectInArrayByPropertyValue($locations, 'id', $locationsForProduct->location_id)->name }}xx
|
||||||
@endforeach
|
@endforeach
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
@if($currentStockEntry->best_before_date < date('Y-m-d
|
@if ($currentStockEntry->best_before_date <
|
||||||
|
date(
|
||||||
|
'Y-m-d
|
||||||
23:59:59',
|
23:59:59',
|
||||||
strtotime('-'
|
strtotime('-' . '1' . ' days'),
|
||||||
. '1'
|
) && $currentStockEntry->amount > 0)
|
||||||
. ' days'
|
@if ($currentStockEntry->due_type == 1) overdue
|
||||||
))
|
@else
|
||||||
&&
|
expired @endif
|
||||||
$currentStockEntry->amount > 0) @if($currentStockEntry->due_type == 1) overdue @else expired @endif @elseif($currentStockEntry->best_before_date < date('Y-m-d
|
@elseif($currentStockEntry->best_before_date <
|
||||||
|
date(
|
||||||
|
'Y-m-d
|
||||||
23:59:59',
|
23:59:59',
|
||||||
strtotime('+'
|
strtotime('+' . $nextXDays . ' days'),
|
||||||
.
|
) && $currentStockEntry->amount > 0)
|
||||||
$nextXDays
|
duesoon
|
||||||
. ' days'
|
@endif
|
||||||
))
|
@if ($currentStockEntry->amount_aggregated > 0) instockX @endif
|
||||||
&&
|
@if ($currentStockEntry->product_missing) belowminstockamount
|
||||||
$currentStockEntry->amount > 0) duesoon @endif
|
@endif
|
||||||
@if($currentStockEntry->amount_aggregated > 0) instockX @endif
|
|
||||||
@if ($currentStockEntry->product_missing) belowminstockamount @endif
|
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
xx{{ $currentStockEntry->product_group_name }}xx
|
xx{{ $currentStockEntry->product_group_name }}xx
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->product_calories }}</span>
|
<span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->product_calories }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->calories }}</span>
|
<span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->calories }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $currentStockEntry->last_purchased }}
|
{{ $currentStockEntry->last_purchased }}
|
||||||
<time class="timeago timeago-contextual"
|
<time class="timeago timeago-contextual"
|
||||||
datetime="{{ $currentStockEntry->last_purchased }}"></time>
|
datetime="{{ $currentStockEntry->last_purchased }}"></time>
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
||||||
<span class="locale-number locale-number-currency">{{ $currentStockEntry->last_price }}</span>
|
<span
|
||||||
|
class="locale-number locale-number-currency">{{ $currentStockEntry->last_price }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->min_stock_amount }}</span>
|
<span
|
||||||
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->min_stock_amount }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{!! $currentStockEntry->product_description !!}
|
{!! $currentStockEntry->product_description !!}
|
||||||
|
|
@ -410,41 +401,42 @@
|
||||||
{{ $currentStockEntry->product_default_location_name }}
|
{{ $currentStockEntry->product_default_location_name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if(!empty($currentStockEntry->product_picture_file_name))
|
@if (!empty($currentStockEntry->product_picture_file_name))
|
||||||
<img data-src="{{ $U('/api/files/productpictures/' . base64_encode($currentStockEntry->product_picture_file_name) . '?force_serve_as=picture&best_fit_width=64&best_fit_height=64') }}"
|
<img data-src="{{ $U('/api/files/productpictures/' .base64_encode($currentStockEntry->product_picture_file_name) .'?force_serve_as=picture&best_fit_width=64&best_fit_height=64') }}"
|
||||||
class="lazy">
|
class="lazy">
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
||||||
<span class="locale-number locale-number-currency">{{ $currentStockEntry->average_price }}</span>
|
<span
|
||||||
|
class="locale-number locale-number-currency">{{ $currentStockEntry->average_price }}</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $currentStockEntry->product_id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$currentStockEntry->product_id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="stockoverview-productcard-modal" tabindex="-1">
|
||||||
id="stockoverview-productcard-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content text-center">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@include('components.productcard')
|
@include('components.productcard')
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,27 +5,27 @@
|
||||||
@section('viewJsName', 'stocksettings')
|
@section('viewJsName', 'stocksettings')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-12">
|
<div class="col-lg-6 col-12">
|
||||||
<div id="productpresets">
|
<div id="productpresets">
|
||||||
<h4>{{ $__t('Presets for new products') }}</h4>
|
<h4>{{ $__t('Presets for new products') }}</h4>
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="product_presets_location_id">{{ $__t('Location') }}</label>
|
<label for="product_presets_location_id">{{ $__t('Location') }}</label>
|
||||||
<select class="custom-control custom-select user-setting-control"
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
id="product_presets_location_id"
|
<select class="custom-control custom-select user-setting-control" id="product_presets_location_id"
|
||||||
data-setting-key="product_presets_location_id">
|
data-setting-key="product_presets_location_id">
|
||||||
<option value="-1"></option>
|
<option value="-1"></option>
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -34,11 +34,11 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="product_presets_product_group_id">{{ $__t('Product group') }}</label>
|
<label for="product_presets_product_group_id">{{ $__t('Product group') }}</label>
|
||||||
<select class="custom-control custom-select user-setting-control"
|
{{-- TODO: Select2: dynamic data: product_groups --}}
|
||||||
id="product_presets_product_group_id"
|
<select class="custom-control custom-select user-setting-control" id="product_presets_product_group_id"
|
||||||
data-setting-key="product_presets_product_group_id">
|
data-setting-key="product_presets_product_group_id">
|
||||||
<option value="-1"></option>
|
<option value="-1"></option>
|
||||||
@foreach($productGroups as $productGroup)
|
@foreach ($productGroups as $productGroup)
|
||||||
<option value="{{ $productGroup->id }}">{{ $productGroup->name }}</option>
|
<option value="{{ $productGroup->id }}">{{ $productGroup->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -46,29 +46,28 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="product_presets_qu_id">{{ $__t('Quantity unit') }}</label>
|
<label for="product_presets_qu_id">{{ $__t('Quantity unit') }}</label>
|
||||||
<select class="custom-control custom-select user-setting-control"
|
{{-- TODO: Select2: dynamic data: quantity_units --}}
|
||||||
id="product_presets_qu_id"
|
<select class="custom-control custom-select user-setting-control" id="product_presets_qu_id"
|
||||||
data-setting-key="product_presets_qu_id">
|
data-setting-key="product_presets_qu_id">
|
||||||
<option value="-1"></option>
|
<option value="-1"></option>
|
||||||
@foreach($quantityunits as $quantityunit)
|
@foreach ($quantityunits as $quantityunit)
|
||||||
<option value="{{ $quantityunit->id }}">{{ $quantityunit->name }}</option>
|
<option value="{{ $quantityunit->id }}">{{ $quantityunit->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'product_presets_default_due_days',
|
'id' => 'product_presets_default_due_days',
|
||||||
'additionalAttributes' => 'data-setting-key="product_presets_default_due_days"',
|
'additionalAttributes' => 'data-setting-key="product_presets_default_due_days"',
|
||||||
'label' => 'Default due days',
|
'label' => 'Default due days',
|
||||||
'min' => -1,
|
'min' => -1,
|
||||||
'additionalCssClasses' => 'user-setting-control'
|
'additionalCssClasses' => 'user-setting-control',
|
||||||
))
|
])
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input type="checkbox"
|
<input type="checkbox" class="form-check-input custom-control-input user-setting-control"
|
||||||
class="form-check-input custom-control-input user-setting-control"
|
|
||||||
id="product_presets_treat_opened_as_out_of_stock"
|
id="product_presets_treat_opened_as_out_of_stock"
|
||||||
data-setting-key="product_presets_treat_opened_as_out_of_stock">
|
data-setting-key="product_presets_treat_opened_as_out_of_stock">
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
|
|
@ -81,18 +80,17 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="mt-2">{{ $__t('Stock overview') }}</h4>
|
<h4 class="mt-2">{{ $__t('Stock overview') }}</h4>
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'stock_due_soon_days',
|
'id' => 'stock_due_soon_days',
|
||||||
'additionalAttributes' => 'data-setting-key="stock_due_soon_days"',
|
'additionalAttributes' => 'data-setting-key="stock_due_soon_days"',
|
||||||
'label' => 'Due soon days',
|
'label' => 'Due soon days',
|
||||||
'min' => 1,
|
'min' => 1,
|
||||||
'additionalCssClasses' => 'user-setting-control'
|
'additionalCssClasses' => 'user-setting-control',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input type="checkbox"
|
<input type="checkbox" class="form-check-input custom-control-input user-setting-control"
|
||||||
class="form-check-input custom-control-input user-setting-control"
|
|
||||||
id="show_icon_on_stock_overview_page_when_product_is_on_shopping_list"
|
id="show_icon_on_stock_overview_page_when_product_is_on_shopping_list"
|
||||||
data-setting-key="show_icon_on_stock_overview_page_when_product_is_on_shopping_list">
|
data-setting-key="show_icon_on_stock_overview_page_when_product_is_on_shopping_list">
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
|
|
@ -103,23 +101,20 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="mt-2">{{ $__t('Purchase') }}</h4>
|
<h4 class="mt-2">{{ $__t('Purchase') }}</h4>
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'stock_default_purchase_amount',
|
'id' => 'stock_default_purchase_amount',
|
||||||
'additionalAttributes' => 'data-setting-key="stock_default_purchase_amount"',
|
'additionalAttributes' => 'data-setting-key="stock_default_purchase_amount"',
|
||||||
'label' => 'Default amount for purchase',
|
'label' => 'Default amount for purchase',
|
||||||
'min' => '0.',
|
'min' => '0.',
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
'additionalCssClasses' => 'user-setting-control locale-number-input locale-number-quantity-amount',
|
'additionalCssClasses' => 'user-setting-control locale-number-input locale-number-quantity-amount',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input type="checkbox"
|
<input type="checkbox" class="form-check-input custom-control-input user-setting-control"
|
||||||
class="form-check-input custom-control-input user-setting-control"
|
id="show_purchased_date_on_purchase" data-setting-key="show_purchased_date_on_purchase">
|
||||||
id="show_purchased_date_on_purchase"
|
<label class="form-check-label custom-control-label" for="show_purchased_date_on_purchase">
|
||||||
data-setting-key="show_purchased_date_on_purchase">
|
|
||||||
<label class="form-check-label custom-control-label"
|
|
||||||
for="show_purchased_date_on_purchase">
|
|
||||||
{{ $__t('Show purchased date on purchase and inventory page (otherwise the purchased date defaults to today)') }}
|
{{ $__t('Show purchased date on purchase and inventory page (otherwise the purchased date defaults to today)') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -127,8 +122,7 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input type="checkbox"
|
<input type="checkbox" class="form-check-input custom-control-input user-setting-control"
|
||||||
class="form-check-input custom-control-input user-setting-control"
|
|
||||||
id="show_warning_on_purchase_when_due_date_is_earlier_than_next"
|
id="show_warning_on_purchase_when_due_date_is_earlier_than_next"
|
||||||
data-setting-key="show_warning_on_purchase_when_due_date_is_earlier_than_next">
|
data-setting-key="show_warning_on_purchase_when_due_date_is_earlier_than_next">
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
|
|
@ -139,20 +133,19 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="mt-2">{{ $__t('Consume') }}</h4>
|
<h4 class="mt-2">{{ $__t('Consume') }}</h4>
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'stock_default_consume_amount',
|
'id' => 'stock_default_consume_amount',
|
||||||
'additionalAttributes' => 'data-setting-key="stock_default_consume_amount"',
|
'additionalAttributes' => 'data-setting-key="stock_default_consume_amount"',
|
||||||
'label' => 'Default amount for consume',
|
'label' => 'Default amount for consume',
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
'additionalCssClasses' => 'user-setting-control locale-number-input locale-number-quantity-amount',
|
'additionalCssClasses' => 'user-setting-control locale-number-input locale-number-quantity-amount',
|
||||||
'additionalGroupCssClasses' => 'mb-0'
|
'additionalGroupCssClasses' => 'mb-0',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input type="checkbox"
|
<input type="checkbox" class="form-check-input custom-control-input user-setting-control"
|
||||||
class="form-check-input custom-control-input user-setting-control"
|
|
||||||
id="stock_default_consume_amount_use_quick_consume_amount"
|
id="stock_default_consume_amount_use_quick_consume_amount"
|
||||||
data-setting-key="stock_default_consume_amount_use_quick_consume_amount">
|
data-setting-key="stock_default_consume_amount_use_quick_consume_amount">
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
|
|
@ -164,43 +157,37 @@
|
||||||
|
|
||||||
<h4 class="mt-2">{{ $__t('Common') }}</h4>
|
<h4 class="mt-2">{{ $__t('Common') }}</h4>
|
||||||
|
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'stock_decimal_places_amounts',
|
'id' => 'stock_decimal_places_amounts',
|
||||||
'additionalAttributes' => 'data-setting-key="stock_decimal_places_amounts"',
|
'additionalAttributes' => 'data-setting-key="stock_decimal_places_amounts"',
|
||||||
'label' => 'Decimal places allowed for amounts',
|
'label' => 'Decimal places allowed for amounts',
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
'additionalCssClasses' => 'user-setting-control'
|
'additionalCssClasses' => 'user-setting-control',
|
||||||
))
|
])
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', [
|
||||||
'id' => 'stock_decimal_places_prices',
|
'id' => 'stock_decimal_places_prices',
|
||||||
'additionalAttributes' => 'data-setting-key="stock_decimal_places_prices"',
|
'additionalAttributes' => 'data-setting-key="stock_decimal_places_prices"',
|
||||||
'label' => 'Decimal places allowed for prices',
|
'label' => 'Decimal places allowed for prices',
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
'additionalCssClasses' => 'user-setting-control'
|
'additionalCssClasses' => 'user-setting-control',
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group mt-n3">
|
<div class="form-group mt-n3">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input type="checkbox"
|
<input type="checkbox" class="form-check-input custom-control-input user-setting-control"
|
||||||
class="form-check-input custom-control-input user-setting-control"
|
id="stock_auto_decimal_separator_prices" data-setting-key="stock_auto_decimal_separator_prices">
|
||||||
id="stock_auto_decimal_separator_prices"
|
<label class="form-check-label custom-control-label" for="stock_auto_decimal_separator_prices">
|
||||||
data-setting-key="stock_auto_decimal_separator_prices">
|
|
||||||
<label class="form-check-label custom-control-label"
|
|
||||||
for="stock_auto_decimal_separator_prices">
|
|
||||||
{{ $__t('Add decimal separator automatically for price inputs') }}
|
{{ $__t('Add decimal separator automatically for price inputs') }}
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('When enabled, you always have to enter the value including decimal places, the decimal separator will be automatically added based on the amount of allowed decimal places') }}"></i>
|
title="{{ $__t('When enabled, you always have to enter the value including decimal places, the decimal separator will be automatically added based on the amount of allowed decimal places') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<a href="{{ $U('/stockoverview') }}"
|
<a href="{{ $U('/stockoverview') }}" class="btn btn-success">{{ $__t('OK') }}</a>
|
||||||
class="btn btn-success">{{ $__t('OK') }}</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,102 +5,84 @@
|
||||||
@section('viewJsName', 'taskcategories')
|
@section('viewJsName', 'taskcategories')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
id="related-links">
|
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
href="{{ $U('/taskcategory/new?embedded') }}">
|
href="{{ $U('/taskcategory/new?embedded') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-outline-secondary"
|
<a class="btn btn-outline-secondary" href="{{ $U('/userfields?entity=task_categories') }}">
|
||||||
href="{{ $U('/userfields?entity=task_categories') }}">
|
|
||||||
{{ $__t('Configure userfields') }}
|
{{ $__t('Configure userfields') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="taskcategories-table"
|
{{-- TODO: DataTables: dynamic data: task_categories --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="taskcategories-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#taskcategories-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#taskcategories-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Description') }}</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($taskCategories as $taskCategory)
|
@foreach ($taskCategories as $taskCategory)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/taskcategory/') }}{{ $taskCategory->id }}?embedded"
|
href="{{ $U('/taskcategory/') }}{{ $taskCategory->id }}?embedded"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm task-category-delete-button"
|
<a class="btn btn-danger btn-sm task-category-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-category-id="{{ $taskCategory->id }}"
|
data-category-id="{{ $taskCategory->id }}"
|
||||||
data-category-name="{{ $taskCategory->name }}"
|
data-category-name="{{ $taskCategory->name }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -112,15 +94,19 @@
|
||||||
{{ $taskCategory->description }}
|
{{ $taskCategory->description }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $taskCategory->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$taskCategory->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -1,64 +1,59 @@
|
||||||
@extends('layout.default')
|
@extends('layout.default')
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
@section('title', $__t('Edit task'))
|
@section('title', $__t('Edit task'))
|
||||||
@else
|
@else
|
||||||
@section('title', $__t('Create task'))
|
@section('title', $__t('Create task'))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@section('viewJsName', 'taskform')
|
@section('viewJsName', 'taskform')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-12">
|
<div class="col-lg-6 col-12">
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditMode = '{{ $mode }}';
|
Grocy.EditMode = '{{ $mode }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditObjectId = {{ $task->id }};
|
Grocy.EditObjectId = {{ $task->id }};
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form id="task-form"
|
<form id="task-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">{{ $__t('Name') }}</label>
|
<label for="name">{{ $__t('Name') }}</label>
|
||||||
<input type="text"
|
<input type="text" class="form-control" required id="name" name="name"
|
||||||
class="form-control"
|
value="@if ($mode == 'edit') {{ $task->name }} @endif">
|
||||||
required
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
value="@if($mode == 'edit'){{ $task->name }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="description">{{ $__t('Description') }}</label>
|
<label for="description">{{ $__t('Description') }}</label>
|
||||||
<textarea class="form-control"
|
<textarea class="form-control" rows="4" id="description" name="description">
|
||||||
rows="4"
|
@if ($mode == 'edit')
|
||||||
id="description"
|
{{ $task->description }}
|
||||||
name="description">@if($mode == 'edit'){{ $task->description }}@endif</textarea>
|
@endif
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php
|
@php
|
||||||
$initialDueDate = null;
|
$initialDueDate = null;
|
||||||
if ($mode == 'edit' && !empty($task->due_date))
|
if ($mode == 'edit' && !empty($task->due_date)) {
|
||||||
{
|
|
||||||
$initialDueDate = date('Y-m-d', strtotime($task->due_date));
|
$initialDueDate = date('Y-m-d', strtotime($task->due_date));
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
@include('components.datetimepicker', array(
|
@include('components.datetimepicker', [
|
||||||
'id' => 'due_date',
|
'id' => 'due_date',
|
||||||
'label' => 'Due',
|
'label' => 'Due',
|
||||||
'format' => 'YYYY-MM-DD',
|
'format' => 'YYYY-MM-DD',
|
||||||
|
|
@ -69,48 +64,46 @@
|
||||||
'invalidFeedback' => $__t('A due date is required'),
|
'invalidFeedback' => $__t('A due date is required'),
|
||||||
'nextInputSelector' => 'category_id',
|
'nextInputSelector' => 'category_id',
|
||||||
'additionalGroupCssClasses' => 'date-only-datetimepicker',
|
'additionalGroupCssClasses' => 'date-only-datetimepicker',
|
||||||
'isRequired' => false
|
'isRequired' => false,
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="category_id">{{ $__t('Category') }}</label>
|
<label for="category_id">{{ $__t('Category') }}</label>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: task_categories --}}
|
||||||
id="category_id"
|
<select class="custom-control custom-select" id="category_id" name="category_id">
|
||||||
name="category_id">
|
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($taskCategories as $taskCategory)
|
@foreach ($taskCategories as $taskCategory)
|
||||||
<option @if($mode=='edit'
|
<option @if ($mode == 'edit' && $taskCategory->id == $task->category_id) selected="selected" @endif
|
||||||
&&
|
value="{{ $taskCategory->id }}">{{ $taskCategory->name }}</option>
|
||||||
$taskCategory->id == $task->category_id) selected="selected" @endif value="{{ $taskCategory->id }}">{{ $taskCategory->name }}</option>
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php
|
@php
|
||||||
$initUserId = GROCY_USER_ID;
|
$initUserId = GROCY_USER_ID;
|
||||||
if ($mode == 'edit')
|
if ($mode == 'edit') {
|
||||||
{
|
|
||||||
$initUserId = $task->assigned_to_user_id;
|
$initUserId = $task->assigned_to_user_id;
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
@include('components.userpicker', array(
|
@include('components.userpicker', [
|
||||||
'label' => 'Assigned to',
|
'label' => 'Assigned to',
|
||||||
'users' => $users,
|
'users' => $users,
|
||||||
'prefillByUserId' => $initUserId
|
'prefillByUserId' => $initUserId,
|
||||||
))
|
])
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@include('components.userfieldsform', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'entity' => 'tasks'
|
'entity' => 'tasks',
|
||||||
))
|
])
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<button class="btn btn-success save-task-button">{{ $__t('Save') }}</button>
|
<button class="btn btn-success save-task-button">{{ $__t('Save') }}</button>
|
||||||
@else
|
@else
|
||||||
<button class="btn btn-success save-task-button">{{ $__t('Save & close') }}</button>
|
<button class="btn btn-success save-task-button">{{ $__t('Save & close') }}</button>
|
||||||
<button class="btn btn-primary save-task-button add-another">{{ $__t('Save & add another task') }}</button>
|
<button
|
||||||
|
class="btn btn-primary save-task-button add-another">{{ $__t('Save & add another task') }}</button>
|
||||||
@endif
|
@endif
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,68 +5,53 @@
|
||||||
@section('viewJsName', 'tasks')
|
@section('viewJsName', 'tasks')
|
||||||
|
|
||||||
@push('pageStyles')
|
@push('pageStyles')
|
||||||
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}"
|
<link href="{{ $U('/node_modules/animate.css/animate.min.css?v=', true) }}{{ $version }}" rel="stylesheet">
|
||||||
rel="stylesheet">
|
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
||||||
id="related-links">
|
id="related-links">
|
||||||
<a class="btn btn-primary responsive-button show-as-dialog-link"
|
<a class="btn btn-primary responsive-button show-as-dialog-link" href="{{ $U('/task/new?embedded') }}">
|
||||||
href="{{ $U('/task/new?embedded') }}">
|
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-top border-bottom my-2 py-1">
|
<div class="border-top border-bottom my-2 py-1">
|
||||||
<div id="info-overdue-tasks"
|
<div id="info-overdue-tasks" data-status-filter="overdue"
|
||||||
data-status-filter="overdue"
|
|
||||||
class="error-message status-filter-message responsive-button mr-2"></div>
|
class="error-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-due-today-tasks"
|
<div id="info-due-today-tasks" data-status-filter="duetoday"
|
||||||
data-status-filter="duetoday"
|
|
||||||
class="normal-message status-filter-message responsive-button mr-2"></div>
|
class="normal-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-due-soon-tasks"
|
<div id="info-due-soon-tasks" data-status-filter="duesoon" data-next-x-days="{{ $nextXDays }}"
|
||||||
data-status-filter="duesoon"
|
class="warning-message status-filter-message responsive-button @if ($nextXDays == 0) d-none @endif">
|
||||||
data-next-x-days="{{ $nextXDays }}"
|
</div>
|
||||||
class="warning-message status-filter-message responsive-button @if($nextXDays == 0) d-none @endif"></div>
|
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a class="btn btn-sm btn-outline-info d-md-none mt-1"
|
<a class="btn btn-sm btn-outline-info d-md-none mt-1" data-toggle="collapse" href="#table-filter-row"
|
||||||
data-toggle="collapse"
|
|
||||||
href="#table-filter-row"
|
|
||||||
role="button">
|
role="button">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</a>
|
</a>
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info mt-1" href="#">
|
||||||
class="btn btn-sm btn-outline-info mt-1"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -74,12 +59,11 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
id="status-filter">
|
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<option value="overdue">{{ $__t('Overdue') }}</option>
|
<option value="overdue">{{ $__t('Overdue') }}</option>
|
||||||
<option value="duetoday">{{ $__t('Due today') }}</option>
|
<option value="duetoday">{{ $__t('Due today') }}</option>
|
||||||
@if($nextXDays > 0)
|
@if ($nextXDays > 0)
|
||||||
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
||||||
@endif
|
@endif
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -87,118 +71,112 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="form-check custom-control custom-checkbox">
|
<div class="form-check custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-done-tasks">
|
||||||
type="checkbox"
|
<label class="form-check-label custom-control-label" for="show-done-tasks">
|
||||||
id="show-done-tasks">
|
|
||||||
<label class="form-check-label custom-control-label"
|
|
||||||
for="show-done-tasks">
|
|
||||||
{{ $__t('Show done tasks') }}
|
{{ $__t('Show done tasks') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="tasks-table"
|
{{-- TODO: DataTables: dynamic data: tasks --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="tasks-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#tasks-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#tasks-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Task') }}</th>
|
<th>{{ $__t('Task') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Due') }}</th>
|
<th class="allow-grouping">{{ $__t('Due') }}</th>
|
||||||
<th class="allow-grouping"
|
<th class="allow-grouping" data-shadow-rowgroup-column="6">{{ $__t('Category') }}</th>
|
||||||
data-shadow-rowgroup-column="6">{{ $__t('Category') }}</th>
|
|
||||||
<th class="allow-grouping">{{ $__t('Assigned to') }}</th>
|
<th class="allow-grouping">{{ $__t('Assigned to') }}</th>
|
||||||
<th class="d-none">Hidden status</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th class="d-none">Hidden category_id</th>
|
<th class="d-none">Hidden category_id</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($tasks as $task)
|
@foreach ($tasks as $task)
|
||||||
<tr id="task-{{ $task->id }}-row"
|
<tr id="task-{{ $task->id }}-row"
|
||||||
class="@if($task->due_type == 'overdue') table-danger @elseif($task->due_type == 'duetoday') table-info @elseif($task->due_type == 'duesoon') table-warning @endif">
|
class="@if ($task->due_type == 'overdue') table-danger @elseif($task->due_type == 'duetoday') table-info @elseif($task->due_type == 'duesoon') table-warning @endif">
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
@if($task->done == 0)
|
@if ($task->done == 0)
|
||||||
<a class="btn btn-success btn-sm do-task-button"
|
<a class="btn btn-success btn-sm do-task-button" href="#" data-toggle="tooltip"
|
||||||
href="#"
|
data-placement="left" title="{{ $__t('Mark task as completed') }}"
|
||||||
data-toggle="tooltip"
|
data-task-id="{{ $task->id }}" data-task-name="{{ $task->name }}">
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Mark task as completed') }}"
|
|
||||||
data-task-id="{{ $task->id }}"
|
|
||||||
data-task-name="{{ $task->name }}">
|
|
||||||
<i class="fas fa-check"></i>
|
<i class="fas fa-check"></i>
|
||||||
</a>
|
</a>
|
||||||
@else
|
@else
|
||||||
<a class="btn btn-secondary btn-sm undo-task-button"
|
<a class="btn btn-secondary btn-sm undo-task-button" href="#" data-toggle="tooltip"
|
||||||
href="#"
|
data-placement="left" title="{{ $__t('Undo task', $task->name) }}"
|
||||||
data-toggle="tooltip"
|
data-task-id="{{ $task->id }}" data-task-name="{{ $task->name }}">
|
||||||
data-placement="left"
|
|
||||||
title="{{ $__t('Undo task', $task->name) }}"
|
|
||||||
data-task-id="{{ $task->id }}"
|
|
||||||
data-task-name="{{ $task->name }}">
|
|
||||||
<i class="fas fa-undo"></i>
|
<i class="fas fa-undo"></i>
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/task/') }}{{ $task->id }}?embedded"
|
href="{{ $U('/task/') }}{{ $task->id }}?embedded" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-danger delete-task-button"
|
<a class="btn btn-sm btn-danger delete-task-button" href="#"
|
||||||
href="#"
|
data-task-id="{{ $task->id }}" data-task-name="{{ $task->name }}"
|
||||||
data-task-id="{{ $task->id }}"
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
data-task-name="{{ $task->name }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td id="task-{{ $task->id }}-name"
|
<td id="task-{{ $task->id }}-name"
|
||||||
class="@if($task->done == 1) text-strike-through @endif">
|
class="@if ($task->done == 1) text-strike-through @endif">
|
||||||
{{ $task->name }}
|
{{ $task->name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span>{{ $task->due_date }}</span>
|
<span>{{ $task->due_date }}</span>
|
||||||
<time class="timeago timeago-contextual"
|
<time class="timeago timeago-contextual" datetime="{{ $task->due_date }}"></time>
|
||||||
datetime="{{ $task->due_date }}"></time>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if($task->category_id != null) <span>{{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }}</span> @else <span class="font-italic font-weight-light">{{ $__t('Uncategorized') }}</span>@endif
|
@if ($task->category_id != null)
|
||||||
|
<span>{{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }}</span>
|
||||||
|
@else
|
||||||
|
<span class="font-italic font-weight-light">{{ $__t('Uncategorized') }}</span>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if($task->assigned_to_user_id != null) <span>{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $task->assigned_to_user_id)) }}</span> @endif
|
@if ($task->assigned_to_user_id != null)
|
||||||
|
<span>{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $task->assigned_to_user_id)) }}</span>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
{{ $task->due_type }}
|
{{ $task->due_type }}
|
||||||
@if($task->due_type == 'duetoday')
|
@if ($task->due_type == 'duetoday')
|
||||||
duesoon
|
duesoon
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="d-none">
|
||||||
@if($task->category_id != null) {{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }} @else {{ $__t('Uncategorized') }} @endif
|
@if ($task->category_id != null)
|
||||||
|
{{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }}
|
||||||
|
@else
|
||||||
|
{{ $__t('Uncategorized') }}
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
@include('components.userfields_tbody',
|
@include('components.userfields_tbody', [
|
||||||
array( 'userfields'=> $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $task->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$task->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,58 +5,59 @@
|
||||||
@section('viewJsName', 'transfer')
|
@section('viewJsName', 'transfer')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<script>
|
<script>
|
||||||
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
||||||
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
Grocy.QuantityUnitConversionsResolved = {!! json_encode($quantityUnitConversionsResolved) !!};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<form id="transfer-form"
|
<form id="transfer-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@include('components.productpicker', array(
|
@include('components.productpicker', [
|
||||||
'products' => $products,
|
'productsQuery' => 'query%5B%5D=active%3D1&only_in_stock=1&order=name%3Acollate%20nocase',
|
||||||
'barcodes' => $barcodes,
|
|
||||||
'nextInputSelector' => '#location_id_from',
|
'nextInputSelector' => '#location_id_from',
|
||||||
'disallowAddProductWorkflows' => true
|
'disallowAddProductWorkflows' => true,
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="location_id_from">{{ $__t('From location') }}</label>
|
<label for="location_id_from">{{ $__t('From location') }}</label>
|
||||||
<select required
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
class="custom-control custom-select location-combobox"
|
<select required class="custom-control custom-select location-combobox" id="location_id_from"
|
||||||
id="location_id_from"
|
|
||||||
name="location_id_from">
|
name="location_id_from">
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<option value="{{ $location->id }}"
|
<option value="{{ $location->id }}" data-is-freezer="{{ $location->is_freezer }}">
|
||||||
data-is-freezer="{{ $location->is_freezer }}">{{ $location->name }}</option>
|
{{ $location->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
<div class="invalid-feedback">{{ $__t('A location is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A location is required') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.productamountpicker', array(
|
@include('components.productamountpicker', [
|
||||||
'value' => 1,
|
'value' => 1,
|
||||||
'additionalHtmlContextHelp' => '<div id="tare-weight-handling-info"
|
'additionalHtmlContextHelp' =>
|
||||||
class="text-info font-italic d-none">' . $__t('Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated') . '</div>'
|
'<div id="tare-weight-handling-info"
|
||||||
))
|
class="text-info font-italic d-none">' .
|
||||||
|
$__t(
|
||||||
|
'Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated'
|
||||||
|
) .
|
||||||
|
'</div>',
|
||||||
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="location_id_to">{{ $__t('To location') }}</label>
|
<label for="location_id_to">{{ $__t('To location') }}</label>
|
||||||
<select required
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
class="custom-control custom-select location-combobox"
|
<select required class="custom-control custom-select location-combobox" id="location_id_to"
|
||||||
id="location_id_to"
|
|
||||||
name="location_id_to">
|
name="location_id_to">
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($locations as $location)
|
@foreach ($locations as $location)
|
||||||
<option value="{{ $location->id }}"
|
<option value="{{ $location->id }}" data-is-freezer="{{ $location->is_freezer }}">
|
||||||
data-is-freezer="{{ $location->is_freezer }}">{{ $location->name }}</option>
|
{{ $location->name }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
<div class="invalid-feedback">{{ $__t('A location is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A location is required') }}</div>
|
||||||
|
|
@ -64,29 +65,22 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input class="form-check-input custom-control-input"
|
<input class="form-check-input custom-control-input" type="checkbox" id="use_specific_stock_entry"
|
||||||
type="checkbox"
|
name="use_specific_stock_entry" value="1">
|
||||||
id="use_specific_stock_entry"
|
|
||||||
name="use_specific_stock_entry"
|
|
||||||
value="1">
|
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
for="use_specific_stock_entry">{{ $__t('Use a specific stock item') }}
|
for="use_specific_stock_entry">{{ $__t('Use a specific stock item') }}
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
data-trigger="hover click"
|
||||||
title="{{ $__t('The first item in this list would be picked by the default rule which is "Opened first, then first due first, then first in first out"') }}"></i>
|
title="{{ $__t('The first item in this list would be picked by the default rule which is "Opened first, then first due first, then first in first out"') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<select disabled
|
<select disabled class="custom-control custom-select mt-2" id="specific_stock_entry"
|
||||||
class="custom-control custom-select mt-2"
|
|
||||||
id="specific_stock_entry"
|
|
||||||
name="specific_stock_entry">
|
name="specific_stock_entry">
|
||||||
<option></option>
|
<option></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="save-transfer-button"
|
<button id="save-transfer-button" class="btn btn-success">{{ $__t('OK') }}</button>
|
||||||
class="btn btn-success">{{ $__t('OK') }}</button>
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -94,5 +88,5 @@
|
||||||
<div class="col-12 col-md-6 col-xl-4 hide-when-embedded">
|
<div class="col-12 col-md-6 col-xl-4 hide-when-embedded">
|
||||||
@include('components.productcard')
|
@include('components.productcard')
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,17 @@
|
||||||
@section('viewJsName', 'userentities')
|
@section('viewJsName', 'userentities')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -32,66 +28,54 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="userentities-table"
|
{{-- TODO: DataTables: dynamic data: userentities --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="userentities-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#userentities-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#userentities-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
<th>{{ $__t('Caption') }}</th>
|
<th>{{ $__t('Caption') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($userentities as $userentity)
|
@foreach ($userentities as $userentity)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/userentity/') }}{{ $userentity->id }}?embedded"
|
href="{{ $U('/userentity/') }}{{ $userentity->id }}?embedded" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm userentity-delete-button"
|
<a class="btn btn-danger btn-sm userentity-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-userentity-id="{{ $userentity->id }}"
|
data-userentity-id="{{ $userentity->id }}"
|
||||||
data-userentity-name="{{ $userentity->name }}"
|
data-userentity-name="{{ $userentity->name }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -111,5 +95,5 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,44 @@
|
||||||
@extends('layout.default')
|
@extends('layout.default')
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
@section('title', $__t('Edit userfield'))
|
@section('title', $__t('Edit userfield'))
|
||||||
@else
|
@else
|
||||||
@section('title', $__t('Create userfield'))
|
@section('title', $__t('Create userfield'))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@section('viewJsName', 'userfieldform')
|
@section('viewJsName', 'userfieldform')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-12">
|
<div class="col-lg-6 col-12">
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditMode = '{{ $mode }}';
|
Grocy.EditMode = '{{ $mode }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if ($mode == 'edit')
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditObjectId = {{ $userfield->id }};
|
Grocy.EditObjectId = {{ $userfield->id }};
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form id="userfield-form"
|
<form id="userfield-form" novalidate>
|
||||||
novalidate>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="entity">{{ $__t('Entity') }}</label>
|
<label for="entity">{{ $__t('Entity') }}</label>
|
||||||
<select required
|
{{-- TODO: Select2: dynamic data: userentities --}}
|
||||||
class="custom-control custom-select"
|
<select required class="custom-control custom-select" id="entity" name="entity">
|
||||||
id="entity"
|
|
||||||
name="entity">
|
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($entities as $entity)
|
@foreach ($entities as $entity)
|
||||||
<option @if($mode=='edit'
|
<option @if ($mode == 'edit' && $userfield->entity == $entity) selected="selected" @endif
|
||||||
&&
|
value="{{ $entity }}">{{ $entity }}</option>
|
||||||
$userfield->entity == $entity) selected="selected" @endif value="{{ $entity }}">{{ $entity }}</option>
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
<div class="invalid-feedback">{{ $__t('A entity is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A entity is required') }}</div>
|
||||||
|
|
@ -51,59 +47,50 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">
|
<label for="name">
|
||||||
{{ $__t('Name') }}
|
{{ $__t('Name') }}
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('This is the internal field name, e. g. for the API') }}"></i>
|
title="{{ $__t('This is the internal field name, e. g. for the API') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
<input type="text"
|
<input type="text" class="form-control" required pattern="^[a-zA-Z0-9]*$" id="name" name="name"
|
||||||
class="form-control"
|
value="@if ($mode == 'edit') {{ $userfield->name }} @endif">
|
||||||
required
|
<div class="invalid-feedback">{{ $__t('This is required and can only contain letters and numbers') }}
|
||||||
pattern="^[a-zA-Z0-9]*$"
|
</div>
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
value="@if($mode == 'edit'){{ $userfield->name }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('This is required and can only contain letters and numbers') }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">
|
<label for="name">
|
||||||
{{ $__t('Caption') }}
|
{{ $__t('Caption') }}
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('This is used to display the field on the frontend') }}"></i>
|
title="{{ $__t('This is used to display the field on the frontend') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
<input type="text"
|
<input type="text" class="form-control" required id="caption" name="caption"
|
||||||
class="form-control"
|
value="@if ($mode == 'edit') {{ $userfield->caption }} @endif">
|
||||||
required
|
|
||||||
id="caption"
|
|
||||||
name="caption"
|
|
||||||
value="@if($mode == 'edit'){{ $userfield->caption }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('A caption is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A caption is required') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php if($mode == 'edit' && !empty($userfield->sort_number)) { $value = $userfield->sort_number; } else { $value = ''; } @endphp
|
@php
|
||||||
@include('components.numberpicker', array(
|
if ($mode == 'edit' && !empty($userfield->sort_number)) {
|
||||||
|
$value = $userfield->sort_number;
|
||||||
|
} else {
|
||||||
|
$value = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('components.numberpicker', [
|
||||||
'id' => 'sort_number',
|
'id' => 'sort_number',
|
||||||
'label' => 'Sort number',
|
'label' => 'Sort number',
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
'hint' => $__t('Multiple Userfields will be ordered by that number on the input form')
|
'hint' => $__t('Multiple Userfields will be ordered by that number on the input form'),
|
||||||
))
|
])
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="type">{{ $__t('Type') }}</label>
|
<label for="type">{{ $__t('Type') }}</label>
|
||||||
<select required
|
{{-- TODO: Select2: static data --}}
|
||||||
class="custom-control custom-select"
|
<select required class="custom-control custom-select" id="type" name="type">
|
||||||
id="type"
|
|
||||||
name="type">
|
|
||||||
<option></option>
|
<option></option>
|
||||||
@foreach($userfieldTypes as $userfieldType)
|
@foreach ($userfieldTypes as $userfieldType)
|
||||||
<option @if($mode=='edit'
|
<option @if ($mode == 'edit' && $userfield->type == $userfieldType) selected="selected" @endif
|
||||||
&&
|
value="{{ $userfieldType }}">{{ $__t($userfieldType) }}</option>
|
||||||
$userfield->type == $userfieldType) selected="selected" @endif value="{{ $userfieldType }}">{{ $__t($userfieldType) }}</option>
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
<div class="invalid-feedback">{{ $__t('A type is required') }}</div>
|
<div class="invalid-feedback">{{ $__t('A type is required') }}</div>
|
||||||
|
|
@ -112,17 +99,18 @@
|
||||||
<div class="form-group d-none">
|
<div class="form-group d-none">
|
||||||
<label for="config">{{ $__t('Configuration') }} <span id="config-hint"
|
<label for="config">{{ $__t('Configuration') }} <span id="config-hint"
|
||||||
class="small text-muted"></span></label>
|
class="small text-muted"></span></label>
|
||||||
<textarea class="form-control"
|
<textarea class="form-control" rows="10" id="config" name="config">
|
||||||
rows="10"
|
@if ($mode == 'edit')
|
||||||
id="config"
|
{{ $userfield->config }}
|
||||||
name="config">@if($mode == 'edit'){{ $userfield->config }}@endif</textarea>
|
@endif
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input @if($mode=='edit'
|
<input @if ($mode == 'edit' && $userfield->show_as_column_in_tables == 1) checked @endif
|
||||||
&&
|
class="form-check-input custom-control-input" type="checkbox" id="show_as_column_in_tables"
|
||||||
$userfield->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">
|
name="show_as_column_in_tables" value="1">
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label"
|
||||||
for="show_as_column_in_tables">{{ $__t('Show as column in tables') }}</label>
|
for="show_as_column_in_tables">{{ $__t('Show as column in tables') }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -130,24 +118,21 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="custom-control custom-checkbox">
|
<div class="custom-control custom-checkbox">
|
||||||
<input @if($mode=='edit'
|
<input @if ($mode == 'edit' && $userfield->input_required == 1) checked @endif
|
||||||
&&
|
class="form-check-input custom-control-input" type="checkbox" id="input_required"
|
||||||
$userfield->input_required == 1) checked @endif class="form-check-input custom-control-input" type="checkbox" id="input_required" name="input_required" value="1">
|
name="input_required" value="1">
|
||||||
<label class="form-check-label custom-control-label"
|
<label class="form-check-label custom-control-label" for="input_required">
|
||||||
for="input_required">
|
|
||||||
{{ $__t('Mandatory') }}
|
{{ $__t('Mandatory') }}
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
data-trigger="hover click"
|
||||||
title="{{ $__t('When enabled, then this field must be filled on the destination form') }}"></i>
|
title="{{ $__t('When enabled, then this field must be filled on the destination form') }}"></i>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="save-userfield-button"
|
<button id="save-userfield-button" class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,49 +5,40 @@
|
||||||
@section('viewJsName', 'userfields')
|
@section('viewJsName', 'userfields')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
||||||
id="related-links">
|
id="related-links">
|
||||||
<a id="new-userfield-button"
|
<a id="new-userfield-button" class="btn btn-primary responsive-button show-as-dialog-link"
|
||||||
class="btn btn-primary responsive-button show-as-dialog-link"
|
|
||||||
href="{{ $U('/userfield/new?embedded') }}">
|
href="{{ $U('/userfield/new?embedded') }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
|
|
@ -55,10 +46,10 @@
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Entity') }}</span>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Entity') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
{{-- TODO: Select2: dynamic data: userfields --}}
|
||||||
id="entity-filter">
|
<select class="custom-control custom-select" id="entity-filter">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
@foreach($entities as $entity)
|
@foreach ($entities as $entity)
|
||||||
<option value="{{ $entity }}">{{ $entity }}</option>
|
<option value="{{ $entity }}">{{ $entity }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
|
|
@ -66,27 +57,22 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="userfields-table"
|
{{-- TODO: DataTables: dynamic data: userfields --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="userfields-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#userfields-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#userfields-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Entity') }}</th>
|
<th class="allow-grouping">{{ $__t('Entity') }}</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Name') }}</th>
|
||||||
|
|
@ -96,20 +82,17 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($userfields as $userfield)
|
@foreach ($userfields as $userfield)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/userfield/') }}{{ $userfield->id }}?embedded"
|
href="{{ $U('/userfield/') }}{{ $userfield->id }}?embedded" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm userfield-delete-button"
|
<a class="btn btn-danger btn-sm userfield-delete-button" href="#"
|
||||||
href="#"
|
|
||||||
data-userfield-id="{{ $userfield->id }}"
|
data-userfield-id="{{ $userfield->id }}"
|
||||||
data-userfield-name="{{ $userfield->name }}"
|
data-userfield-name="{{ $userfield->name }}" data-toggle="tooltip"
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -134,5 +117,5 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
@section('viewJsName', 'userobjects')
|
@section('viewJsName', 'userobjects')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title mr-2 order-0">
|
<h2 class="title mr-2 order-0">
|
||||||
|
|
@ -15,16 +15,12 @@
|
||||||
<span class="text-muted small">{{ $userentity->description }}</span>
|
<span class="text-muted small">{{ $userentity->description }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -41,76 +37,71 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="userobjects-table"
|
{{-- TODO: DataTables: dynamic data: userobjects --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="userobjects-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right d-print-none"></th>
|
<th class="border-right d-print-none"></th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($userobjects as $userobject)
|
@foreach ($userobjects as $userobject)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right d-print-none">
|
<td class="fit-content border-right d-print-none">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
href="{{ $U('/userobject/' . $userentity->name . '/') }}{{ $userobject->id }}?embedded"
|
href="{{ $U('/userobject/' . $userentity->name . '/') }}{{ $userobject->id }}?embedded"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm userobject-delete-button"
|
<a class="btn btn-danger btn-sm userobject-delete-button" href="#"
|
||||||
href="#"
|
data-userobject-id="{{ $userobject->id }}" data-toggle="tooltip"
|
||||||
data-userobject-id="{{ $userobject->id }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $userobject->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$userobject->id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,23 @@
|
||||||
@section('viewJsName', 'users')
|
@section('viewJsName', 'users')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h2 class="title">@yield('title')</h2>
|
<h2 class="title">@yield('title')</h2>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#table-filter-row">
|
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
type="button"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#related-links">
|
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
||||||
id="related-links">
|
id="related-links">
|
||||||
<a class="btn btn-primary responsive-button"
|
<a class="btn btn-primary responsive-button" href="{{ $U('/user/new') }}">
|
||||||
href="{{ $U('/user/new') }}">
|
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Add') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
||||||
|
|
@ -36,77 +31,62 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-2">
|
<hr class="my-2">
|
||||||
|
|
||||||
<div class="row collapse d-md-flex"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
id="table-filter-row">
|
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text"
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
id="search"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="{{ $__t('Search') }}">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<a id="clear-filter-button"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
{{ $__t('Clear filter') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table id="users-table"
|
{{-- TODO: DataTables: dynamic data: users --}}
|
||||||
class="table table-sm table-striped nowrap w-100">
|
<table id="users-table" class="table table-sm table-striped nowrap w-100">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#users-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
title="{{ $__t('Table options') }}"
|
|
||||||
data-table-selector="#users-table"
|
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</th>
|
</th>
|
||||||
<th>{{ $__t('Username') }}</th>
|
<th>{{ $__t('Username') }}</th>
|
||||||
<th>{{ $__t('First name') }}</th>
|
<th>{{ $__t('First name') }}</th>
|
||||||
<th>{{ $__t('Last name') }}</th>
|
<th>{{ $__t('Last name') }}</th>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
@include('components.userfields_thead', [
|
||||||
'userfields' => $userfields
|
'userfields' => $userfields,
|
||||||
))
|
])
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="d-none">
|
<tbody class="d-none">
|
||||||
@foreach($users as $user)
|
@foreach ($users as $user)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fit-content border-right">
|
<td class="fit-content border-right">
|
||||||
<a class="btn btn-info btn-sm"
|
<a class="btn btn-info btn-sm" href="{{ $U('/user/') }}{{ $user->id }}"
|
||||||
href="{{ $U('/user/') }}{{ $user->id }}"
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Edit this item') }}">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-info btn-sm"
|
<a class="btn btn-info btn-sm" href="{{ $U('/user/' . $user->id . '/permissions') }}"
|
||||||
href="{{ $U('/user/' . $user->id . '/permissions') }}"
|
data-toggle="tooltip" title="{{ $__t('Configure user permissions') }}">
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Configure user permissions') }}">
|
|
||||||
<i class="fas fa-lock"></i>
|
<i class="fas fa-lock"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-danger btn-sm user-delete-button @if($user->id == GROCY_USER_ID) disabled @endif"
|
<a class="btn btn-danger btn-sm user-delete-button @if ($user->id == GROCY_USER_ID) disabled @endif"
|
||||||
href="#"
|
href="#" data-user-id="{{ $user->id }}"
|
||||||
data-user-id="{{ $user->id }}"
|
data-user-username="{{ $user->username }}" data-toggle="tooltip"
|
||||||
data-user-username="{{ $user->username }}"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -121,14 +101,18 @@
|
||||||
{{ $user->last_name }}
|
{{ $user->last_name }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $user->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$user->id
|
||||||
|
),
|
||||||
|
])
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
49
yarn.lock
49
yarn.lock
|
|
@ -238,7 +238,7 @@ datatables.net-bs4@1.10.16:
|
||||||
datatables.net "1.10.16"
|
datatables.net "1.10.16"
|
||||||
jquery ">=1.7"
|
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"
|
version "1.11.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-bs4/-/datatables.net-bs4-1.11.4.tgz#caa82ab1a989bf1462f075b91213df865060d1ec"
|
resolved "https://registry.yarnpkg.com/datatables.net-bs4/-/datatables.net-bs4-1.11.4.tgz#caa82ab1a989bf1462f075b91213df865060d1ec"
|
||||||
integrity sha512-4V2uSxFloX1jRIsy4eAt1INyp5M5Pq5SV017/naq3zpVKraaFwqFjLhtkx64UHGXqcPj7egvj27dVcdnNIKnNA==
|
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"
|
datatables.net ">=1.11.3"
|
||||||
jquery ">=1.7"
|
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"
|
version "1.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-colreorder-bs4/-/datatables.net-colreorder-bs4-1.5.5.tgz#52ca2f95148572583ad619d6c9cdb44f1952d355"
|
resolved "https://registry.yarnpkg.com/datatables.net-colreorder-bs4/-/datatables.net-colreorder-bs4-1.5.5.tgz#52ca2f95148572583ad619d6c9cdb44f1952d355"
|
||||||
integrity sha512-MGAJ/k/FeSK2Kccio5k0oBRacBpmaIKP2wXYfC64ONZFjOFxKBSmFevfg7yPdipYdYDwoQqDnmw0MpdIL7UUug==
|
integrity sha512-MGAJ/k/FeSK2Kccio5k0oBRacBpmaIKP2wXYfC64ONZFjOFxKBSmFevfg7yPdipYdYDwoQqDnmw0MpdIL7UUug==
|
||||||
|
|
@ -255,7 +263,7 @@ datatables.net-colreorder-bs4@^1.5.2:
|
||||||
datatables.net-colreorder ">=1.5.4"
|
datatables.net-colreorder ">=1.5.4"
|
||||||
jquery ">=1.7"
|
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"
|
version "1.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-colreorder/-/datatables.net-colreorder-1.5.5.tgz#0de93e460cba5eb0167c0c491a2da0c76a2e3b12"
|
resolved "https://registry.yarnpkg.com/datatables.net-colreorder/-/datatables.net-colreorder-1.5.5.tgz#0de93e460cba5eb0167c0c491a2da0c76a2e3b12"
|
||||||
integrity sha512-AUwv5A/87I4hg7GY/WbhRrDhqng9b019jLvvKutHibSPCEtMDWqyNtuP0q8zYoquqU9UQ1/nqXLW/ld8TzIDYQ==
|
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"
|
datatables.net ">=1.11.3"
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net-plugins@^1.10.20:
|
datatables.net-plugins@^1.11.5:
|
||||||
version "1.11.4"
|
version "1.11.5"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-plugins/-/datatables.net-plugins-1.11.4.tgz#8eb7915cd9f43ba8ba256b89e06917aa24d1ac41"
|
resolved "https://registry.yarnpkg.com/datatables.net-plugins/-/datatables.net-plugins-1.11.5.tgz#c53ebbd0ab3473a08c6ae36eb1990a66de599b89"
|
||||||
integrity sha512-39yyyoCCavagE0mO1BFsrRPeak5BwOlbtSACdGpPNf3jG5Lm7D6vEUPPcpGy6eLxjCiG/orMxlAqb8E5lSZtoA==
|
integrity sha512-+Rsf/fyLG8GyFqp7Bvd1ElqWGQO3NPsx2VADn9X8QaZbctshGVW0sqvR5V7iHHgY6OY1LR0+t6qIMhan9BM4gA==
|
||||||
|
|
||||||
datatables.net-rowgroup-bs4@^1.1.2:
|
datatables.net-rowgroup-bs4@^1.1.4:
|
||||||
version "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"
|
resolved "https://registry.yarnpkg.com/datatables.net-rowgroup-bs4/-/datatables.net-rowgroup-bs4-1.1.4.tgz#dd4fad888edea895acd06fe8cf66816809d78eec"
|
||||||
integrity sha512-D0+LxraRjvV1RpPNtXJuW9Z4Jn90Sykb7ytJC/5eJsEYc9WnLUvxWEok7fqPpl3dWphQKg5ZbWpKG55Gd1IIXA==
|
integrity sha512-D0+LxraRjvV1RpPNtXJuW9Z4Jn90Sykb7ytJC/5eJsEYc9WnLUvxWEok7fqPpl3dWphQKg5ZbWpKG55Gd1IIXA==
|
||||||
|
|
@ -277,7 +285,7 @@ datatables.net-rowgroup-bs4@^1.1.2:
|
||||||
datatables.net-rowgroup ">=1.1.3"
|
datatables.net-rowgroup ">=1.1.3"
|
||||||
jquery ">=1.7"
|
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"
|
version "1.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-rowgroup/-/datatables.net-rowgroup-1.1.4.tgz#3eea91951d46f6c207d2e0c03cb3d635b7b09689"
|
resolved "https://registry.yarnpkg.com/datatables.net-rowgroup/-/datatables.net-rowgroup-1.1.4.tgz#3eea91951d46f6c207d2e0c03cb3d635b7b09689"
|
||||||
integrity sha512-Oe9mL3X8RXLOQZblJVWTYD0melyw3xoPeQ3T2x1k2guTFxob8/2caKuzn95oFJau6tvbhsvY/QneTaCzHRKnnQ==
|
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"
|
datatables.net ">=1.11.3"
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net-select-bs4@^1.3.1:
|
datatables.net-select-bs4@^1.3.4:
|
||||||
version "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"
|
resolved "https://registry.yarnpkg.com/datatables.net-select-bs4/-/datatables.net-select-bs4-1.3.4.tgz#07336260be0aa7741a61b82188350f4d1e422a02"
|
||||||
integrity sha512-hXxxTwR9Mx8xwD55g8hNiLt035afguKZ9Ejsdm5/mo3wmm9ml7gs8QG5fJuMRwtrdP9EKcnjc54+zVoHymEcgw==
|
integrity sha512-hXxxTwR9Mx8xwD55g8hNiLt035afguKZ9Ejsdm5/mo3wmm9ml7gs8QG5fJuMRwtrdP9EKcnjc54+zVoHymEcgw==
|
||||||
|
|
@ -294,7 +302,7 @@ datatables.net-select-bs4@^1.3.1:
|
||||||
datatables.net-select ">=1.3.3"
|
datatables.net-select ">=1.3.3"
|
||||||
jquery ">=1.7"
|
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"
|
version "1.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net-select/-/datatables.net-select-1.3.4.tgz#7970587a8d8db8ba70a4cccb89b8519bb518116d"
|
resolved "https://registry.yarnpkg.com/datatables.net-select/-/datatables.net-select-1.3.4.tgz#7970587a8d8db8ba70a4cccb89b8519bb518116d"
|
||||||
integrity sha512-iQ/dBHIWkhfCBxzNdtef79seCNO1ZsA5zU0Uiw3R2mlwmjcJM1xn6pFNajke6SX7VnlzndGDHGqzzEljSqz4pA==
|
integrity sha512-iQ/dBHIWkhfCBxzNdtef79seCNO1ZsA5zU0Uiw3R2mlwmjcJM1xn6pFNajke6SX7VnlzndGDHGqzzEljSqz4pA==
|
||||||
|
|
@ -309,13 +317,20 @@ datatables.net@1.10.16:
|
||||||
dependencies:
|
dependencies:
|
||||||
jquery ">=1.7"
|
jquery ">=1.7"
|
||||||
|
|
||||||
datatables.net@>=1.11.3, datatables.net@^1.10.22:
|
datatables.net@>=1.11.3:
|
||||||
version "1.11.4"
|
version "1.11.4"
|
||||||
resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.11.4.tgz#5f3e1ec134fa532e794fbd47c13f8333d7a5c455"
|
resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.11.4.tgz#5f3e1ec134fa532e794fbd47c13f8333d7a5c455"
|
||||||
integrity sha512-z9LG4O0VYOYzp+rnArLExvnUWV8ikyWBcHYZEKDfVuz7BKxQdEq4a/tpO0Trbm+FL1+RY7UEIh+UcYNY/hwGxA==
|
integrity sha512-z9LG4O0VYOYzp+rnArLExvnUWV8ikyWBcHYZEKDfVuz7BKxQdEq4a/tpO0Trbm+FL1+RY7UEIh+UcYNY/hwGxA==
|
||||||
dependencies:
|
dependencies:
|
||||||
jquery ">=1.7"
|
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:
|
delayed-stream@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
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"
|
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
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:
|
sprintf-js@^1.0.3, sprintf-js@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
|
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user