mirror of
https://github.com/grocy/grocy.git
synced 2026-04-07 13:26:14 +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)
|
protected function applyOrder(Result $data, array $query): Result
|
||||||
{
|
{
|
||||||
$data = $data->orderBy($parts[0]);
|
if (isset($query['order'])) {
|
||||||
}
|
$parts = explode(',', $query['order']);
|
||||||
else
|
foreach ($parts as $part) {
|
||||||
{
|
$col_dir = explode(':', $part, 2);
|
||||||
if ($parts[1] != 'asc' && $parts[1] != 'desc')
|
if (count($col_dir) == 1) {
|
||||||
{
|
$data = $data->orderBy($col_dir[0]);
|
||||||
throw new \Exception('Invalid sort order ' . $parts[1]);
|
} else {
|
||||||
|
if ($col_dir[1] != 'asc' && $col_dir[1] != 'desc' && $col_dir[1] != 'collate nocase') {
|
||||||
|
throw new \Exception('Invalid sort order ' . $col_dir[1]);
|
||||||
|
}
|
||||||
|
$data = $data->orderBy($col_dir[0], $col_dir[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $data->orderBy($parts[0], $parts[1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,58 +133,73 @@ class BaseApiController extends BaseController
|
||||||
|
|
||||||
protected function filter(Result $data, array $query): Result
|
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 . ')'
|
||||||
. '(?P<op>' . self::PATTERN_OPERATOR . ')'
|
. '(?P<op>' . self::PATTERN_OPERATOR . ')'
|
||||||
. '(?P<value>' . self::PATTERN_VALUE . ')/u',
|
. '(?P<value>' . self::PATTERN_VALUE . ')/u',
|
||||||
$q,
|
$q,
|
||||||
$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)
|
|
||||||
{
|
|
||||||
$value = FindObjectInArrayByPropertyValue(FindAllObjectsInArrayByPropertyValue($allUserfieldValues, 'object_id', $object->id), 'name', $userfield->name);
|
|
||||||
if ($value)
|
|
||||||
{
|
|
||||||
$userfieldKeyValuePairs[$userfield->name] = $value->value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$userfieldKeyValuePairs[$userfield->name] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$object->userfields = $userfieldKeyValuePairs;
|
// apply limit/order
|
||||||
}
|
$objects = $this->applyLimit($objects, $query);
|
||||||
|
$objects = $this->applyOrder($objects, $query);
|
||||||
|
|
||||||
|
// add entity-specific queries
|
||||||
|
if ($args['entity'] === 'products' && isset($query['only_in_stock'])) {
|
||||||
|
$objects = $objects->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)');
|
||||||
|
}
|
||||||
|
|
||||||
|
// add userfields and joins to objects
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$this->addUserfieldsAndJoinsToRow($object, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->ApiResponse($response, $objects);
|
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,377 +1,457 @@
|
||||||
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 addProductWorkflowsAdditionalCssClasses = "";
|
||||||
var possibleOptionElement = [];
|
if (Grocy.Components.ProductPicker.GetOption('disallow-add-product-workflows')) {
|
||||||
|
addProductWorkflowsAdditionalCssClasses = "d-none";
|
||||||
// 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)
|
var embedded = "";
|
||||||
{
|
if (GetUriParam("embedded") !== undefined) {
|
||||||
$('#product_id').val(possibleOptionElement.val());
|
embedded = "embedded";
|
||||||
$('#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();
|
var buttons = {
|
||||||
if (input.length > 0 && optionElement.length === 0 && GetUriParam('flow') === undefined && Grocy.Components.ProductPicker.GetPicker().parent().data('disallow-all-product-workflows').toString() === "false")
|
cancel: {
|
||||||
{
|
label: __t('Cancel'),
|
||||||
var addProductWorkflowsAdditionalCssClasses = "";
|
className: 'btn-secondary responsive-button',
|
||||||
if (Grocy.Components.ProductPicker.GetPicker().parent().data('disallow-add-product-workflows').toString() === "true")
|
callback: function() {
|
||||||
{
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
addProductWorkflowsAdditionalCssClasses = "d-none";
|
Grocy.Components.ProductPicker.Clear();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
var embedded = "";
|
addnewproduct: {
|
||||||
if (GetUriParam("embedded") !== undefined)
|
label: '<strong>P</strong> ' + __t('Add as new product'),
|
||||||
{
|
className: 'btn-success add-new-product-dialog-button responsive-button ' + addProductWorkflowsAdditionalCssClasses,
|
||||||
embedded = "embedded";
|
callback: function() {
|
||||||
}
|
// 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)
|
||||||
var buttons = {
|
if (GetUriParam("list") !== undefined) {
|
||||||
cancel: {
|
embedded += "&list=" + GetUriParam("list");
|
||||||
label: __t('Cancel'),
|
|
||||||
className: 'btn-secondary responsive-button',
|
|
||||||
callback: function()
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addnewproduct: {
|
|
||||||
label: '<strong>P</strong> ' + __t('Add as new product'),
|
|
||||||
className: 'btn-success add-new-product-dialog-button responsive-button ' + addProductWorkflowsAdditionalCssClasses,
|
|
||||||
callback: function()
|
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
if (GetUriParam("list") !== undefined)
|
|
||||||
{
|
|
||||||
embedded += "&list=" + GetUriParam("list");
|
|
||||||
}
|
|
||||||
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
|
||||||
window.location.href = U('/product/new?flow=InplaceNewProductWithName&name=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(Grocy.CurrentUrlRelative + "?flow=InplaceNewProductWithName&" + embedded) + "&" + embedded);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addbarcode: {
|
|
||||||
label: '<strong>B</strong> ' + __t('Add as barcode to existing product'),
|
|
||||||
className: 'btn-info add-new-barcode-dialog-button responsive-button',
|
|
||||||
callback: function()
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
|
||||||
window.location.href = U(Grocy.CurrentUrlRelative + '?flow=InplaceAddBarcodeToExistingProduct&barcode=' + encodeURIComponent(input) + "&" + embedded);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addnewproductwithbarcode: {
|
|
||||||
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,
|
|
||||||
callback: function()
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_DISABLE_BROWSER_BARCODE_CAMERA_SCANNING)
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
{
|
window.location.href = U('/product/new?flow=InplaceNewProductWithName&name=' + encodeURIComponent(lastProductSearchTerm) + '&returnto=' + encodeURIComponent(Grocy.CurrentUrlRelative + "?flow=InplaceNewProductWithName&" + embedded) + "&" + embedded);
|
||||||
buttons.retrycamerascanning = {
|
}
|
||||||
label: '<strong>C</strong> <i class="fas fa-camera"></i>',
|
},
|
||||||
className: 'btn-primary responsive-button retry-camera-scanning-button',
|
addbarcode: {
|
||||||
callback: function()
|
label: '<strong>B</strong> ' + __t('Add as barcode to existing product'),
|
||||||
{
|
className: 'btn-info add-new-barcode-dialog-button responsive-button',
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
callback: function() {
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
$("#barcodescanner-start-button").click();
|
window.location.href = U(Grocy.CurrentUrlRelative + '?flow=InplaceAddBarcodeToExistingProduct&barcode=' + encodeURIComponent(lastProductSearchTerm) + "&" + embedded);
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
addnewproductwithbarcode: {
|
||||||
|
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,
|
||||||
|
callback: function() {
|
||||||
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
|
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) {
|
||||||
|
buttons.retrycamerascanning = {
|
||||||
|
label: '<strong>C</strong> <i class="fas fa-camera"></i>',
|
||||||
|
className: 'btn-primary responsive-button retry-camera-scanning-button',
|
||||||
|
callback: function() {
|
||||||
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
|
Grocy.Components.ProductPicker.Clear();
|
||||||
|
$("#barcodescanner-start-button").trigger('click');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// The product picker contains only in-stock products on some pages,
|
||||||
|
// so only show the workflow dialog when the entered input
|
||||||
|
// does not match in existing product (name) or barcode,
|
||||||
|
// otherwise an error validation message that the product is not in stock
|
||||||
|
var existsAsProduct = false;
|
||||||
|
var existsAsBarcode = false;
|
||||||
|
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + lastProductSearchTerm,
|
||||||
|
function(barcodeResult) {
|
||||||
|
if (barcodeResult.length > 0) {
|
||||||
|
existsAsProduct = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The product picker contains only in-stock products on some pages,
|
Grocy.Api.Get('objects/products?query[]=name=' + lastProductSearchTerm,
|
||||||
// so only show the workflow dialog when the entered input
|
function(productResult) {
|
||||||
// does not match in existing product (name) or barcode,
|
if (productResult.length > 0) {
|
||||||
// otherwise an error validation message that the product is not in stock
|
|
||||||
var existsAsProduct = false;
|
|
||||||
var existsAsBarcode = false;
|
|
||||||
Grocy.Api.Get('objects/product_barcodes?query[]=barcode=' + input,
|
|
||||||
function(barcodeResult)
|
|
||||||
{
|
|
||||||
if (barcodeResult.length > 0)
|
|
||||||
{
|
|
||||||
existsAsProduct = true;
|
existsAsProduct = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grocy.Api.Get('objects/products?query[]=name=' + input,
|
if (!existsAsBarcode && !existsAsProduct) {
|
||||||
function(productResult)
|
Grocy.Components.ProductPicker.PopupOpen = true;
|
||||||
{
|
bootbox.dialog({
|
||||||
if (productResult.length > 0)
|
message: __t('"%s" could not be resolved to a product, how do you want to proceed?', lastProductSearchTerm),
|
||||||
{
|
title: __t('Create or assign product'),
|
||||||
existsAsProduct = true;
|
onEscape: function() {
|
||||||
}
|
Grocy.Components.ProductPicker.PopupOpen = false;
|
||||||
|
|
||||||
if (!existsAsBarcode && !existsAsProduct)
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = true;
|
|
||||||
bootbox.dialog({
|
|
||||||
message: __t('"%s" could not be resolved to a product, how do you want to proceed?', input),
|
|
||||||
title: __t('Create or assign product'),
|
|
||||||
onEscape: function()
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductPicker.PopupOpen = false;
|
|
||||||
Grocy.Components.ProductPicker.SetValue('');
|
|
||||||
},
|
|
||||||
size: 'large',
|
|
||||||
backdrop: true,
|
|
||||||
closeButton: false,
|
|
||||||
buttons: buttons
|
|
||||||
}).on('keypress', function(e)
|
|
||||||
{
|
|
||||||
if (e.key === 'B' || e.key === 'b')
|
|
||||||
{
|
|
||||||
$('.add-new-barcode-dialog-button').not(".d-none").click();
|
|
||||||
}
|
|
||||||
if (e.key === 'p' || e.key === 'P')
|
|
||||||
{
|
|
||||||
$('.add-new-product-dialog-button').not(".d-none").click();
|
|
||||||
}
|
|
||||||
if (e.key === 'a' || e.key === 'A')
|
|
||||||
{
|
|
||||||
$('.add-new-product-with-barcode-dialog-button').not(".d-none").click();
|
|
||||||
}
|
|
||||||
if (e.key === 'c' || e.key === 'C')
|
|
||||||
{
|
|
||||||
$('.retry-camera-scanning-button').not(".d-none").click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Grocy.Components.ProductAmountPicker.Reset();
|
|
||||||
Grocy.Components.ProductPicker.Clear();
|
Grocy.Components.ProductPicker.Clear();
|
||||||
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
},
|
||||||
Grocy.Components.ProductPicker.ShowCustomError(__t('This product is not in stock'));
|
size: 'large',
|
||||||
Grocy.Components.ProductPicker.GetInputElement().focus();
|
backdrop: true,
|
||||||
|
closeButton: false,
|
||||||
|
buttons: buttons
|
||||||
|
}).on('keypress', function(e) {
|
||||||
|
if (e.key === 'B' || e.key === 'b') {
|
||||||
|
$('.add-new-barcode-dialog-button').not(".d-none").trigger('click');
|
||||||
}
|
}
|
||||||
},
|
if (e.key === 'p' || e.key === 'P') {
|
||||||
function(xhr)
|
$('.add-new-product-dialog-button').not(".d-none").trigger('click');
|
||||||
{
|
}
|
||||||
console.error(xhr);
|
if (e.key === 'a' || e.key === 'A') {
|
||||||
}
|
$('.add-new-product-with-barcode-dialog-button').not(".d-none").trigger('click');
|
||||||
);
|
}
|
||||||
|
if (e.key === 'c' || e.key === 'C') {
|
||||||
|
$('.retry-camera-scanning-button').not(".d-none").trigger('click');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Grocy.Components.ProductAmountPicker.Reset();
|
||||||
|
Grocy.Components.ProductPicker.Clear();
|
||||||
|
Grocy.FrontendHelpers.ValidateForm('consume-form');
|
||||||
|
Grocy.Components.ProductPicker.ShowCustomError(__t('This product is not in stock'));
|
||||||
|
Grocy.Components.ProductPicker.Focus();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
function(xhr)
|
function(xhr) {
|
||||||
{
|
|
||||||
console.error(xhr);
|
console.error(xhr);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
function(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
|
|
||||||
{
|
|
||||||
UpdateUriParam("product", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.location.reload();
|
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: [{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
});
|
||||||
{
|
|
||||||
|
$("#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,140 +5,124 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<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"
|
||||||
</button>
|
href="{{ $U('/battery/new?embedded') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
||||||
<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('/userfields?entity=batteries') }}">
|
||||||
href="{{ $U('/battery/new?embedded') }}">
|
{{ $__t('Configure userfields') }}
|
||||||
{{ $__t('Add') }}
|
</a>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=batteries') }}">
|
</div>
|
||||||
{{ $__t('Configure userfields') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="form-check custom-control custom-checkbox">
|
||||||
</div>
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-disabled">
|
||||||
</div>
|
<label class="form-check-label custom-control-label" for="show-disabled">
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
{{ $__t('Show disabled') }}
|
||||||
<div class="form-check custom-control custom-checkbox">
|
</label>
|
||||||
<input class="form-check-input custom-control-input"
|
</div>
|
||||||
type="checkbox"
|
</div>
|
||||||
id="show-disabled">
|
<div class="col">
|
||||||
<label class="form-check-label custom-control-label"
|
<div class="float-right">
|
||||||
for="show-disabled">
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
{{ $__t('Show disabled') }}
|
{{ $__t('Clear filter') }}
|
||||||
</label>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
</div>
|
||||||
<div class="float-right">
|
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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"
|
</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Name') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th class="allow-grouping">{{ $__t('Used in') }}</th>
|
||||||
<th>{{ $__t('Description') }}</th>
|
<th class="allow-grouping">{{ $__t('Charge cycle interval (days)') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Used in') }}</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" href="#"
|
||||||
<a class="btn btn-danger btn-sm battery-delete-button permission-MASTER_DATA_EDIT"
|
data-battery-id="{{ $battery->id }}" data-battery-name="{{ $battery->name }}"
|
||||||
href="#"
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
data-battery-id="{{ $battery->id }}"
|
<i class="fas fa-trash"></i>
|
||||||
data-battery-name="{{ $battery->name }}"
|
</a>
|
||||||
data-toggle="tooltip"
|
</td>
|
||||||
title="{{ $__t('Delete this item') }}">
|
<td>
|
||||||
<i class="fas fa-trash"></i>
|
{{ $battery->name }}
|
||||||
</a>
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{{ $battery->description }}
|
||||||
{{ $battery->name }}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{{ $battery->used_in }}
|
||||||
{{ $battery->description }}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{{ $battery->charge_interval_days }}
|
||||||
{{ $battery->used_in }}
|
</td>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ $battery->charge_interval_days }}
|
|
||||||
</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,125 +5,110 @@
|
||||||
@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-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
</div>
|
||||||
</button>
|
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Battery') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
{{-- TODO: Select2: dynamic data: batteries --}}
|
||||||
<div class="input-group-prepend">
|
<select class="custom-control custom-select" id="battery-filter">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Battery') }}</span>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
</div>
|
@foreach ($batteries as $battery)
|
||||||
<select class="custom-control custom-select"
|
<option value="{{ $battery->id }}">{{ $battery->name }}</option>
|
||||||
id="battery-filter">
|
@endforeach
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
</select>
|
||||||
@foreach($batteries as $battery)
|
</div>
|
||||||
<option value="{{ $battery->id }}">{{ $battery->name }}</option>
|
</div>
|
||||||
@endforeach
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
</select>
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
<select class="custom-control custom-select" id="daterange-filter">
|
||||||
<div class="input-group-prepend">
|
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
<option value="6">{{ $__n(6, '%s month', '%s months') }}</option>
|
||||||
</div>
|
<option value="12">{{ $__n(1, '%s year', '%s years') }}</option>
|
||||||
<select class="custom-control custom-select"
|
<option value="24" selected>{{ $__n(2, '%s month', '%s years') }}</option>
|
||||||
id="daterange-filter">
|
<option value="9999">{{ $__t('All') }}</option>
|
||||||
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
</select>
|
||||||
<option value="6">{{ $__n(6, '%s month', '%s months') }}</option>
|
</div>
|
||||||
<option value="12">{{ $__n(1, '%s year', '%s years') }}</option>
|
</div>
|
||||||
<option value="24"
|
<div class="col">
|
||||||
selected>{{ $__n(2, '%s month', '%s years') }}</option>
|
<div class="float-right">
|
||||||
<option value="9999">{{ $__t('All') }}</option>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</select>
|
{{ $__t('Clear filter') }}
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
</div>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#batteries-journal-table"
|
<th class="allow-grouping">{{ $__t('Battery') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Tracked time') }}</th>
|
||||||
</th>
|
</tr>
|
||||||
<th class="allow-grouping">{{ $__t('Battery') }}</th>
|
</thead>
|
||||||
<th>{{ $__t('Tracked time') }}</th>
|
<tbody class="d-none">
|
||||||
</tr>
|
@foreach ($chargeCycles as $chargeCycleEntry)
|
||||||
</thead>
|
<tr id="charge-cycle-{{ $chargeCycleEntry->id }}-row"
|
||||||
<tbody class="d-none">
|
class="@if ($chargeCycleEntry->undone == 1) text-muted @endif">
|
||||||
@foreach($chargeCycles as $chargeCycleEntry)
|
<td class="fit-content border-right">
|
||||||
<tr id="charge-cycle-{{ $chargeCycleEntry->id }}-row"
|
<a class="btn btn-secondary btn-xs undo-battery-execution-button @if ($chargeCycleEntry->undone == 1) disabled @endif permission-BATTERIES_UNDO_CHARGE_CYCLE"
|
||||||
class="@if($chargeCycleEntry->undone == 1) text-muted @endif">
|
href="#" data-charge-cycle-id="{{ $chargeCycleEntry->id }}" data-toggle="tooltip"
|
||||||
<td class="fit-content border-right">
|
data-placement="left" title="{{ $__t('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"
|
<i class="fas fa-undo"></i>
|
||||||
href="#"
|
</a>
|
||||||
data-charge-cycle-id="{{ $chargeCycleEntry->id }}"
|
</td>
|
||||||
data-toggle="tooltip"
|
<td>
|
||||||
data-placement="left"
|
<span
|
||||||
title="{{ $__t('Undo charge cycle') }}">
|
class="name-anchor @if ($chargeCycleEntry->undone == 1) text-strike-through @endif">{{ FindObjectInArrayByPropertyValue($batteries, 'id', $chargeCycleEntry->battery_id)->name }}</span>
|
||||||
<i class="fas fa-undo"></i>
|
@if ($chargeCycleEntry->undone == 1)
|
||||||
</a>
|
<br>
|
||||||
</td>
|
{{ $__t('Undone on') . ' ' . $chargeCycleEntry->undone_timestamp }}
|
||||||
<td>
|
<time class="timeago timeago-contextual"
|
||||||
<span class="name-anchor @if($chargeCycleEntry->undone == 1) text-strike-through @endif">{{ FindObjectInArrayByPropertyValue($batteries, 'id', $chargeCycleEntry->battery_id)->name }}</span>
|
datetime="{{ $chargeCycleEntry->undone_timestamp }}"></time>
|
||||||
@if($chargeCycleEntry->undone == 1)
|
@endif
|
||||||
<br>
|
</td>
|
||||||
{{ $__t('Undone on') . ' ' . $chargeCycleEntry->undone_timestamp }}
|
<td>
|
||||||
<time class="timeago timeago-contextual"
|
{{ $chargeCycleEntry->tracked_time }}
|
||||||
datetime="{{ $chargeCycleEntry->undone_timestamp }}"></time>
|
<time class="timeago timeago-contextual"
|
||||||
@endif
|
datetime="{{ $chargeCycleEntry->tracked_time }}"></time>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
</tr>
|
||||||
{{ $chargeCycleEntry->tracked_time }}
|
@endforeach
|
||||||
<time class="timeago timeago-contextual"
|
</tbody>
|
||||||
datetime="{{ $chargeCycleEntry->tracked_time }}"></time>
|
</table>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,223 +5,199 @@
|
||||||
@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"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-target="#related-links">
|
</button>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
</button>
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
href="{{ $U('/batteriesjournal') }}">
|
||||||
id="related-links">
|
{{ $__t('Journal') }}
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
</a>
|
||||||
href="{{ $U('/batteriesjournal') }}">
|
</div>
|
||||||
{{ $__t('Journal') }}
|
</div>
|
||||||
</a>
|
<div class="border-top border-bottom my-2 py-1">
|
||||||
</div>
|
<div id="info-overdue-batteries" data-status-filter="overdue"
|
||||||
</div>
|
class="error-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div class="border-top border-bottom my-2 py-1">
|
<div id="info-due-today-batteries" data-status-filter="duetoday"
|
||||||
<div id="info-overdue-batteries"
|
class="normal-message status-filter-message responsive-button mr-2"></div>
|
||||||
data-status-filter="overdue"
|
<div id="info-due-soon-batteries" data-status-filter="duesoon" data-next-x-days="{{ $nextXDays }}"
|
||||||
class="error-message status-filter-message responsive-button mr-2"></div>
|
class="warning-message status-filter-message responsive-button @if ($nextXDays == 0) d-none @endif">
|
||||||
<div id="info-due-today-batteries"
|
</div>
|
||||||
data-status-filter="duetoday"
|
<div class="float-right">
|
||||||
class="normal-message status-filter-message responsive-button mr-2"></div>
|
<a class="btn btn-sm btn-outline-info d-md-none mt-1" data-toggle="collapse" href="#table-filter-row"
|
||||||
<div id="info-due-soon-batteries"
|
role="button">
|
||||||
data-status-filter="duesoon"
|
<i class="fas fa-filter"></i>
|
||||||
data-next-x-days="{{ $nextXDays }}"
|
</a>
|
||||||
class="warning-message status-filter-message responsive-button @if($nextXDays == 0) d-none @endif"></div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info mt-1" href="#">
|
||||||
<div class="float-right">
|
{{ $__t('Clear filter') }}
|
||||||
<a class="btn btn-sm btn-outline-info d-md-none mt-1"
|
</a>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
href="#table-filter-row"
|
</div>
|
||||||
role="button">
|
</div>
|
||||||
<i class="fas fa-filter"></i>
|
</div>
|
||||||
</a>
|
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info mt-1"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
<div class="input-group-prepend">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<option value="overdue">{{ $__t('Overdue') }}</option>
|
||||||
</div>
|
<option value="duetoday">{{ $__t('Due today') }}</option>
|
||||||
<select class="custom-control custom-select"
|
@if ($nextXDays > 0)
|
||||||
id="status-filter">
|
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
@endif
|
||||||
<option value="overdue">{{ $__t('Overdue') }}</option>
|
</select>
|
||||||
<option value="duetoday">{{ $__t('Due today') }}</option>
|
</div>
|
||||||
@if($nextXDays > 0)
|
</div>
|
||||||
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
</div>
|
||||||
@endif
|
|
||||||
</select>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#batteries-overview-table"
|
<th>{{ $__t('Battery') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th class="allow-grouping">{{ $__t('Used in') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Last charged') }}</th>
|
||||||
<th>{{ $__t('Battery') }}</th>
|
<th>{{ $__t('Next planned charge cycle') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Used in') }}</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th>{{ $__t('Last charged') }}</th>
|
|
||||||
<th>{{ $__t('Next planned charge cycle') }}</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"
|
title="{{ $__t('Track charge cycle') }}"
|
||||||
data-placement="left"
|
data-battery-id="{{ $currentBatteryEntry->battery_id }}"
|
||||||
title="{{ $__t('Track charge cycle') }}"
|
data-battery-name="{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->name }}">
|
||||||
data-battery-id="{{ $currentBatteryEntry->battery_id }}"
|
<i class="fas fa-car-battery"></i>
|
||||||
data-battery-name="{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->name }}">
|
</a>
|
||||||
<i class="fas fa-car-battery"></i>
|
<div class="dropdown d-inline-block">
|
||||||
</a>
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
<div class="dropdown d-inline-block">
|
data-toggle="dropdown">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="dropdown">
|
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="dropdown-item battery-name-cell"
|
||||||
</button>
|
data-battery-id="{{ $currentBatteryEntry->battery_id }}" type="button"
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
href="#">
|
||||||
<a class="dropdown-item battery-name-cell"
|
<span class="dropdown-item-text">{{ $__t('Battery overview') }}</span>
|
||||||
data-battery-id="{{ $currentBatteryEntry->battery_id }}"
|
</a>
|
||||||
type="button"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
href="#">
|
href="{{ $U('/batteriesjournal?embedded&battery=') }}{{ $currentBatteryEntry->battery_id }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Battery overview') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Battery journal') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item permission-MASTER_DATA_EDIT show-as-dialog-link"
|
||||||
type="button"
|
type="button"
|
||||||
href="{{ $U('/batteriesjournal?embedded&battery=') }}{{ $currentBatteryEntry->battery_id }}">
|
href="{{ $U('/battery/') }}{{ $currentBatteryEntry->battery_id }}?embedded">
|
||||||
<span class="dropdown-item-text">{{ $__t('Battery journal') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Edit battery') }}</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item permission-MASTER_DATA_EDIT show-as-dialog-link"
|
<div class="dropdown-divider"></div>
|
||||||
type="button"
|
<a class="dropdown-item" type="button"
|
||||||
href="{{ $U('/battery/') }}{{ $currentBatteryEntry->battery_id }}?embedded">
|
href="{{ $U('/battery/' . $currentBatteryEntry->battery_id . '/grocycode?download=true') }}">
|
||||||
<span class="dropdown-item-text">{{ $__t('Edit battery') }}</span>
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Battery'))) !!}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
<a class="dropdown-item"
|
<a class="dropdown-item battery-grocycode-label-print"
|
||||||
type="button"
|
data-battery-id="{{ $currentBatteryEntry->battery_id }}" type="button"
|
||||||
href="{{ $U('/battery/' . $currentBatteryEntry->battery_id . '/grocycode?download=true') }}">
|
href="#">
|
||||||
{!! 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('Print %s grocycode on label printer', $__t('Battery'))) !!}
|
||||||
</a>
|
</a>
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
@endif
|
||||||
<a class="dropdown-item battery-grocycode-label-print"
|
</div>
|
||||||
data-battery-id="{{ $currentBatteryEntry->battery_id }}"
|
</div>
|
||||||
type="button"
|
</td>
|
||||||
href="#">
|
<td class="battery-name-cell cursor-link"
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Battery'))) !!}
|
data-battery-id="{{ $currentBatteryEntry->battery_id }}">
|
||||||
</a>
|
{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->name }}
|
||||||
@endif
|
</td>
|
||||||
</div>
|
<td class="fit-content">
|
||||||
</div>
|
{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->used_in }}
|
||||||
</td>
|
</td>
|
||||||
<td class="battery-name-cell cursor-link"
|
<td>
|
||||||
data-battery-id="{{ $currentBatteryEntry->battery_id }}">
|
<span
|
||||||
{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->name }}
|
id="battery-{{ $currentBatteryEntry->battery_id }}-last-tracked-time">{{ $currentBatteryEntry->last_tracked_time }}</span>
|
||||||
</td>
|
<time id="battery-{{ $currentBatteryEntry->battery_id }}-last-tracked-time-timeago"
|
||||||
<td class="fit-content">
|
class="timeago timeago-contextual"
|
||||||
{{ FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->used_in }}
|
datetime="{{ $currentBatteryEntry->last_tracked_time }}"></time>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span id="battery-{{ $currentBatteryEntry->battery_id }}-last-tracked-time">{{ $currentBatteryEntry->last_tracked_time }}</span>
|
@if (FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->charge_interval_days > 0)
|
||||||
<time id="battery-{{ $currentBatteryEntry->battery_id }}-last-tracked-time-timeago"
|
<span
|
||||||
class="timeago timeago-contextual"
|
id="battery-{{ $currentBatteryEntry->battery_id }}-next-charge-time">{{ $currentBatteryEntry->next_estimated_charge_time }}</span>
|
||||||
datetime="{{ $currentBatteryEntry->last_tracked_time }}"></time>
|
<time id="battery-{{ $currentBatteryEntry->battery_id }}-next-charge-time-timeago"
|
||||||
</td>
|
class="timeago timeago-contextual"
|
||||||
<td>
|
datetime="{{ $currentBatteryEntry->next_estimated_charge_time }}"></time>
|
||||||
@if(FindObjectInArrayByPropertyValue($batteries, 'id', $currentBatteryEntry->battery_id)->charge_interval_days > 0)
|
@else
|
||||||
<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"
|
@endif
|
||||||
class="timeago timeago-contextual"
|
</td>
|
||||||
datetime="{{ $currentBatteryEntry->next_estimated_charge_time }}"></time>
|
<td class="d-none">
|
||||||
@else
|
{{ $currentBatteryEntry->due_type }}
|
||||||
...
|
@if ($currentBatteryEntry->due_type == 'duetoday')
|
||||||
@endif
|
duesoon
|
||||||
</td>
|
@endif
|
||||||
<td class="d-none">
|
</td>
|
||||||
{{ $currentBatteryEntry->due_type }}
|
|
||||||
@if($currentBatteryEntry->due_type == 'duetoday')
|
|
||||||
duesoon
|
|
||||||
@endif
|
|
||||||
</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"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-dialog">
|
<div class="modal-body">
|
||||||
<div class="modal-content text-center">
|
@include('components.batterycard')
|
||||||
<div class="modal-body">
|
</div>
|
||||||
@include('components.batterycard')
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
<div class="modal-footer">
|
</div>
|
||||||
<button type="button"
|
</div>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
</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>
|
||||||
|
|
@ -56,4 +49,4 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.barcodescanner')
|
@include('components.barcodescanner')
|
||||||
@stop
|
@stop
|
||||||
|
|
@ -82,12 +82,12 @@
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $chore->period_days; } else { $value = 0; } @endphp
|
@php if($mode == 'edit') { $value = $chore->period_days; } else { $value = 0; } @endphp
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', array(
|
||||||
'id' => 'period_days',
|
'id' => 'period_days',
|
||||||
'label' => 'Period days',
|
'label' => 'Period days',
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'min' => '0',
|
'min' => '0',
|
||||||
'additionalCssClasses' => 'input-group-chore-period-type',
|
'additionalCssClasses' => 'input-group-chore-period-type',
|
||||||
'additionalGroupCssClasses' => 'period-type-input period-type-monthly'
|
'additionalGroupCssClasses' => 'period-type-input period-type-monthly'
|
||||||
))
|
))
|
||||||
|
|
||||||
<div class="form-group period-type-input period-type-weekly">
|
<div class="form-group period-type-input period-type-weekly">
|
||||||
|
|
@ -156,12 +156,12 @@
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $chore->period_interval; } else { $value = 1; } @endphp
|
@php if($mode == 'edit') { $value = $chore->period_interval; } else { $value = 1; } @endphp
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', array(
|
||||||
'id' => 'period_interval',
|
'id' => 'period_interval',
|
||||||
'label' => 'Period interval',
|
'label' => 'Period interval',
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'min' => '1',
|
'min' => '1',
|
||||||
'additionalCssClasses' => 'input-group-chore-period-type',
|
'additionalCssClasses' => 'input-group-chore-period-type',
|
||||||
'additionalGroupCssClasses' => 'period-type-input period-type-hourly period-type-daily period-type-weekly period-type-monthly period-type-yearly'
|
'additionalGroupCssClasses' => 'period-type-input period-type-hourly period-type-daily period-type-weekly period-type-monthly period-type-yearly'
|
||||||
))
|
))
|
||||||
|
|
||||||
<p id="chore-schedule-info"
|
<p id="chore-schedule-info"
|
||||||
|
|
@ -175,15 +175,15 @@
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
@include('components.datetimepicker', array(
|
@include('components.datetimepicker', array(
|
||||||
'id' => 'start',
|
'id' => 'start',
|
||||||
'label' => 'Start date',
|
'label' => 'Start date',
|
||||||
'initialValue' => $value,
|
'initialValue' => $value,
|
||||||
'format' => 'YYYY-MM-DD HH:mm:ss',
|
'format' => 'YYYY-MM-DD HH:mm:ss',
|
||||||
'initWithNow' => true,
|
'initWithNow' => true,
|
||||||
'limitEndToNow' => false,
|
'limitEndToNow' => false,
|
||||||
'limitStartToNow' => false,
|
'limitStartToNow' => false,
|
||||||
'invalidFeedback' => $__t('A start date is required'),
|
'invalidFeedback' => $__t('A start date is required'),
|
||||||
'hint' => $__t('The start date cannot be changed when the chore was once tracked')
|
'hint' => $__t('The start date cannot be changed when the chore was once tracked')
|
||||||
))
|
))
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
|
|
@ -276,29 +276,29 @@
|
||||||
|
|
||||||
@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,
|
||||||
'prefillById' => $prefillById
|
'prefillById' => $prefillById
|
||||||
))
|
))
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $chore->product_amount; } else { $value = ''; } @endphp
|
@php if($mode == 'edit') { $value = $chore->product_amount; } else { $value = ''; } @endphp
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', array(
|
||||||
'id' => 'product_amount',
|
'id' => 'product_amount',
|
||||||
'label' => 'Amount',
|
'label' => 'Amount',
|
||||||
'contextInfoId' => 'amount_qu_unit',
|
'contextInfoId' => 'amount_qu_unit',
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
||||||
))
|
))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@include('components.userfieldsform', array(
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'entity' => 'chores'
|
'entity' => 'chores'
|
||||||
))
|
))
|
||||||
|
|
||||||
<div class="sticky-form-footer pt-1">
|
<div class="sticky-form-footer pt-1">
|
||||||
|
|
|
||||||
|
|
@ -5,203 +5,174 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
href="{{ $U('/chore/new') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary 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('/userfields?entity=chores') }}">
|
||||||
href="{{ $U('/chore/new') }}">
|
{{ $__t('Configure userfields') }}
|
||||||
{{ $__t('Add') }}
|
</a>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=chores') }}">
|
</div>
|
||||||
{{ $__t('Configure userfields') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="form-check custom-control custom-checkbox">
|
||||||
</div>
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-disabled">
|
||||||
</div>
|
<label class="form-check-label custom-control-label" for="show-disabled">
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
{{ $__t('Show disabled') }}
|
||||||
<div class="form-check custom-control custom-checkbox">
|
</label>
|
||||||
<input class="form-check-input custom-control-input"
|
</div>
|
||||||
type="checkbox"
|
</div>
|
||||||
id="show-disabled">
|
<div class="col">
|
||||||
<label class="form-check-label custom-control-label"
|
<div class="float-right">
|
||||||
for="show-disabled">
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
{{ $__t('Show disabled') }}
|
{{ $__t('Clear filter') }}
|
||||||
</label>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
</div>
|
||||||
<div class="float-right">
|
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#chores-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th class="allow-grouping">{{ $__t('Period type') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Description') }}</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
|
||||||
<th class="allow-grouping">{{ $__t('Period type') }}</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"
|
<i class="fas fa-edit"></i>
|
||||||
title="{{ $__t('Edit this item') }}">
|
</a>
|
||||||
<i class="fas fa-edit"></i>
|
<a class="btn btn-danger btn-sm chore-delete-button" href="#"
|
||||||
</a>
|
data-chore-id="{{ $chore->id }}" data-chore-name="{{ $chore->name }}"
|
||||||
<a class="btn btn-danger btn-sm chore-delete-button"
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
href="#"
|
<i class="fas fa-trash"></i>
|
||||||
data-chore-id="{{ $chore->id }}"
|
</a>
|
||||||
data-chore-name="{{ $chore->name }}"
|
<div class="dropdown d-inline-block">
|
||||||
data-toggle="tooltip"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
title="{{ $__t('Delete this item') }}">
|
data-toggle="dropdown">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
</a>
|
</button>
|
||||||
<div class="dropdown d-inline-block">
|
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<a class="dropdown-item merge-chores-button" data-chore-id="{{ $chore->id }}"
|
||||||
type="button"
|
type="button" href="#">
|
||||||
data-toggle="dropdown">
|
<span class="dropdown-item-text">{{ $__t('Merge') }}</span>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
</a>
|
||||||
</button>
|
</div>
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
</div>
|
||||||
<a class="dropdown-item merge-chores-button"
|
</td>
|
||||||
data-chore-id="{{ $chore->id }}"
|
<td>
|
||||||
type="button"
|
{{ $chore->name }}
|
||||||
href="#">
|
</td>
|
||||||
<span class="dropdown-item-text">{{ $__t('Merge') }}</span>
|
<td>
|
||||||
</a>
|
{{ $__t($chore->period_type) }}
|
||||||
</div>
|
</td>
|
||||||
</div>
|
<td>
|
||||||
</td>
|
{{ $chore->description }}
|
||||||
<td>
|
</td>
|
||||||
{{ $chore->name }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ $__t($chore->period_type) }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ $chore->description }}
|
|
||||||
</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"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content text-center">
|
<h4 class="modal-title w-100">{{ $__t('Merge chores') }}</h4>
|
||||||
<div class="modal-header">
|
</div>
|
||||||
<h4 class="modal-title w-100">{{ $__t('Merge chores') }}</h4>
|
<div class="modal-body">
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="modal-body">
|
<label for="merge-chores-keep">{{ $__t('Chore to keep') }} <i
|
||||||
<div class="form-group">
|
class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
<label for="merge-chores-keep">{{ $__t('Chore to keep') }} <i class="fas fa-question-circle text-muted"
|
title="{{ $__t('After merging, this chore will be kept') }}"></i>
|
||||||
data-toggle="tooltip"
|
</label>
|
||||||
data-trigger="hover click"
|
{{-- TODO: Select2: dynamic data: chores --}}
|
||||||
title="{{ $__t('After merging, this chore will be kept') }}"></i>
|
<select class="custom-control custom-select" id="merge-chores-keep">
|
||||||
</label>
|
<option></option>
|
||||||
<select class="custom-control custom-select"
|
@foreach ($chores as $chore)
|
||||||
id="merge-chores-keep">
|
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||||
<option></option>
|
@endforeach
|
||||||
@foreach($chores as $chore)
|
</select>
|
||||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
</div>
|
||||||
@endforeach
|
<div class="form-group">
|
||||||
</select>
|
<label for="merge-chores-remove">{{ $__t('Chore to remove') }} <i
|
||||||
</div>
|
class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
<div class="form-group">
|
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 for="merge-chores-remove">{{ $__t('Chore to remove') }} <i class="fas fa-question-circle text-muted"
|
</label>
|
||||||
data-toggle="tooltip"
|
{{-- TODO: Select2: dynamic data: chores --}}
|
||||||
data-trigger="hover click"
|
<select class="custom-control custom-select" id="merge-chores-remove">
|
||||||
title="{{ $__t('After merging, all occurences of this chore will be replaced by the kept chore (means this chore will not exist anymore)') }}"></i>
|
<option></option>
|
||||||
</label>
|
@foreach ($chores as $chore)
|
||||||
<select class="custom-control custom-select"
|
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||||
id="merge-chores-remove">
|
@endforeach
|
||||||
<option></option>
|
</select>
|
||||||
@foreach($chores as $chore)
|
</div>
|
||||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
</div>
|
||||||
@endforeach
|
<div class="modal-footer">
|
||||||
</select>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
</div>
|
<button id="merge-chores-save-button" type="button" class="btn btn-primary"
|
||||||
</div>
|
data-dismiss="modal">{{ $__t('OK') }}</button>
|
||||||
<div class="modal-footer">
|
</div>
|
||||||
<button type="button"
|
</div>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
</div>
|
||||||
<button id="merge-chores-save-button"
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary"
|
|
||||||
data-dismiss="modal">{{ $__t('OK') }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,149 +5,139 @@
|
||||||
@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-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
</div>
|
||||||
</button>
|
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Chore') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
{{-- TODO: Select2: dynamic data: chores --}}
|
||||||
<div class="input-group-prepend">
|
<select class="custom-control custom-select" id="chore-filter">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Chore') }}</span>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
</div>
|
@foreach ($chores as $chore)
|
||||||
<select class="custom-control custom-select"
|
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
||||||
id="chore-filter">
|
@endforeach
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
</select>
|
||||||
@foreach($chores as $chore)
|
</div>
|
||||||
<option value="{{ $chore->id }}">{{ $chore->name }}</option>
|
</div>
|
||||||
@endforeach
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
</select>
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
<select class="custom-control custom-select" id="daterange-filter">
|
||||||
<div class="input-group-prepend">
|
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
<option value="6">{{ $__n(6, '%s month', '%s months') }}</option>
|
||||||
</div>
|
<option value="12" selected>{{ $__n(1, '%s year', '%s years') }}</option>
|
||||||
<select class="custom-control custom-select"
|
<option value="24">{{ $__n(2, '%s month', '%s years') }}</option>
|
||||||
id="daterange-filter">
|
<option value="9999">{{ $__t('All') }}</option>
|
||||||
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
</select>
|
||||||
<option value="6">{{ $__n(6, '%s month', '%s months') }}</option>
|
</div>
|
||||||
<option value="12"
|
</div>
|
||||||
selected>{{ $__n(1, '%s year', '%s years') }}</option>
|
<div class="col">
|
||||||
<option value="24">{{ $__n(2, '%s month', '%s years') }}</option>
|
<div class="float-right">
|
||||||
<option value="9999">{{ $__t('All') }}</option>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</select>
|
{{ $__t('Clear filter') }}
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
</div>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#chores-journal-table"
|
<th class="allow-grouping">{{ $__t('Chore') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Tracked time') }}</th>
|
||||||
</th>
|
@if (GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
<th class="allow-grouping">{{ $__t('Chore') }}</th>
|
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
||||||
<th>{{ $__t('Tracked time') }}</th>
|
@endif
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
|
||||||
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
|
||||||
@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"
|
<i class="fas fa-undo"></i>
|
||||||
data-placement="left"
|
</a>
|
||||||
title="{{ $__t('Undo chore execution') }}">
|
</td>
|
||||||
<i class="fas fa-undo"></i>
|
<td>
|
||||||
</a>
|
<span
|
||||||
</td>
|
class="name-anchor @if ($choreLogEntry->undone == 1) text-strike-through @endif">{{ FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->name }}</span>
|
||||||
<td>
|
@if ($choreLogEntry->undone == 1)
|
||||||
<span class="name-anchor @if($choreLogEntry->undone == 1) text-strike-through @endif">{{ FindObjectInArrayByPropertyValue($chores, 'id', $choreLogEntry->chore_id)->name }}</span>
|
<br>
|
||||||
@if($choreLogEntry->undone == 1)
|
{{ $__t('Undone on') . ' ' . $choreLogEntry->undone_timestamp }}
|
||||||
<br>
|
<time class="timeago timeago-contextual"
|
||||||
{{ $__t('Undone on') . ' ' . $choreLogEntry->undone_timestamp }}
|
datetime="{{ $choreLogEntry->undone_timestamp }}"></time>
|
||||||
<time class="timeago timeago-contextual"
|
@endif
|
||||||
datetime="{{ $choreLogEntry->undone_timestamp }}"></time>
|
</td>
|
||||||
@endif
|
<td>
|
||||||
</td>
|
<span>{{ $choreLogEntry->tracked_time }}</span>
|
||||||
<td>
|
<time
|
||||||
<span>{{ $choreLogEntry->tracked_time }}</span>
|
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)) }}
|
@else
|
||||||
@else
|
{{ $__t('Unknown') }}
|
||||||
{{ $__t('Unknown') }}
|
@endif
|
||||||
@endif
|
</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,
|
||||||
</tr>
|
'object_id',
|
||||||
@endforeach
|
$choreLogEntry->id
|
||||||
</tbody>
|
),
|
||||||
</table>
|
])
|
||||||
</div>
|
</tr>
|
||||||
</div>
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,268 +5,238 @@
|
||||||
@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"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-target="#related-links">
|
</button>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
</button>
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
href="{{ $U('/choresjournal') }}">
|
||||||
id="related-links">
|
{{ $__t('Journal') }}
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
</a>
|
||||||
href="{{ $U('/choresjournal') }}">
|
</div>
|
||||||
{{ $__t('Journal') }}
|
</div>
|
||||||
</a>
|
<div class="border-top border-bottom my-2 py-1">
|
||||||
</div>
|
<div id="info-overdue-chores" data-status-filter="overdue"
|
||||||
</div>
|
class="error-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div class="border-top border-bottom my-2 py-1">
|
<div id="info-due-today-chores" data-status-filter="duetoday"
|
||||||
<div id="info-overdue-chores"
|
class="normal-message status-filter-message responsive-button mr-2"></div>
|
||||||
data-status-filter="overdue"
|
<div id="info-due-soon-chores" data-status-filter="duesoon" data-next-x-days="{{ $nextXDays }}"
|
||||||
class="error-message status-filter-message responsive-button mr-2"></div>
|
class="warning-message status-filter-message responsive-message mr-2 @if ($nextXDays == 0) d-none @endif">
|
||||||
<div id="info-due-today-chores"
|
</div>
|
||||||
data-status-filter="duetoday"
|
@if (GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
class="normal-message status-filter-message responsive-button mr-2"></div>
|
<div id="info-assigned-to-me-chores" data-user-filter="xx{{ GROCY_USER_ID }}xx"
|
||||||
<div id="info-due-soon-chores"
|
class="secondary-message user-filter-message responsive-button"></div>
|
||||||
data-status-filter="duesoon"
|
@endif
|
||||||
data-next-x-days="{{ $nextXDays }}"
|
<div class="float-right">
|
||||||
class="warning-message status-filter-message responsive-message mr-2 @if($nextXDays == 0) d-none @endif"></div>
|
<a class="btn btn-sm btn-outline-info d-md-none mt-1" data-toggle="collapse" href="#table-filter-row"
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
role="button">
|
||||||
<div id="info-assigned-to-me-chores"
|
<i class="fas fa-filter"></i>
|
||||||
data-user-filter="xx{{ GROCY_USER_ID }}xx"
|
</a>
|
||||||
class="secondary-message user-filter-message responsive-button"></div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info mt-1" href="#">
|
||||||
@endif
|
{{ $__t('Clear filter') }}
|
||||||
<div class="float-right">
|
</a>
|
||||||
<a class="btn btn-sm btn-outline-info d-md-none mt-1"
|
</div>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
href="#table-filter-row"
|
</div>
|
||||||
role="button">
|
</div>
|
||||||
<i class="fas fa-filter"></i>
|
|
||||||
</a>
|
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info mt-1"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
<div class="input-group-prepend">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<option value="overdue">{{ $__t('Overdue') }}</option>
|
||||||
</div>
|
<option value="duetoday">{{ $__t('Due today') }}</option>
|
||||||
<select class="custom-control custom-select"
|
@if ($nextXDays > 0)
|
||||||
id="status-filter">
|
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
@endif
|
||||||
<option value="overdue">{{ $__t('Overdue') }}</option>
|
</select>
|
||||||
<option value="duetoday">{{ $__t('Due today') }}</option>
|
</div>
|
||||||
@if($nextXDays > 0)
|
</div>
|
||||||
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
@if (GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
||||||
@endif
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
</select>
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i
|
||||||
@if(GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS)
|
class="fas fa-filter"></i> {{ $__t('Assignment') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
{{-- TODO: Select2: dynamic data: users --}}
|
||||||
<div class="input-group-prepend">
|
<select class="custom-control custom-select" id="user-filter">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Assignment') }}</span>
|
<option></option>
|
||||||
</div>
|
@foreach ($users as $user)
|
||||||
<select class="custom-control custom-select"
|
<option data-user-id="{{ $user->id }}" value="xx{{ $user->id }}xx">
|
||||||
id="user-filter">
|
{{ $user->display_name }}</option>
|
||||||
<option></option>
|
@endforeach
|
||||||
@foreach($users as $user)
|
</select>
|
||||||
<option data-user-id="{{ $user->id }}"
|
</div>
|
||||||
value="xx{{ $user->id }}xx">{{ $user->display_name }}</option>
|
</div>
|
||||||
@endforeach
|
@endif
|
||||||
</select>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#chores-overview-table"
|
<th>{{ $__t('Chore') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Next estimated tracking') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Last tracked') }}</th>
|
||||||
<th>{{ $__t('Chore') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS) d-none @endif allow-grouping">
|
||||||
<th>{{ $__t('Next estimated tracking') }}</th>
|
{{ $__t('Assigned to') }}</th>
|
||||||
<th>{{ $__t('Last tracked') }}</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_CHORES_ASSIGNMENTS) d-none @endif allow-grouping">{{ $__t('Assigned to') }}</th>
|
<th class="d-none">Hidden assigned to user id</th>
|
||||||
<th class="d-none">Hidden status</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"
|
title="{{ $__t('Track chore execution') }}"
|
||||||
data-placement="left"
|
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
||||||
title="{{ $__t('Track chore execution') }}"
|
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
<i class="fas fa-play"></i>
|
||||||
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
</a>
|
||||||
<i class="fas fa-play"></i>
|
<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>
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
<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"
|
title="{{ $__t('Skip next chore schedule') }}"
|
||||||
href="#"
|
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
||||||
data-toggle="tooltip"
|
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
||||||
data-placement="left"
|
<i class="fas fa-forward"></i>
|
||||||
title="{{ $__t('Skip next chore schedule') }}"
|
</a>
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
<div class="dropdown d-inline-block">
|
||||||
data-chore-name="{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}">
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
<i class="fas fa-forward"></i>
|
data-toggle="dropdown">
|
||||||
</a>
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
<div class="dropdown d-inline-block">
|
</button>
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
||||||
type="button"
|
<a class="dropdown-item chore-name-cell"
|
||||||
data-toggle="dropdown">
|
data-chore-id="{{ $curentChoreEntry->chore_id }}" type="button" href="#">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<span class="dropdown-item-text">{{ $__t('Chore overview') }}</span>
|
||||||
</button>
|
</a>
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right">
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
<a class="dropdown-item chore-name-cell"
|
href="{{ $U('/choresjournal?embedded&chore=') }}{{ $curentChoreEntry->chore_id }}">
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
<span class="dropdown-item-text">{{ $__t('Chore journal') }}</span>
|
||||||
type="button"
|
</a>
|
||||||
href="#">
|
<a class="dropdown-item permission-MASTER_DATA_EDIT" type="button"
|
||||||
<span class="dropdown-item-text">{{ $__t('Chore overview') }}</span>
|
href="{{ $U('/chore/') }}{{ $curentChoreEntry->chore_id }}">
|
||||||
</a>
|
<span class="dropdown-item-text">{{ $__t('Edit chore') }}</span>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
</a>
|
||||||
type="button"
|
<div class="dropdown-divider"></div>
|
||||||
href="{{ $U('/choresjournal?embedded&chore=') }}{{ $curentChoreEntry->chore_id }}">
|
<a class="dropdown-item" type="button"
|
||||||
<span class="dropdown-item-text">{{ $__t('Chore journal') }}</span>
|
href="{{ $U('/chore/' . $curentChoreEntry->chore_id . '/grocycode?download=true') }}">
|
||||||
</a>
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Chore'))) !!}
|
||||||
<a class="dropdown-item permission-MASTER_DATA_EDIT"
|
</a>
|
||||||
type="button"
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
href="{{ $U('/chore/') }}{{ $curentChoreEntry->chore_id }}">
|
<a class="dropdown-item chore-grocycode-label-print"
|
||||||
<span class="dropdown-item-text">{{ $__t('Edit chore') }}</span>
|
data-chore-id="{{ $curentChoreEntry->chore_id }}" type="button" href="#">
|
||||||
</a>
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Chore'))) !!}
|
||||||
<div class="dropdown-divider"></div>
|
</a>
|
||||||
<a class="dropdown-item"
|
@endif
|
||||||
type="button"
|
</div>
|
||||||
href="{{ $U('/chore/' . $curentChoreEntry->chore_id . '/grocycode?download=true') }}">
|
</div>
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Chore'))) !!}
|
</td>
|
||||||
</a>
|
<td class="chore-name-cell cursor-link" data-chore-id="{{ $curentChoreEntry->chore_id }}">
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}
|
||||||
<a class="dropdown-item chore-grocycode-label-print"
|
</td>
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}"
|
<td>
|
||||||
type="button"
|
@if (FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY)
|
||||||
href="#">
|
<span
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Chore'))) !!}
|
id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time">{{ $curentChoreEntry->next_estimated_execution_time }}</span>
|
||||||
</a>
|
<time id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time-timeago"
|
||||||
@endif
|
class="timeago timeago-contextual @if ($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
||||||
</div>
|
datetime="{{ $curentChoreEntry->next_estimated_execution_time }}"></time>
|
||||||
</div>
|
@else
|
||||||
</td>
|
<span>-</span>
|
||||||
<td class="chore-name-cell cursor-link"
|
@endif
|
||||||
data-chore-id="{{ $curentChoreEntry->chore_id }}">
|
</td>
|
||||||
{{ FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->name }}
|
<td>
|
||||||
</td>
|
<span
|
||||||
<td>
|
id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time">{{ $curentChoreEntry->last_tracked_time }}</span>
|
||||||
@if(FindObjectInArrayByPropertyValue($chores, 'id', $curentChoreEntry->chore_id)->period_type !== \Grocy\Services\ChoresService::CHORE_PERIOD_TYPE_MANUALLY)
|
<time id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time-timeago"
|
||||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time">{{ $curentChoreEntry->next_estimated_execution_time }}</span>
|
class="timeago timeago-contextual @if ($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
||||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-next-execution-time-timeago"
|
datetime="{{ $curentChoreEntry->last_tracked_time }}"></time>
|
||||||
class="timeago timeago-contextual @if($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
</td>
|
||||||
datetime="{{ $curentChoreEntry->next_estimated_execution_time }}"></time>
|
|
||||||
@else
|
|
||||||
<span>-</span>
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time">{{ $curentChoreEntry->last_tracked_time }}</span>
|
|
||||||
<time id="chore-{{ $curentChoreEntry->chore_id }}-last-tracked-time-timeago"
|
|
||||||
class="timeago timeago-contextual @if($curentChoreEntry->track_date_only == 1) timeago-date-only @endif"
|
|
||||||
datetime="{{ $curentChoreEntry->last_tracked_time }}"></time>
|
|
||||||
</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"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-dialog">
|
<div class="modal-body">
|
||||||
<div class="modal-content text-center">
|
@include('components.chorecard')
|
||||||
<div class="modal-body">
|
</div>
|
||||||
@include('components.chorecard')
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
<div class="modal-footer">
|
</div>
|
||||||
<button type="button"
|
</div>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
</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(
|
||||||
|
|
@ -76,4 +67,4 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.barcodescanner')
|
@include('components.barcodescanner')
|
||||||
@stop
|
@stop
|
||||||
|
|
@ -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,37 +1,50 @@
|
||||||
@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 }}"
|
<label for="location_id">{{ $__t('Location') }}
|
||||||
data-prefill-by-id="{{ $prefillById }}">
|
@if (!empty($hint))
|
||||||
<label for="location_id">{{ $__t('Location') }}
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
@if(!empty($hint))
|
title="{{ $hint }}"></i>
|
||||||
<i class="fas fa-question-circle text-muted"
|
@endif
|
||||||
data-toggle="tooltip"
|
</label>
|
||||||
data-trigger="hover click"
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
title="{{ $hint }}"></i>
|
<select class="form-control location-combobox" id="location_id" name="location_id"
|
||||||
@endif
|
@if ($isRequired) required @endif>
|
||||||
</label>
|
<option value=""></option>
|
||||||
<select class="form-control location-combobox"
|
@foreach ($locations as $location)
|
||||||
id="location_id"
|
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
||||||
name="location_id"
|
@endforeach
|
||||||
@if($isRequired)
|
</select>
|
||||||
required
|
<div class="invalid-feedback">{{ $__t('You have to select a location') }}</div>
|
||||||
@endif>
|
|
||||||
<option value=""></option>
|
|
||||||
@foreach($locations as $location)
|
|
||||||
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback">{{ $__t('You have to select a location') }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -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-id="{{ $prefillById }}"
|
||||||
data-prefill-by-name="{{ $prefillByName }}"
|
data-products-query="{{ $productsQuery }}">
|
||||||
data-prefill-by-id="{{ $prefillById }}">
|
<label class="w-100" for="product_id">
|
||||||
<label class="w-100"
|
{{ $__t($label) }}
|
||||||
for="product_id">
|
@if (!$disallowAllProductWorkflows)
|
||||||
{{ $__t($label) }}
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
@if(!$disallowAllProductWorkflows)
|
title="{{ $__t('Type a new product name or barcode and hit TAB or ENTER to start a workflow') }}"></i>
|
||||||
<i class="fas fa-question-circle text-muted"
|
@endif
|
||||||
data-toggle="tooltip"
|
@if (!empty($hint))
|
||||||
data-trigger="hover click"
|
<i class="fas fa-question-circle text-muted" 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="{{ $hint }}"></i>
|
||||||
@endif
|
@endif
|
||||||
@if(!empty($hint))
|
<span id="barcode-lookup-disabled-hint" class="small text-muted d-none float-right">
|
||||||
<i class="fas fa-question-circle text-muted"
|
{{ $__t('Barcode lookup is disabled') }}</span>
|
||||||
data-toggle="tooltip"
|
<i id="barcode-lookup-hint" class="fas fa-barcode float-right mt-1"></i>
|
||||||
data-trigger="hover click"
|
</label>
|
||||||
title="{{ $hint }}"></i>
|
<div class="input-group">
|
||||||
@endif
|
<select class="select2 custom-control custom-select barcodescanner-input" id="product_id" name="product_id"
|
||||||
<span id="barcode-lookup-disabled-hint"
|
@if ($isRequired) required @endif @if ($disabled) disabled @endif
|
||||||
class="small text-muted d-none float-right"> {{ $__t('Barcode lookup is disabled') }}</span>
|
data-target="@productpicker"></select>
|
||||||
<i id="barcode-lookup-hint"
|
<div class="invalid-feedback">{{ $__t($validationMessage) }}</div>
|
||||||
class="fas fa-barcode float-right mt-1"></i>
|
</div>
|
||||||
</label>
|
<div id="custom-productpicker-error" class="form-text text-danger d-none"></div>
|
||||||
<select class="form-control product-combobox barcodescanner-input"
|
<div id="flow-info-InplaceAddBarcodeToExistingProduct" class="form-text text-info small d-none"><strong><span
|
||||||
id="product_id"
|
id="InplaceAddBarcodeToExistingProduct"></span></strong>
|
||||||
name="product_id"
|
{{ $__t('will be added to the list of barcodes for the selected product on submit') }}</div>
|
||||||
@if($isRequired)
|
|
||||||
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 id="custom-productpicker-error"
|
|
||||||
class="form-text text-danger d-none"></div>
|
|
||||||
<div id="flow-info-InplaceAddBarcodeToExistingProduct"
|
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.barcodescanner')
|
@include('components.barcodescanner')
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,53 @@
|
||||||
@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') }}
|
title="{{ $hint }}"></i>
|
||||||
@if(!empty($hint))
|
@endif
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-barcode float-right mt-1"></i>
|
||||||
data-toggle="tooltip"
|
</label>
|
||||||
data-trigger="hover click"
|
{{-- TODO: Select2: dynamic data: recipes --}}
|
||||||
title="{{ $hint }}"></i>
|
<select class="form-control recipe-combobox barcodescanner-input" id="recipe_id" name="recipe_id"
|
||||||
@endif
|
data-target="@recipepicker" @if ($isRequired) required @endif>
|
||||||
<i class="fas fa-barcode float-right mt-1"></i>
|
<option value=""></option>
|
||||||
</label>
|
@foreach ($recipes as $recipe)
|
||||||
<select class="form-control recipe-combobox barcodescanner-input"
|
<option value="{{ $recipe->id }}">{{ $recipe->name }}</option>
|
||||||
id="recipe_id"
|
@endforeach
|
||||||
name="recipe_id"
|
</select>
|
||||||
data-target="@recipepicker"
|
<div class="invalid-feedback">{{ $__t('You have to select a recipe') }}</div>
|
||||||
@if($isRequired)
|
|
||||||
required
|
|
||||||
@endif>
|
|
||||||
<option value=""></option>
|
|
||||||
@foreach($recipes as $recipe)
|
|
||||||
<option value="{{ $recipe->id }}">{{ $recipe->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback">{{ $__t('You have to select a recipe') }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include('components.barcodescanner')
|
@include('components.barcodescanner')
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,47 @@
|
||||||
@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 }}"
|
class="small text-muted">{{ $hint }}</span></label>
|
||||||
@endif
|
{{-- TODO: Select2: dynamic data: shopping_locations --}}
|
||||||
class="small text-muted">{{ $hint }}</span></label>
|
<select class="form-control shopping-location-combobox" id="shopping_location_id" name="shopping_location_id"
|
||||||
<select class="form-control shopping-location-combobox"
|
@if ($isRequired) required @endif>
|
||||||
id="shopping_location_id"
|
<option value=""></option>
|
||||||
name="shopping_location_id"
|
@foreach ($shoppinglocations as $shoppinglocation)
|
||||||
@if($isRequired)
|
<option value="{{ $shoppinglocation->id }}">{{ $shoppinglocation->name }}</option>
|
||||||
required
|
@endforeach
|
||||||
@endif>
|
</select>
|
||||||
<option value=""></option>
|
<div class="invalid-feedback">{{ $__t('You have to select a store') }}</div>
|
||||||
@foreach($shoppinglocations as $shoppinglocation)
|
|
||||||
<option value="{{ $shoppinglocation->id }}">{{ $shoppinglocation->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback">{{ $__t('You have to select a store') }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -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 }}"
|
<label for="user_id">{{ $__t($label) }}</label>
|
||||||
data-prefill-by-user-id="{{ $prefillByUserId }}">
|
{{-- TODO: Select2: dynamic data: users --}}
|
||||||
<label for="user_id">{{ $__t($label) }}</label>
|
<select class="form-control user-combobox" id="user_id" name="user_id">
|
||||||
<select class="form-control user-combobox"
|
<option value=""></option>
|
||||||
id="user_id"
|
@foreach ($users as $user)
|
||||||
name="user_id">
|
<option data-additional-searchdata="{{ $user->username }}" value="{{ $user->id }}">
|
||||||
<option value=""></option>
|
{{ GetUserDisplayName($user) }}</option>
|
||||||
@foreach($users as $user)
|
@endforeach
|
||||||
<option data-additional-searchdata="{{ $user->username }}"
|
</select>
|
||||||
value="{{ $user->id }}">{{ GetUserDisplayName($user) }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,151 +5,136 @@
|
||||||
@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"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-target="#related-links">
|
</button>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
</button>
|
@if (!$embedded)
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<button id="scan-mode-button"
|
||||||
id="related-links">
|
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"
|
||||||
@if(!$embedded)
|
data-toggle="tooltip"
|
||||||
<button id="scan-mode-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') }}
|
||||||
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"
|
<span id="scan-mode-status">
|
||||||
data-toggle="tooltip"
|
@if (boolval($userSettings['scan_mode_consume_enabled']))
|
||||||
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>
|
{{ $__t('on') }}
|
||||||
<input id="scan-mode"
|
@else
|
||||||
type="checkbox"
|
{{ $__t('off') }}
|
||||||
class="d-none user-setting-control"
|
@endif
|
||||||
data-setting-key="scan_mode_consume_enabled"
|
</span></button>
|
||||||
@if(boolval($userSettings['scan_mode_consume_enabled']))
|
<input id="scan-mode" type="checkbox" class="d-none user-setting-control"
|
||||||
checked
|
data-setting-key="scan_mode_consume_enabled" @if (boolval($userSettings['scan_mode_consume_enabled'])) checked @endif>
|
||||||
@endif>
|
@else
|
||||||
@else
|
<script>
|
||||||
<script>
|
Grocy.UserSettings.scan_mode_consume_enabled = false;
|
||||||
Grocy.UserSettings.scan_mode_consume_enabled = false;
|
</script>
|
||||||
</script>
|
@endif
|
||||||
@endif
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<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" type="checkbox" id="consume-exact-amount"
|
||||||
<input class="form-check-input custom-control-input"
|
name="consume-exact-amount" value="1">
|
||||||
type="checkbox"
|
<label class="form-check-label custom-control-label"
|
||||||
id="consume-exact-amount"
|
for="consume-exact-amount">{{ $__t('Consume exact amount') }}
|
||||||
name="consume-exact-amount"
|
</label>
|
||||||
value="1">
|
</div>
|
||||||
<label class="form-check-label custom-control-label"
|
</div>
|
||||||
for="consume-exact-amount">{{ $__t('Consume exact amount') }}
|
|
||||||
</label>
|
|
||||||
</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>
|
<div class="invalid-feedback">{{ $__t('A location is required') }}</div>
|
||||||
<div class="invalid-feedback">{{ $__t('A location is required') }}</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="spoiled" name="spoiled"
|
||||||
type="checkbox"
|
value="1">
|
||||||
id="spoiled"
|
<label class="form-check-label custom-control-label" for="spoiled">{{ $__t('Spoiled') }}
|
||||||
name="spoiled"
|
</label>
|
||||||
value="1">
|
</div>
|
||||||
<label class="form-check-label custom-control-label"
|
</div>
|
||||||
for="spoiled">{{ $__t('Spoiled') }}
|
|
||||||
</label>
|
|
||||||
</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"
|
<label class="form-check-label custom-control-label"
|
||||||
name="use_specific_stock_entry"
|
for="use_specific_stock_entry">{{ $__t('Use a specific stock item') }}
|
||||||
value="1">
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip"
|
||||||
<label class="form-check-label custom-control-label"
|
data-trigger="hover click"
|
||||||
for="use_specific_stock_entry">{{ $__t('Use a specific stock item') }}
|
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>
|
||||||
<i class="fas fa-question-circle text-muted"
|
</label>
|
||||||
data-toggle="tooltip"
|
</div>
|
||||||
data-trigger="hover click"
|
<select disabled class="custom-control custom-select mt-2" id="specific_stock_entry"
|
||||||
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>
|
name="specific_stock_entry">
|
||||||
</label>
|
<option></option>
|
||||||
</div>
|
</select>
|
||||||
<select disabled
|
</div>
|
||||||
class="custom-control custom-select mt-2"
|
|
||||||
id="specific_stock_entry"
|
|
||||||
name="specific_stock_entry">
|
|
||||||
<option></option>
|
|
||||||
</select>
|
|
||||||
</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
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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,185 +5,156 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
href="{{ $U('/equipment/new') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
</div>
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/equipment/new') }}">
|
|
||||||
{{ $__t('Add') }}
|
|
||||||
</a>
|
|
||||||
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#equipment-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
|
||||||
</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" type="button"
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
data-toggle="dropdown">
|
||||||
type="button"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-toggle="dropdown">
|
</button>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<div
|
||||||
</button>
|
class="table-inline-menu dropdown-menu dropdown-menu-right hide-on-fullscreen-card hide-when-embedded">
|
||||||
<div class="table-inline-menu dropdown-menu dropdown-menu-right hide-on-fullscreen-card hide-when-embedded">
|
<a class="dropdown-item equipment-delete-button" type="button" href="#"
|
||||||
<a class="dropdown-item equipment-delete-button"
|
data-equipment-id="{{ $equipmentItem->id }}"
|
||||||
type="button"
|
data-equipment-name="{{ $equipmentItem->name }}">
|
||||||
href="#"
|
<span class="dropdown-item-text">{{ $__t('Delete this item') }}</span>
|
||||||
data-equipment-id="{{ $equipmentItem->id }}"
|
</a>
|
||||||
data-equipment-name="{{ $equipmentItem->name }}">
|
</div>
|
||||||
<span class="dropdown-item-text">{{ $__t('Delete this item') }}</span>
|
</div>
|
||||||
</a>
|
</td>
|
||||||
</div>
|
<td>
|
||||||
</div>
|
{{ $equipmentItem->name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
{{ $equipmentItem->name }}
|
|
||||||
</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
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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" data-toggle="tab" href="#description-tab">{{ $__t('Notes') }}</a>
|
||||||
<a class="nav-link"
|
</li>
|
||||||
data-toggle="tab"
|
</ul>
|
||||||
href="#description-tab">{{ $__t('Notes') }}</a>
|
<div class="tab-content grocy-tabs">
|
||||||
</li>
|
<div class="tab-pane fade show active" id="instruction-manual-tab">
|
||||||
</ul>
|
<div id="selectedEquipmentInstructionManualCard" class="card">
|
||||||
<div class="tab-content grocy-tabs">
|
<div class="card-header card-header-fullscreen">
|
||||||
<div class="tab-pane fade show active"
|
<span class="selected-equipment-name"></span>
|
||||||
id="instruction-manual-tab">
|
<a id="selectedEquipmentInstructionManualToggleFullscreenButton"
|
||||||
<div id="selectedEquipmentInstructionManualCard"
|
class="btn btn-sm btn-outline-secondary py-0 float-right mr-1" href="#"
|
||||||
class="card">
|
data-toggle="tooltip" title="{{ $__t('Expand to fullscreen') }}">
|
||||||
<div class="card-header card-header-fullscreen">
|
<i class="fas fa-expand-arrows-alt"></i>
|
||||||
<span class="selected-equipment-name"></span>
|
</a>
|
||||||
<a id="selectedEquipmentInstructionManualToggleFullscreenButton"
|
<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') }}">
|
||||||
data-toggle="tooltip"
|
<i class="fas fa-file-download"></i>
|
||||||
title="{{ $__t('Expand to fullscreen') }}">
|
</a>
|
||||||
<i class="fas fa-expand-arrows-alt"></i>
|
</div>
|
||||||
</a>
|
<div class="card-body py-0 px-0">
|
||||||
<a id="selectedEquipmentInstructionManualDownloadButton"
|
<p id="selected-equipment-has-no-instruction-manual-hint"
|
||||||
class="btn btn-sm btn-outline-secondary py-0 float-right mr-1"
|
class="text-muted font-italic d-none pt-3 pl-3">
|
||||||
href="#"
|
{{ $__t('The selected equipment has no instruction manual') }}</p>
|
||||||
target="_blank"
|
<embed id="selected-equipment-instruction-manual" class="embed-responsive embed-responsive-4by3"
|
||||||
data-toggle="tooltip"
|
src="" type="application/pdf">
|
||||||
title="{{ $__t('Download file') }}">
|
</div>
|
||||||
<i class="fas fa-file-download"></i>
|
</div>
|
||||||
</a>
|
</div>
|
||||||
</div>
|
<div class="tab-pane fade" id="description-tab">
|
||||||
<div class="card-body py-0 px-0">
|
<div id="selectedEquipmentDescriptionCard" class="card">
|
||||||
<p id="selected-equipment-has-no-instruction-manual-hint"
|
<div class="card-header card-header-fullscreen">
|
||||||
class="text-muted font-italic d-none pt-3 pl-3">{{ $__t('The selected equipment has no instruction manual') }}</p>
|
<span class="selected-equipment-name"></span>
|
||||||
<embed id="selected-equipment-instruction-manual"
|
<a id="selectedEquipmentDescriptionToggleFullscreenButton"
|
||||||
class="embed-responsive embed-responsive-4by3"
|
class="btn btn-sm btn-outline-secondary py-0 float-right" href="#" data-toggle="tooltip"
|
||||||
src=""
|
title="{{ $__t('Expand to fullscreen') }}">
|
||||||
type="application/pdf">
|
<i class="fas fa-expand-arrows-alt"></i>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="card-body">
|
||||||
<div class="tab-pane fade"
|
<div id="description-tab-content" class="mb-0"></div>
|
||||||
id="description-tab">
|
</div>
|
||||||
<div id="selectedEquipmentDescriptionCard"
|
</div>
|
||||||
class="card">
|
</div>
|
||||||
<div class="card-header card-header-fullscreen">
|
</div>
|
||||||
<span class="selected-equipment-name"></span>
|
</div>
|
||||||
<a id="selectedEquipmentDescriptionToggleFullscreenButton"
|
</div>
|
||||||
class="btn btn-sm btn-outline-secondary py-0 float-right"
|
|
||||||
href="#"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="{{ $__t('Expand to fullscreen') }}">
|
|
||||||
<i class="fas fa-expand-arrows-alt"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div id="description-tab-content"
|
|
||||||
class="mb-0"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -21,33 +21,32 @@
|
||||||
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'
|
|
||||||
))
|
))
|
||||||
|
|
||||||
@include('components.productamountpicker', array(
|
@include('components.productamountpicker', array(
|
||||||
'value' => 1,
|
'value' => 1,
|
||||||
'label' => 'New stock amount',
|
'label' => 'New stock amount',
|
||||||
'additionalHtmlElements' => '<div id="inventory-change-info"
|
'additionalHtmlElements' => '<div id="inventory-change-info"
|
||||||
class="form-text text-muted d-none ml-3 my-0 w-100"></div>',
|
class="form-text text-muted d-none ml-3 my-0 w-100"></div>',
|
||||||
'additionalHtmlContextHelp' => '<div id="tare-weight-handling-info"
|
'additionalHtmlContextHelp' => '<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>'
|
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>'
|
||||||
))
|
))
|
||||||
|
|
||||||
@if(boolval($userSettings['show_purchased_date_on_purchase']))
|
@if(boolval($userSettings['show_purchased_date_on_purchase']))
|
||||||
@include('components.datetimepicker2', array(
|
@include('components.datetimepicker2', array(
|
||||||
'id' => 'purchased_date',
|
'id' => 'purchased_date',
|
||||||
'label' => 'Purchased date',
|
'label' => 'Purchased date',
|
||||||
'format' => 'YYYY-MM-DD',
|
'format' => 'YYYY-MM-DD',
|
||||||
'hint' => $__t('This will apply to added products'),
|
'hint' => $__t('This will apply to added products'),
|
||||||
'initWithNow' => true,
|
'initWithNow' => true,
|
||||||
'limitEndToNow' => false,
|
'limitEndToNow' => false,
|
||||||
'limitStartToNow' => false,
|
'limitStartToNow' => false,
|
||||||
'invalidFeedback' => $__t('A purchased date is required'),
|
'invalidFeedback' => $__t('A purchased date is required'),
|
||||||
'nextInputSelector' => '#best_before_date',
|
'nextInputSelector' => '#best_before_date',
|
||||||
'additionalCssClasses' => 'date-only-datetimepicker2',
|
'additionalCssClasses' => 'date-only-datetimepicker2',
|
||||||
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
||||||
))
|
))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
@ -59,44 +58,44 @@
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
@include('components.datetimepicker', array(
|
@include('components.datetimepicker', array(
|
||||||
'id' => 'best_before_date',
|
'id' => 'best_before_date',
|
||||||
'label' => 'Due date',
|
'label' => 'Due date',
|
||||||
'hint' => $__t('This will apply to added products'),
|
'hint' => $__t('This will apply to added products'),
|
||||||
'format' => 'YYYY-MM-DD',
|
'format' => 'YYYY-MM-DD',
|
||||||
'initWithNow' => false,
|
'initWithNow' => false,
|
||||||
'limitEndToNow' => false,
|
'limitEndToNow' => false,
|
||||||
'limitStartToNow' => false,
|
'limitStartToNow' => false,
|
||||||
'invalidFeedback' => $__t('A due date is required'),
|
'invalidFeedback' => $__t('A due date is required'),
|
||||||
'nextInputSelector' => '#best_before_date',
|
'nextInputSelector' => '#best_before_date',
|
||||||
'additionalGroupCssClasses' => 'date-only-datetimepicker',
|
'additionalGroupCssClasses' => 'date-only-datetimepicker',
|
||||||
'shortcutValue' => '2999-12-31',
|
'shortcutValue' => '2999-12-31',
|
||||||
'shortcutLabel' => 'Never overdue',
|
'shortcutLabel' => 'Never overdue',
|
||||||
'earlierThanInfoLimit' => date('Y-m-d'),
|
'earlierThanInfoLimit' => date('Y-m-d'),
|
||||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
||||||
'additionalGroupCssClasses' => $additionalGroupCssClasses,
|
'additionalGroupCssClasses' => $additionalGroupCssClasses,
|
||||||
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
||||||
))
|
))
|
||||||
@php $additionalGroupCssClasses = ''; @endphp
|
@php $additionalGroupCssClasses = ''; @endphp
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', array(
|
||||||
'id' => 'price',
|
'id' => 'price',
|
||||||
'label' => 'Price',
|
'label' => 'Price',
|
||||||
'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_prices']),
|
'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_prices']),
|
||||||
'decimals' => $userSettings['stock_decimal_places_prices'],
|
'decimals' => $userSettings['stock_decimal_places_prices'],
|
||||||
'value' => '',
|
'value' => '',
|
||||||
'hint' => $__t('Per stock quantity unit', GROCY_CURRENCY),
|
'hint' => $__t('Per stock quantity unit', GROCY_CURRENCY),
|
||||||
'additionalHtmlContextHelp' => '<i class="fas fa-question-circle text-muted"
|
'additionalHtmlContextHelp' => '<i class="fas fa-question-circle text-muted"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
data-trigger="hover click"
|
data-trigger="hover click"
|
||||||
title="' . $__t('This will apply to added products') . '"></i>',
|
title="' . $__t('This will apply to added products') . '"></i>',
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-currency'
|
'additionalCssClasses' => 'locale-number-input locale-number-currency'
|
||||||
))
|
))
|
||||||
|
|
||||||
@include('components.shoppinglocationpicker', array(
|
@include('components.shoppinglocationpicker', array(
|
||||||
'label' => 'Store',
|
'label' => 'Store',
|
||||||
'shoppinglocations' => $shoppinglocations
|
'shoppinglocations' => $shoppinglocations
|
||||||
))
|
))
|
||||||
@else
|
@else
|
||||||
<input type="hidden"
|
<input type="hidden"
|
||||||
|
|
@ -107,8 +106,8 @@
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
@include('components.locationpicker', array(
|
@include('components.locationpicker', array(
|
||||||
'locations' => $locations,
|
'locations' => $locations,
|
||||||
'hint' => $__t('This will apply to added products')
|
'hint' => $__t('This will apply to added products')
|
||||||
))
|
))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -722,4 +727,4 @@
|
||||||
@endif
|
@endif
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -4,101 +4,102 @@
|
||||||
@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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page.no-page-break {
|
.page.no-page-break {
|
||||||
page-break-after: avoid !important;
|
page-break-after: avoid !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Workaround because of Firefox bug
|
Workaround because of Firefox bug
|
||||||
see https://github.com/twbs/bootstrap/issues/22753
|
see https://github.com/twbs/bootstrap/issues/22753
|
||||||
and https://bugzilla.mozilla.org/show_bug.cgi?id=1413121
|
and https://bugzilla.mozilla.org/show_bug.cgi?id=1413121
|
||||||
*/
|
*/
|
||||||
.row {
|
.row {
|
||||||
display: inline !important;
|
display: inline !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</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"
|
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>
|
||||||
data-trigger="hover click"
|
</h2>
|
||||||
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>
|
<div class="float-right">
|
||||||
</h2>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button" data-toggle="collapse"
|
||||||
<div class="float-right">
|
data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right print-all-locations-button"
|
||||||
</button>
|
href="#">
|
||||||
</div>
|
{{ $__t('Print') . ' (' . $__t('all locations') . ')' }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
</div>
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right print-all-locations-button"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Print') . ' (' . $__t('all locations') . ')' }}
|
|
||||||
</a>
|
|
||||||
</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" href="#">
|
||||||
<a class="btn btn-outline-dark btn-sm responsive-button print-single-location-button d-print-none"
|
{{ $__t('Print') . ' (' . $__t('this location') . ')' }}
|
||||||
href="#">
|
</a>
|
||||||
{{ $__t('Print') . ' (' . $__t('this location') . ')' }}
|
</h1>
|
||||||
</a>
|
<h6 class="mb-4 d-none d-print-block text-center">
|
||||||
</h1>
|
{{ $__t('Time of printing') }}:
|
||||||
<h6 class="mb-4 d-none d-print-block text-center">
|
<span class="d-inline print-timestamp"></span>
|
||||||
{{ $__t('Time of printing') }}:
|
</h6>
|
||||||
<span class="d-inline print-timestamp"></span>
|
<div class="row w-75">
|
||||||
</h6>
|
<div class="col">
|
||||||
<div class="row w-75">
|
{{-- TODO: DataTables: dynamic data: stock --}}
|
||||||
<div class="col">
|
<table class="table">
|
||||||
<table class="table">
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<th>{{ $__t('Product') }}</th>
|
||||||
<th>{{ $__t('Product') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th>{{ $__t('Consumed amount') . ' / ' . $__t('Notes') }}</th>
|
||||||
<th>{{ $__t('Consumed amount') . ' / ' . $__t('Notes') }}</th>
|
</tr>
|
||||||
</tr>
|
</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
|
||||||
<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>
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span>
|
||||||
<span class="small font-italic">@if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif</span>
|
<span
|
||||||
</td>
|
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>
|
||||||
<td class=""></td>
|
<span class="small font-italic">
|
||||||
</tr>
|
@if ($currentStockEntry->amount_opened > 0)
|
||||||
@endforeach
|
{{ $__t('%s opened', $currentStockEntry->amount_opened) }}
|
||||||
</tbody>
|
@endif
|
||||||
</table>
|
</span>
|
||||||
</div>
|
</td>
|
||||||
</div>
|
<td class=""></td>
|
||||||
</div>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,122 +5,108 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
</button>
|
href="{{ $U('/location/new?embedded') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary 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 show-as-dialog-link"
|
href="{{ $U('/userfields?entity=locations') }}">
|
||||||
href="{{ $U('/location/new?embedded') }}">
|
{{ $__t('Configure userfields') }}
|
||||||
{{ $__t('Add') }}
|
</a>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=locations') }}">
|
</div>
|
||||||
{{ $__t('Configure userfields') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#locations-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Description') }}</th>
|
||||||
</th>
|
|
||||||
<th>{{ $__t('Name') }}</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" href="#"
|
||||||
<a class="btn btn-danger btn-sm location-delete-button"
|
data-location-id="{{ $location->id }}" data-location-name="{{ $location->name }}"
|
||||||
href="#"
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
data-location-id="{{ $location->id }}"
|
<i class="fas fa-trash"></i>
|
||||||
data-location-name="{{ $location->name }}"
|
</a>
|
||||||
data-toggle="tooltip"
|
</td>
|
||||||
title="{{ $__t('Delete this item') }}">
|
<td>
|
||||||
<i class="fas fa-trash"></i>
|
{{ $location->name }}
|
||||||
</a>
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{{ $location->description }}
|
||||||
{{ $location->name }}
|
</td>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ $location->description }}
|
|
||||||
</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,140 +5,120 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
href="{{ $U('/manageapikeys/new') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
</div>
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/manageapikeys/new') }}">
|
</div>
|
||||||
{{ $__t('Add') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#apikeys-table"
|
<th>{{ $__t('API key') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th class="allow-grouping">{{ $__t('User') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Expires') }}</th>
|
||||||
<th>{{ $__t('API key') }}</th>
|
<th>{{ $__t('Last used') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('User') }}</th>
|
<th>{{ $__t('Created') }}</th>
|
||||||
<th>{{ $__t('Expires') }}</th>
|
<th class="allow-grouping">{{ $__t('Key type') }}</th>
|
||||||
<th>{{ $__t('Last used') }}</th>
|
</tr>
|
||||||
<th>{{ $__t('Created') }}</th>
|
</thead>
|
||||||
<th class="allow-grouping">{{ $__t('Key type') }}</th>
|
<tbody class="d-none">
|
||||||
</tr>
|
@foreach ($apiKeys as $apiKey)
|
||||||
</thead>
|
<tr id="apiKeyRow_{{ $apiKey->id }}">
|
||||||
<tbody class="d-none">
|
<td class="fit-content border-right">
|
||||||
@foreach($apiKeys as $apiKey)
|
<a class="btn btn-danger btn-sm apikey-delete-button" href="#"
|
||||||
<tr id="apiKeyRow_{{ $apiKey->id }}">
|
data-apikey-id="{{ $apiKey->id }}" data-apikey-apikey="{{ $apiKey->api_key }}"
|
||||||
<td class="fit-content border-right">
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
<a class="btn btn-danger btn-sm apikey-delete-button"
|
<i class="fas fa-trash"></i>
|
||||||
href="#"
|
</a>
|
||||||
data-apikey-id="{{ $apiKey->id }}"
|
<a class="btn btn-info btn-sm apikey-show-qr-button" href="#"
|
||||||
data-apikey-apikey="{{ $apiKey->api_key }}"
|
data-apikey-key="{{ $apiKey->api_key }}"
|
||||||
data-toggle="tooltip"
|
data-apikey-type="{{ $apiKey->key_type }}" data-toggle="tooltip"
|
||||||
title="{{ $__t('Delete this item') }}">
|
title="{{ $__t('Show a QR-Code for this API key') }}">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-qrcode"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-info btn-sm apikey-show-qr-button"
|
</td>
|
||||||
href="#"
|
<td>
|
||||||
data-apikey-key="{{ $apiKey->api_key }}"
|
{{ $apiKey->api_key }}
|
||||||
data-apikey-type="{{ $apiKey->key_type }}"
|
</td>
|
||||||
data-toggle="tooltip"
|
<td>
|
||||||
title="{{ $__t('Show a QR-Code for this API key') }}">
|
{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $apiKey->user_id)) }}
|
||||||
<i class="fas fa-qrcode"></i>
|
</td>
|
||||||
</a>
|
<td>
|
||||||
</td>
|
{{ $apiKey->expires }}
|
||||||
<td>
|
<time class="timeago timeago-contextual" datetime="{{ $apiKey->expires }}"></time>
|
||||||
{{ $apiKey->api_key }}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
@if (empty($apiKey->last_used))
|
||||||
{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $apiKey->user_id)) }}
|
{{ $__t('never') }}@else{{ $apiKey->last_used }}
|
||||||
</td>
|
@endif
|
||||||
<td>
|
<time class="timeago timeago-contextual" datetime="{{ $apiKey->last_used }}"></time>
|
||||||
{{ $apiKey->expires }}
|
</td>
|
||||||
<time class="timeago timeago-contextual"
|
<td>
|
||||||
datetime="{{ $apiKey->expires }}"></time>
|
{{ $apiKey->row_created_timestamp }}
|
||||||
</td>
|
<time class="timeago timeago-contextual"
|
||||||
<td>
|
datetime="{{ $apiKey->row_created_timestamp }}"></time>
|
||||||
@if(empty($apiKey->last_used)){{ $__t('never') }}@else{{ $apiKey->last_used }}@endif
|
</td>
|
||||||
<time class="timeago timeago-contextual"
|
<td>
|
||||||
datetime="{{ $apiKey->last_used }}"></time>
|
{{ $apiKey->key_type }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
</tr>
|
||||||
{{ $apiKey->row_created_timestamp }}
|
@endforeach
|
||||||
<time class="timeago timeago-contextual"
|
</tbody>
|
||||||
datetime="{{ $apiKey->row_created_timestamp }}"></time>
|
</table>
|
||||||
</td>
|
</div>
|
||||||
<td>
|
</div>
|
||||||
{{ $apiKey->key_type }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,365 +5,311 @@
|
||||||
@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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-fluid {
|
.img-fluid {
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
max-height: 140px;
|
max-height: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-time-grid-container,
|
.fc-time-grid-container,
|
||||||
hr.fc-divider {
|
hr.fc-divider {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-axis {
|
.fc-axis {
|
||||||
width: 25px !important;
|
width: 25px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-axis div {
|
.fc-axis div {
|
||||||
transform: translateX(-50%) translateY(-50%) rotate(-90deg);
|
transform: translateX(-50%) translateY(-50%) rotate(-90deg);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.75em;
|
font-size: 1.75em;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 0;
|
left: 0;
|
||||||
margin-left: 17px;
|
margin-left: 17px;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
line-height: 0.55;
|
line-height: 0.55;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-axis .small {
|
.fc-axis .small {
|
||||||
font-size: 60%;
|
font-size: 60%;
|
||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-content-skeleton {
|
.fc-content-skeleton {
|
||||||
padding-bottom: 0 !important;
|
padding-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar[data-primary-section='false'] .fc-toolbar.fc-header-toolbar,
|
.calendar[data-primary-section='false'] .fc-toolbar.fc-header-toolbar,
|
||||||
.calendar[data-primary-section='false'] .fc-head {
|
.calendar[data-primary-section='false'] .fc-head {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar[data-primary-section='false'] {
|
.calendar[data-primary-section='false'] {
|
||||||
border-top: #d6d6d6 solid 5px;
|
border-top: #d6d6d6 solid 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 400px) {
|
@media (min-width: 400px) {
|
||||||
.table-inline-menu.dropdown-menu {
|
.table-inline-menu.dropdown-menu {
|
||||||
width: 200px !important;
|
width: 200px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</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) !!}
|
||||||
|
|
||||||
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
Grocy.QuantityUnits = {!! json_encode($quantityUnits) !!};
|
||||||
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"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-target="#related-links">
|
</button>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
</div>
|
||||||
</button>
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 d-print-none" id="related-links">
|
||||||
</div>
|
<a id="print-meal-plan-button" class="btn btn-outline-dark m-1 mt-md-0 mb-md-0 float-right">
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 d-print-none"
|
{{ $__t('Print') }}
|
||||||
id="related-links">
|
</a>
|
||||||
<a id="print-meal-plan-button"
|
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
||||||
class="btn btn-outline-dark m-1 mt-md-0 mb-md-0 float-right">
|
href="{{ $U('/mealplansections') }}">
|
||||||
{{ $__t('Print') }}
|
{{ $__t('Configure sections') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/mealplansections') }}">
|
</div>
|
||||||
{{ $__t('Configure sections') }}
|
</div>
|
||||||
</a>
|
</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) }}" {{-- $loop->last doesn't work however, is always null... --}}
|
||||||
data-primary-section="{{ BoolToString($loop->first) }}"
|
data-last-section="{{ BoolToString(array_values(array_slice($usedMealplanSections->fetchAll(), -1))[0]->id == $mealplanSection->id) }}">
|
||||||
{{--
|
</div>
|
||||||
$loop->last doesn't work however, is always null...
|
</div>
|
||||||
--}}
|
</div>
|
||||||
data-last-section="{{ BoolToString(array_values(array_slice($usedMealplanSections->fetchAll(), -1))[0]->id == $mealplanSection->id) }}">
|
@endforeach
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@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-last-section="true">
|
||||||
data-section-name=""
|
</div>
|
||||||
data-primary-section="true"
|
</div>
|
||||||
data-last-section="true">
|
</div>
|
||||||
</div>
|
@endif
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="add-recipe-modal" tabindex="-1">
|
||||||
id="add-recipe-modal"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 id="add-recipe-modal-title" class="modal-title w-100"></h4>
|
||||||
<div class="modal-header">
|
</div>
|
||||||
<h4 id="add-recipe-modal-title"
|
<div class="modal-body">
|
||||||
class="modal-title w-100"></h4>
|
<form id="add-recipe-form" novalidate>
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form id="add-recipe-form"
|
|
||||||
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>
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
<button id="save-add-recipe-button"
|
</div>
|
||||||
data-dismiss="modal"
|
</div>
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="add-note-modal" tabindex="-1">
|
||||||
id="add-note-modal"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 id="add-note-modal-title" class="modal-title w-100"></h4>
|
||||||
<div class="modal-header">
|
</div>
|
||||||
<h4 id="add-note-modal-title"
|
<div class="modal-body">
|
||||||
class="modal-title w-100"></h4>
|
<form id="add-note-form" novalidate>
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form id="add-note-form"
|
|
||||||
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"
|
</div>
|
||||||
id="note"
|
|
||||||
name="note"></textarea>
|
|
||||||
</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>
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
<button id="save-add-note-button"
|
</div>
|
||||||
data-dismiss="modal"
|
</div>
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="add-product-modal" tabindex="-1">
|
||||||
id="add-product-modal"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 id="add-product-modal-title" class="modal-title w-100"></h4>
|
||||||
<div class="modal-header">
|
</div>
|
||||||
<h4 id="add-product-modal-title"
|
<div class="modal-body">
|
||||||
class="modal-title w-100"></h4>
|
<form id="add-product-form" novalidate>
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form id="add-product-form"
|
|
||||||
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>
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
<button id="save-add-product-button"
|
</div>
|
||||||
data-dismiss="modal"
|
</div>
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="copy-day-modal" tabindex="-1">
|
||||||
id="copy-day-modal"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content">
|
||||||
<div class="modal-dialog">
|
<div class="modal-header">
|
||||||
<div class="modal-content">
|
<h4 id="copy-day-modal-title" class="modal-title w-100"></h4>
|
||||||
<div class="modal-header">
|
</div>
|
||||||
<h4 id="copy-day-modal-title"
|
<div class="modal-body">
|
||||||
class="modal-title w-100"></h4>
|
<form id="copy-day-form" novalidate>
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form id="copy-day-form"
|
|
||||||
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',
|
||||||
'initWithNow' => false,
|
'initWithNow' => false,
|
||||||
'limitEndToNow' => false,
|
'limitEndToNow' => false,
|
||||||
'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>
|
class="btn btn-primary">{{ $__t('Copy') }}</button>
|
||||||
<button id="save-copy-day-button"
|
</div>
|
||||||
data-dismiss="modal"
|
</div>
|
||||||
class="btn btn-primary">{{ $__t('Copy') }}</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal fade"
|
<div class="modal fade" id="mealplan-productcard-modal" tabindex="-1">
|
||||||
id="mealplan-productcard-modal"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-dialog">
|
<div class="modal-body">
|
||||||
<div class="modal-content text-center">
|
@include('components.productcard')
|
||||||
<div class="modal-body">
|
</div>
|
||||||
@include('components.productcard')
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
<div class="modal-footer">
|
</div>
|
||||||
<button type="button"
|
</div>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,111 +5,94 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
</button>
|
href="{{ $U('/mealplansection/new?embedded') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
</div>
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
</div>
|
||||||
href="{{ $U('/mealplansection/new?embedded') }}">
|
</div>
|
||||||
{{ $__t('Add') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#mealplansections-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Sort number') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Time') }}</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
</tr>
|
||||||
<th>{{ $__t('Sort number') }}</th>
|
</thead>
|
||||||
<th>{{ $__t('Time') }}</th>
|
<tbody class="d-none">
|
||||||
</tr>
|
@foreach ($mealplanSections as $mealplanSection)
|
||||||
</thead>
|
<tr>
|
||||||
<tbody class="d-none">
|
<td class="fit-content border-right">
|
||||||
@foreach($mealplanSections as $mealplanSection)
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
<tr>
|
href="{{ $U('/mealplansection/') }}{{ $mealplanSection->id }}?embedded"
|
||||||
<td class="fit-content border-right">
|
data-toggle="tooltip" title="{{ $__t('Edit this item') }}">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<i class="fas fa-edit"></i>
|
||||||
href="{{ $U('/mealplansection/') }}{{ $mealplanSection->id }}?embedded"
|
</a>
|
||||||
data-toggle="tooltip"
|
<a class="btn btn-danger btn-sm mealplansection-delete-button" href="#"
|
||||||
title="{{ $__t('Edit this item') }}">
|
data-mealplansection-id="{{ $mealplanSection->id }}"
|
||||||
<i class="fas fa-edit"></i>
|
data-mealplansection-name="{{ $mealplanSection->name }}" data-toggle="tooltip"
|
||||||
</a>
|
title="{{ $__t('Delete this item') }}">
|
||||||
<a class="btn btn-danger btn-sm mealplansection-delete-button"
|
<i class="fas fa-trash"></i>
|
||||||
href="#"
|
</a>
|
||||||
data-mealplansection-id="{{ $mealplanSection->id }}"
|
</td>
|
||||||
data-mealplansection-name="{{ $mealplanSection->name }}"
|
<td>
|
||||||
data-toggle="tooltip"
|
{{ $mealplanSection->name }}
|
||||||
title="{{ $__t('Delete this item') }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td>
|
||||||
</a>
|
{{ $mealplanSection->sort_number }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $mealplanSection->name }}
|
{{ $mealplanSection->time_info }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
</tr>
|
||||||
{{ $mealplanSection->sort_number }}
|
@endforeach
|
||||||
</td>
|
</tbody>
|
||||||
<td>
|
</table>
|
||||||
{{ $mealplanSection->time_info }}
|
</div>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -1,113 +1,104 @@
|
||||||
@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') }}
|
||||||
</h2>
|
<strong>{{ $product->name }}</strong></span>
|
||||||
</div>
|
</h2>
|
||||||
</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 }}';
|
||||||
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
|
data-target="#barcode">
|
||||||
id="barcode"
|
@include('components.barcodescanner')
|
||||||
name="barcode"
|
</div>
|
||||||
value="@if($mode == 'edit'){{ $barcode->barcode }}@endif"
|
</div>
|
||||||
data-target="#barcode">
|
|
||||||
@include('components.barcodescanner')
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $barcode->amount; } else { $value = ''; } @endphp
|
@php
|
||||||
@include('components.productamountpicker', array(
|
if ($mode == 'edit') {
|
||||||
'value' => $value,
|
$value = $barcode->amount;
|
||||||
'isRequired' => false
|
} else {
|
||||||
))
|
$value = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('components.productamountpicker', [
|
||||||
|
'value' => $value,
|
||||||
|
'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' && $store->id == $barcode->shopping_location_id) selected="selected" @endif
|
||||||
<option @if($mode=='edit'
|
value="{{ $store->id }}">{{ $store->name }}</option>
|
||||||
&&
|
@endforeach
|
||||||
$store->id == $barcode->shopping_location_id) selected="selected" @endif value="{{ $store->id }}">{{ $store->name }}</option>
|
</select>
|
||||||
@endforeach
|
</div>
|
||||||
</select>
|
@else
|
||||||
</div>
|
<input type="hidden" name="shopping_location_id" id="shopping_location_id" value="1">
|
||||||
@else
|
@endif
|
||||||
<input type="hidden"
|
|
||||||
name="shopping_location_id"
|
|
||||||
id="shopping_location_id"
|
|
||||||
value="1">
|
|
||||||
@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"
|
</div>
|
||||||
name="note"
|
|
||||||
value="@if($mode == 'edit'){{ $barcode->note }}@endif">
|
|
||||||
</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,129 +5,116 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button show-as-dialog-link m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
href="{{ $U('/productgroup/new?embedded') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary 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('/userfields?entity=product_groups') }}">
|
||||||
href="{{ $U('/productgroup/new?embedded') }}">
|
{{ $__t('Configure userfields') }}
|
||||||
{{ $__t('Add') }}
|
</a>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=product_groups') }}">
|
</div>
|
||||||
{{ $__t('Configure userfields') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#productgroups-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Description') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Product count') }}</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
|
||||||
<th>{{ $__t('Description') }}</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" href="#"
|
||||||
<a class="btn btn-danger btn-sm product-group-delete-button"
|
data-group-id="{{ $productGroup->id }}"
|
||||||
href="#"
|
data-group-name="{{ $productGroup->name }}" data-toggle="tooltip"
|
||||||
data-group-id="{{ $productGroup->id }}"
|
title="{{ $__t('Delete this item') }}">
|
||||||
data-group-name="{{ $productGroup->name }}"
|
<i class="fas fa-trash"></i>
|
||||||
data-toggle="tooltip"
|
</a>
|
||||||
title="{{ $__t('Delete this item') }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td>
|
||||||
</a>
|
{{ $productGroup->name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $productGroup->name }}
|
{{ $productGroup->description }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $productGroup->description }}
|
{{ count(FindAllObjectsInArrayByPropertyValue($products, 'product_group_id', $productGroup->id)) }}
|
||||||
</td>
|
<a class="btn btn-link btn-sm text-body"
|
||||||
<td>
|
href="{{ $U('/products?product-group=') . $productGroup->id }}">
|
||||||
{{ count(FindAllObjectsInArrayByPropertyValue($products, 'product_group_id', $productGroup->id)) }}
|
<i class="fas fa-external-link-alt"></i>
|
||||||
<a class="btn btn-link btn-sm text-body"
|
</a>
|
||||||
href="{{ $U('/products?product-group=') . $productGroup->id }}">
|
</td>
|
||||||
<i class="fas fa-external-link-alt"></i>
|
|
||||||
</a>
|
|
||||||
</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,268 +5,148 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
href="{{ $U('/product/new') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary 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('/userfields?entity=products') }}">
|
||||||
href="{{ $U('/product/new') }}">
|
{{ $__t('Configure userfields') }}
|
||||||
{{ $__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"
|
href="{{ $U('/stocksettings#productpresets') }}">
|
||||||
href="{{ $U('/userfields?entity=products') }}">
|
{{ $__t('Presets for new products') }}
|
||||||
{{ $__t('Configure userfields') }}
|
</a>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/stocksettings#productpresets') }}">
|
</div>
|
||||||
{{ $__t('Presets for new products') }}
|
</div>
|
||||||
</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 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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product group') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
{{-- TODO: Select2: dynamic data: product_groups --}}
|
||||||
<div class="input-group-prepend">
|
<select class="custom-control custom-select" id="product-group-filter">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product group') }}</span>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
</div>
|
@foreach ($productGroups as $productGroup)
|
||||||
<select class="custom-control custom-select"
|
<option value="{{ $productGroup->id }}">{{ $productGroup->name }}</option>
|
||||||
id="product-group-filter">
|
@endforeach
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
</select>
|
||||||
@foreach($productGroups as $productGroup)
|
</div>
|
||||||
<option value="{{ $productGroup->id }}">{{ $productGroup->name }}</option>
|
</div>
|
||||||
@endforeach
|
<div class="col-12 col-md-6 col-xl-2">
|
||||||
</select>
|
<div class="form-check custom-control custom-checkbox">
|
||||||
</div>
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-disabled">
|
||||||
</div>
|
<label class="form-check-label custom-control-label" for="show-disabled">
|
||||||
<div class="col-12 col-md-6 col-xl-2">
|
{{ $__t('Show disabled') }}
|
||||||
<div class="form-check custom-control custom-checkbox">
|
</label>
|
||||||
<input class="form-check-input custom-control-input"
|
</div>
|
||||||
type="checkbox"
|
</div>
|
||||||
id="show-disabled">
|
<div class="col-12 col-md-6 col-xl-2">
|
||||||
<label class="form-check-label custom-control-label"
|
<div class="form-check custom-control custom-checkbox">
|
||||||
for="show-disabled">
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-only-in-stock">
|
||||||
{{ $__t('Show disabled') }}
|
<label class="form-check-label custom-control-label" for="show-only-in-stock">
|
||||||
</label>
|
{{ $__t('Show only in-stock products') }}
|
||||||
</div>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-2">
|
</div>
|
||||||
<div class="form-check custom-control custom-checkbox">
|
<div class="col">
|
||||||
<input class="form-check-input custom-control-input"
|
<div class="float-right">
|
||||||
type="checkbox"
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
id="show-only-in-stock">
|
{{ $__t('Clear filter') }}
|
||||||
<label class="form-check-label custom-control-label"
|
</a>
|
||||||
for="show-only-in-stock">
|
</div>
|
||||||
{{ $__t('Show only in-stock products') }}
|
</div>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div class="float-right">
|
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#products-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
data-toggle="tooltip"
|
</th>
|
||||||
title="{{ $__t('Table options') }}"
|
<th>{{ $__t('Name') }}</th>
|
||||||
data-table-selector="#products-table"
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
</th>
|
||||||
</th>
|
<th class="allow-grouping">{{ $__t('Min. stock amount') }}</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th class="">{{ $__t('Default quantity unit purchase') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}</th>
|
<th class="allow-grouping">{{ $__t('Quantity unit stock') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Min. stock amount') }}</th>
|
<th class="">{{ $__t('Product group') }}</th>
|
||||||
<th class="">{{ $__t('Default quantity unit purchase') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">
|
||||||
<th class="allow-grouping">{{ $__t('Quantity unit stock') }}</th>
|
{{ $__t('Default store') }}</th>
|
||||||
<th class="">{{ $__t('Product group') }}</th>
|
@include('components.userfields_thead', [
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">{{ $__t('Default store') }}</th>
|
'userfields' => $userfields,
|
||||||
|
])
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@include('components.userfields_thead', array(
|
<div class="modal fade" id="merge-products-modal" tabindex="-1">
|
||||||
'userfields' => $userfields
|
<div class="modal-dialog">
|
||||||
))
|
<div class="modal-content text-center">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title w-100">{{ $__t('Merge products') }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="merge-products-keep">{{ $__t('Product to keep') }} <i
|
||||||
|
class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
|
title="{{ $__t('After merging, this product will be kept') }}"></i>
|
||||||
|
</label>
|
||||||
|
<select class="select2 custom-control custom-select" id="merge-products-keep"></select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="merge-products-remove">{{ $__t('Product to remove') }} <i
|
||||||
|
class="fas fa-question-circle text-muted" data-toggle="tooltip" 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>
|
||||||
|
</label>
|
||||||
|
<select class="select2 custom-control custom-select" id="merge-products-remove"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
|
<button id="merge-products-save-button" type="button" class="btn btn-primary"
|
||||||
|
data-dismiss="modal">{{ $__t('OK') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</tr>
|
<script>
|
||||||
</thead>
|
var userfields = {!! json_encode($userfields) !!};
|
||||||
<tbody class="d-none">
|
</script>
|
||||||
@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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal fade"
|
|
||||||
id="merge-products-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content text-center">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h4 class="modal-title w-100">{{ $__t('Merge products') }}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="merge-products-keep">{{ $__t('Product to keep') }} <i class="fas fa-question-circle text-muted"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
data-trigger="hover click"
|
|
||||||
title="{{ $__t('After merging, this product will be kept') }}"></i>
|
|
||||||
</label>
|
|
||||||
<select class="custom-control custom-select"
|
|
||||||
id="merge-products-keep">
|
|
||||||
<option></option>
|
|
||||||
@foreach($products as $product)
|
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="merge-products-remove">{{ $__t('Product to remove') }} <i class="fas fa-question-circle text-muted"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
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>
|
|
||||||
</label>
|
|
||||||
<select class="custom-control custom-select"
|
|
||||||
id="merge-products-remove">
|
|
||||||
<option></option>
|
|
||||||
@foreach($products as $product)
|
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
|
||||||
<button id="merge-products-save-button"
|
|
||||||
type="button"
|
|
||||||
class="btn btn-primary"
|
|
||||||
data-dismiss="modal">{{ $__t('OK') }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -53,62 +53,61 @@
|
||||||
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'
|
|
||||||
))
|
))
|
||||||
|
|
||||||
@include('components.productamountpicker', array(
|
@include('components.productamountpicker', array(
|
||||||
'value' => 1,
|
'value' => 1,
|
||||||
'additionalHtmlContextHelp' => '<div id="tare-weight-handling-info"
|
'additionalHtmlContextHelp' => '<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>'
|
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>'
|
||||||
))
|
))
|
||||||
|
|
||||||
@if(boolval($userSettings['show_purchased_date_on_purchase']))
|
@if(boolval($userSettings['show_purchased_date_on_purchase']))
|
||||||
@include('components.datetimepicker2', array(
|
@include('components.datetimepicker2', array(
|
||||||
'id' => 'purchased_date',
|
'id' => 'purchased_date',
|
||||||
'label' => 'Purchased date',
|
'label' => 'Purchased date',
|
||||||
'format' => 'YYYY-MM-DD',
|
'format' => 'YYYY-MM-DD',
|
||||||
'initWithNow' => true,
|
'initWithNow' => true,
|
||||||
'limitEndToNow' => false,
|
'limitEndToNow' => false,
|
||||||
'limitStartToNow' => false,
|
'limitStartToNow' => false,
|
||||||
'invalidFeedback' => $__t('A purchased date is required'),
|
'invalidFeedback' => $__t('A purchased date is required'),
|
||||||
'nextInputSelector' => '#best_before_date',
|
'nextInputSelector' => '#best_before_date',
|
||||||
'additionalCssClasses' => 'date-only-datetimepicker2',
|
'additionalCssClasses' => 'date-only-datetimepicker2',
|
||||||
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
||||||
))
|
))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||||
@include('components.datetimepicker', array(
|
@include('components.datetimepicker', array(
|
||||||
'id' => 'best_before_date',
|
'id' => 'best_before_date',
|
||||||
'label' => 'Due date',
|
'label' => 'Due date',
|
||||||
'format' => 'YYYY-MM-DD',
|
'format' => 'YYYY-MM-DD',
|
||||||
'initWithNow' => false,
|
'initWithNow' => false,
|
||||||
'limitEndToNow' => false,
|
'limitEndToNow' => false,
|
||||||
'limitStartToNow' => false,
|
'limitStartToNow' => false,
|
||||||
'invalidFeedback' => $__t('A due date is required'),
|
'invalidFeedback' => $__t('A due date is required'),
|
||||||
'nextInputSelector' => '#price',
|
'nextInputSelector' => '#price',
|
||||||
'additionalCssClasses' => 'date-only-datetimepicker',
|
'additionalCssClasses' => 'date-only-datetimepicker',
|
||||||
'shortcutValue' => '2999-12-31',
|
'shortcutValue' => '2999-12-31',
|
||||||
'shortcutLabel' => 'Never overdue',
|
'shortcutLabel' => 'Never overdue',
|
||||||
'earlierThanInfoLimit' => date('Y-m-d'),
|
'earlierThanInfoLimit' => date('Y-m-d'),
|
||||||
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
'earlierThanInfoText' => $__t('The given date is earlier than today, are you sure?'),
|
||||||
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
'activateNumberPad' => GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD
|
||||||
))
|
))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', array(
|
||||||
'id' => 'price',
|
'id' => 'price',
|
||||||
'label' => 'Price',
|
'label' => 'Price',
|
||||||
'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_prices']),
|
'min' => '0.' . str_repeat('0', $userSettings['stock_decimal_places_prices']),
|
||||||
'decimals' => $userSettings['stock_decimal_places_prices'],
|
'decimals' => $userSettings['stock_decimal_places_prices'],
|
||||||
'value' => '',
|
'value' => '',
|
||||||
'contextInfoId' => 'price-hint',
|
'contextInfoId' => 'price-hint',
|
||||||
'isRequired' => false,
|
'isRequired' => false,
|
||||||
'additionalGroupCssClasses' => 'mb-1',
|
'additionalGroupCssClasses' => 'mb-1',
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-currency'
|
'additionalCssClasses' => 'locale-number-input locale-number-currency'
|
||||||
))
|
))
|
||||||
|
|
||||||
<div class="custom-control custom-radio custom-control-inline mt-n2 mb-3">
|
<div class="custom-control custom-radio custom-control-inline mt-n2 mb-3">
|
||||||
|
|
@ -131,8 +130,8 @@
|
||||||
for="price-type-total-price">{{ $__t('Total price') }}</label>
|
for="price-type-total-price">{{ $__t('Total price') }}</label>
|
||||||
</div>
|
</div>
|
||||||
@include('components.shoppinglocationpicker', array(
|
@include('components.shoppinglocationpicker', array(
|
||||||
'label' => 'Store',
|
'label' => 'Store',
|
||||||
'shoppinglocations' => $shoppinglocations
|
'shoppinglocations' => $shoppinglocations
|
||||||
))
|
))
|
||||||
@else
|
@else
|
||||||
<input type="hidden"
|
<input type="hidden"
|
||||||
|
|
@ -143,8 +142,8 @@
|
||||||
|
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
@include('components.locationpicker', array(
|
@include('components.locationpicker', array(
|
||||||
'locations' => $locations,
|
'locations' => $locations,
|
||||||
'isRequired' => false
|
'isRequired' => false
|
||||||
))
|
))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,122 +1,116 @@
|
||||||
@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') }}
|
||||||
@else
|
<strong>{{ $product->name }}</strong></span>
|
||||||
<span class="text-muted small">{{ $__t('Default for QU') }} <strong>{{ $defaultQuUnit->name }}</strong></span>
|
@else
|
||||||
@endif
|
<span class="text-muted small">{{ $__t('Default for QU') }}
|
||||||
</h2>
|
<strong>{{ $defaultQuUnit->name }}</strong></span>
|
||||||
</div>
|
@endif
|
||||||
</div>
|
</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 = {{ $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"
|
@endif
|
||||||
value="{{ $product->id }}">
|
|
||||||
@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"
|
<option></option>
|
||||||
name="from_qu_id">
|
@foreach ($quantityunits as $quantityunit)
|
||||||
<option></option>
|
<option @if (($product != null && $quantityunit->id == $product->qu_id_stock) || ($defaultQuUnit != null && $quantityunit->id == $defaultQuUnit->id)) ) selected="selected" @endif
|
||||||
@foreach($quantityunits as $quantityunit)
|
value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">
|
||||||
<option @if(($product
|
{{ $quantityunit->name }}</option>
|
||||||
!=null
|
@endforeach
|
||||||
&&
|
</select>
|
||||||
$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>
|
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
||||||
@endforeach
|
</div>
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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"
|
<option></option>
|
||||||
name="to_qu_id">
|
@foreach ($quantityunits as $quantityunit)
|
||||||
<option></option>
|
<option @if ($mode == 'edit' && $quantityunit->id == $quConversion->to_qu_id) selected="selected" @endif
|
||||||
@foreach($quantityunits as $quantityunit)
|
value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">
|
||||||
<option @if($mode=='edit'
|
{{ $quantityunit->name }}</option>
|
||||||
&&
|
@endforeach
|
||||||
$quantityunit->id == $quConversion->to_qu_id) selected="selected" @endif value="{{ $quantityunit->id }}" data-plural-form="{{ $quantityunit->name_plural }}">{{ $quantityunit->name }}</option>
|
</select>
|
||||||
@endforeach
|
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
||||||
</select>
|
</div>
|
||||||
<div class="invalid-feedback">{{ $__t('A quantity unit is required') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $quConversion->factor; } else { $value = 1; } @endphp
|
@php
|
||||||
@include('components.numberpicker', array(
|
if ($mode == 'edit') {
|
||||||
'id' => 'factor',
|
$value = $quConversion->factor;
|
||||||
'label' => 'Factor',
|
} else {
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
$value = 1;
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
}
|
||||||
'value' => $value,
|
@endphp
|
||||||
'additionalHtmlElements' => '<p id="qu-conversion-info"
|
@include('components.numberpicker', [
|
||||||
class="form-text text-info d-none"></p>',
|
'id' => 'factor',
|
||||||
'additionalCssClasses' => 'input-group-qu locale-number-input locale-number-quantity-amount'
|
'label' => 'Factor',
|
||||||
))
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
|
'value' => $value,
|
||||||
|
'additionalHtmlElements' => '<p id="qu-conversion-info"
|
||||||
|
class="form-text text-info d-none"></p>',
|
||||||
|
'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"
|
<label class="form-check-label custom-control-label"
|
||||||
id="create_inverse"
|
for="create_inverse">{{ $__t('Create inverse QU conversion') }}</label>
|
||||||
name="create_inverse:skip"
|
</div>
|
||||||
value="1">
|
<span id="qu-conversion-inverse-info" class="form-text text-info d-none"></span>
|
||||||
<label class="form-check-label custom-control-label"
|
</div>
|
||||||
for="create_inverse">{{ $__t('Create inverse QU conversion') }}</label>
|
|
||||||
</div>
|
|
||||||
<span id="qu-conversion-inverse-info"
|
|
||||||
class="form-text text-info d-none"></span>
|
|
||||||
</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,170 +1,161 @@
|
||||||
@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"
|
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||||
name="name"
|
</div>
|
||||||
value="@if($mode == 'edit'){{ $quantityUnit->name }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('A name is required') }}</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"
|
</div>
|
||||||
value="@if($mode == 'edit'){{ $quantityUnit->name_plural }}@endif">
|
|
||||||
</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>
|
||||||
<span class="small text-muted">
|
<span class="small text-muted">
|
||||||
{{ $__t('One plural form per line, the current language requires') }}:<br>
|
{{ $__t('One plural form per line, the current language requires') }}:<br>
|
||||||
{{ $__t('Plural count') }}: {{ $pluralCount }}<br>
|
{{ $__t('Plural count') }}: {{ $pluralCount }}<br>
|
||||||
{{ $__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
|
||||||
</div>
|
</textarea>
|
||||||
@endif
|
</div>
|
||||||
|
@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
|
||||||
</div>
|
</textarea>
|
||||||
|
</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
|
||||||
|
|
||||||
</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" type="button"
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
type="button"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-toggle="collapse"
|
</button>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-outline-primary btn-sm m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
</button>
|
href="{{ $U('/quantityunitconversion/new?embedded&qu-unit=' . $quantityUnit->id) }}">
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
{{ $__t('Add') }}
|
||||||
id="related-links">
|
</a>
|
||||||
<a class="btn btn-outline-primary btn-sm m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
</div>
|
||||||
href="{{ $U('/quantityunitconversion/new?embedded&qu-unit=' . $quantityUnit->id ) }}">
|
</div>
|
||||||
{{ $__t('Add') }}
|
|
||||||
</a>
|
|
||||||
</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"
|
</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Factor') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Unit') }}</th>
|
||||||
<th>{{ $__t('Factor') }}</th>
|
</tr>
|
||||||
<th>{{ $__t('Unit') }}</th>
|
</thead>
|
||||||
</tr>
|
<tbody class="d-none">
|
||||||
</thead>
|
@if ($mode == 'edit')
|
||||||
<tbody class="d-none">
|
@foreach ($defaultQuConversions as $defaultQuConversion)
|
||||||
@if($mode == "edit")
|
<tr>
|
||||||
@foreach($defaultQuConversions as $defaultQuConversion)
|
<td class="fit-content border-right">
|
||||||
<tr>
|
<a class="btn btn-sm btn-info show-as-dialog-link"
|
||||||
<td class="fit-content border-right">
|
href="{{ $U('/quantityunitconversion/' . $defaultQuConversion->id . '?embedded&qu-unit=' . $quantityUnit->id) }}"
|
||||||
<a class="btn btn-sm btn-info show-as-dialog-link"
|
data-qu-conversion-id="{{ $defaultQuConversion->id }}">
|
||||||
href="{{ $U('/quantityunitconversion/' . $defaultQuConversion->id . '?embedded&qu-unit=' . $quantityUnit->id ) }}"
|
<i class="fas fa-edit"></i>
|
||||||
data-qu-conversion-id="{{ $defaultQuConversion->id }}">
|
</a>
|
||||||
<i class="fas fa-edit"></i>
|
<a class="btn btn-sm btn-danger qu-conversion-delete-button" href="#"
|
||||||
</a>
|
data-qu-conversion-id="{{ $defaultQuConversion->id }}">
|
||||||
<a class="btn btn-sm btn-danger qu-conversion-delete-button"
|
<i class="fas fa-trash"></i>
|
||||||
href="#"
|
</a>
|
||||||
data-qu-conversion-id="{{ $defaultQuConversion->id }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td>
|
||||||
</a>
|
<span
|
||||||
</td>
|
class="locale-number locale-number-quantity-amount">{{ $defaultQuConversion->factor }}</span>
|
||||||
<td>
|
</td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $defaultQuConversion->factor }}</span>
|
<td>
|
||||||
</td>
|
{{ FindObjectInArrayByPropertyValue($quantityUnits, 'id', $defaultQuConversion->to_qu_id)->name }}
|
||||||
<td>
|
</td>
|
||||||
{{ FindObjectInArrayByPropertyValue($quantityUnits, 'id', $defaultQuConversion->to_qu_id)->name }}
|
</tr>
|
||||||
</td>
|
@endforeach
|
||||||
</tr>
|
@endif
|
||||||
@endforeach
|
</tbody>
|
||||||
@endif
|
</table>
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
</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 }}" data-singular-form="{{ $quantityUnit->name }}"
|
||||||
<option value="{{ $quantityUnit->id }}"
|
data-plural-form="{{ $quantityUnit->name_plural }}">{{ $quantityUnit->name }}</option>
|
||||||
data-singular-form="{{ $quantityUnit->name }}"
|
@endforeach
|
||||||
data-plural-form="{{ $quantityUnit->name_plural }}">{{ $quantityUnit->name }}</option>
|
</select>
|
||||||
@endforeach
|
</div>
|
||||||
</select>
|
|
||||||
</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,121 +5,107 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
href="{{ $U('/quantityunit/new') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary 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('/userfields?entity=quantity_units') }}">
|
||||||
href="{{ $U('/quantityunit/new') }}">
|
{{ $__t('Configure userfields') }}
|
||||||
{{ $__t('Add') }}
|
</a>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=quantity_units') }}">
|
</div>
|
||||||
{{ $__t('Configure userfields') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#quantityunits-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Description') }}</th>
|
||||||
</th>
|
|
||||||
<th>{{ $__t('Name') }}</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"
|
<i class="fas fa-edit"></i>
|
||||||
title="{{ $__t('Edit this item') }}">
|
</a>
|
||||||
<i class="fas fa-edit"></i>
|
<a class="btn btn-danger btn-sm quantityunit-delete-button" href="#"
|
||||||
</a>
|
data-quantityunit-id="{{ $quantityunit->id }}"
|
||||||
<a class="btn btn-danger btn-sm quantityunit-delete-button"
|
data-quantityunit-name="{{ $quantityunit->name }}" data-toggle="tooltip"
|
||||||
href="#"
|
title="{{ $__t('Delete this item') }}">
|
||||||
data-quantityunit-id="{{ $quantityunit->id }}"
|
<i class="fas fa-trash"></i>
|
||||||
data-quantityunit-name="{{ $quantityunit->name }}"
|
</a>
|
||||||
data-toggle="tooltip"
|
</td>
|
||||||
title="{{ $__t('Delete this item') }}">
|
<td>
|
||||||
<i class="fas fa-trash"></i>
|
{{ $quantityunit->name }}
|
||||||
</a>
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{{ $quantityunit->description }}
|
||||||
{{ $quantityunit->name }}
|
</td>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ $quantityunit->description }}
|
|
||||||
</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,414 +1,388 @@
|
||||||
@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>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditMode = '{{ $mode }}';
|
Grocy.EditMode = '{{ $mode }}';
|
||||||
Grocy.QuantityUnits = {!! json_encode($quantityunits) !!};
|
Grocy.QuantityUnits = {!! json_encode($quantityunits) !!};
|
||||||
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
|
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||||
id="name"
|
</div>
|
||||||
name="name"
|
|
||||||
value="@if($mode == 'edit'){{ $recipe->name }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@php if($mode == 'edit') { $value = $recipe->base_servings; } else { $value = 1; } @endphp
|
@php
|
||||||
@include('components.numberpicker', array(
|
if ($mode == 'edit') {
|
||||||
'id' => 'base_servings',
|
$value = $recipe->base_servings;
|
||||||
'label' => 'Servings',
|
} else {
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
$value = 1;
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
}
|
||||||
'value' => $value,
|
@endphp
|
||||||
'hint' => $__t('The ingredients listed here result in this amount of servings'),
|
@include('components.numberpicker', [
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
'id' => 'base_servings',
|
||||||
))
|
'label' => 'Servings',
|
||||||
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
|
'value' => $value,
|
||||||
|
'hint' => $__t('The ingredients listed here result in this amount of servings'),
|
||||||
|
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount',
|
||||||
|
])
|
||||||
|
|
||||||
<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" data-toggle="tooltip" data-trigger="hover click"
|
||||||
<i class="fas fa-question-circle text-muted"
|
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>
|
||||||
data-toggle="tooltip"
|
</label>
|
||||||
data-trigger="hover click"
|
</div>
|
||||||
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>
|
</div>
|
||||||
</label>
|
|
||||||
</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(
|
||||||
'disallowAllProductWorkflows' => true,
|
'When a product is selected, one unit (per serving in stock quantity unit) will be added to stock on consuming this recipe'
|
||||||
))
|
),
|
||||||
|
'disallowAllProductWorkflows' => true,
|
||||||
|
])
|
||||||
|
|
||||||
@include('components.userfieldsform', array(
|
@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 }}
|
||||||
</div>
|
@endif
|
||||||
|
</textarea>
|
||||||
|
</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>
|
||||||
<button class="save-recipe btn btn-info mb-2"
|
<button class="save-recipe btn btn-info mb-2"
|
||||||
data-location="return">{{ $__t('Save & return to recipes') }}</button>
|
data-location="return">{{ $__t('Save & return to recipes') }}</button>
|
||||||
|
|
||||||
</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"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-target="#related-links">
|
</button>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
</button>
|
<a id="recipe-pos-add-button"
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
class="btn btn-outline-primary btn-sm recipe-pos-add-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
id="related-links">
|
type="button" href="#">
|
||||||
<a id="recipe-pos-add-button"
|
{{ $__t('Add') }}
|
||||||
class="btn btn-outline-primary btn-sm recipe-pos-add-button m-1 mt-md-0 mb-md-0 float-right"
|
</a>
|
||||||
type="button"
|
</div>
|
||||||
href="#">
|
</div>
|
||||||
{{ $__t('Add') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#recipes-pos-table"
|
<th>{{ $__t('Product') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
</th>
|
<th class="fit-content">{{ $__t('Note') }}</th>
|
||||||
<th>{{ $__t('Product') }}</th>
|
<th class="allow-grouping">{{ $__t('Ingredient group') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
</tr>
|
||||||
<th class="fit-content">{{ $__t('Note') }}</th>
|
</thead>
|
||||||
<th class="allow-grouping">{{ $__t('Ingredient group') }}</th>
|
<tbody class="d-none">
|
||||||
</tr>
|
@if ($mode == 'edit')
|
||||||
</thead>
|
@foreach ($recipePositions as $recipePosition)
|
||||||
<tbody class="d-none">
|
<tr>
|
||||||
@if($mode == "edit")
|
<td class="fit-content border-right">
|
||||||
@foreach($recipePositions as $recipePosition)
|
<a class="btn btn-sm btn-info recipe-pos-edit-button" type="button" href="#"
|
||||||
<tr>
|
data-recipe-pos-id="{{ $recipePosition->id }}"
|
||||||
<td class="fit-content border-right">
|
data-product-id="{{ $recipePosition->product_id }}">
|
||||||
<a class="btn btn-sm btn-info recipe-pos-edit-button"
|
<i class="fas fa-edit"></i>
|
||||||
type="button"
|
</a>
|
||||||
href="#"
|
<a class="btn btn-sm btn-danger recipe-pos-delete-button" href="#"
|
||||||
data-recipe-pos-id="{{ $recipePosition->id }}"
|
data-recipe-pos-id="{{ $recipePosition->id }}"
|
||||||
data-product-id="{{ $recipePosition->product_id }}">
|
data-recipe-pos-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-danger recipe-pos-delete-button"
|
</td>
|
||||||
href="#"
|
<td>
|
||||||
data-recipe-pos-id="{{ $recipePosition->id }}"
|
{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }}
|
||||||
data-recipe-pos-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td>
|
||||||
</a>
|
@php
|
||||||
</td>
|
// The amount can't be non-numeric when using the frontend,
|
||||||
<td>
|
// but some users decide to edit the database manually and
|
||||||
{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }}
|
// enter something like "4 or 5" in the amount column (brilliant)
|
||||||
</td>
|
// => So at least don't crash this view by just assuming 0 if that's the case
|
||||||
<td>
|
if (!is_numeric($recipePosition->amount)) {
|
||||||
@php
|
$recipePosition->amount = 0;
|
||||||
// The amount can't be non-numeric when using the frontend,
|
}
|
||||||
// but some users decide to edit the database manually and
|
|
||||||
// enter something like "4 or 5" in the amount column (brilliant)
|
$product = FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id);
|
||||||
// => So at least don't crash this view by just assuming 0 if that's the case
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
||||||
if (!is_numeric($recipePosition->amount))
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
||||||
{
|
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $recipePosition->qu_id);
|
||||||
$recipePosition->amount = 0;
|
if ($productQuConversion && $recipePosition->only_check_single_unit_in_stock == 0) {
|
||||||
}
|
$recipePosition->amount = $recipePosition->amount * $productQuConversion->factor;
|
||||||
|
}
|
||||||
$product = FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id);
|
@endphp
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
@if (!empty($recipePosition->variable_amount))
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
{{ $recipePosition->variable_amount }}
|
||||||
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $recipePosition->qu_id);
|
@else
|
||||||
if ($productQuConversion && $recipePosition->only_check_single_unit_in_stock == 0)
|
<span class="locale-number locale-number-quantity-amount">
|
||||||
{
|
@if ($recipePosition->amount == round($recipePosition->amount))
|
||||||
$recipePosition->amount = $recipePosition->amount * $productQuConversion->factor;
|
{{ round($recipePosition->amount) }}@else{{ $recipePosition->amount }}
|
||||||
}
|
@endif
|
||||||
@endphp
|
</span>
|
||||||
@if(!empty($recipePosition->variable_amount))
|
@endif
|
||||||
{{ $recipePosition->variable_amount }}
|
{{ $__n($recipePosition->amount,FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name,FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name_plural,true) }}
|
||||||
@else
|
|
||||||
<span class="locale-number locale-number-quantity-amount">@if($recipePosition->amount == round($recipePosition->amount)){{ round($recipePosition->amount) }}@else{{ $recipePosition->amount }}@endif</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') }}
|
||||||
@endif
|
</div>
|
||||||
</td>
|
@endif
|
||||||
<td class="fit-content">
|
</td>
|
||||||
<a class="btn btn-sm btn-info recipe-pos-show-note-button @if(empty($recipePosition->note)) disabled @endif"
|
<td class="fit-content">
|
||||||
href="#"
|
<a class="btn btn-sm btn-info recipe-pos-show-note-button @if (empty($recipePosition->note)) disabled @endif"
|
||||||
data-toggle="tooltip"
|
href="#" data-toggle="tooltip" data-placement="top"
|
||||||
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>
|
</a>
|
||||||
</a>
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{{ $recipePosition->ingredient_group }}
|
||||||
{{ $recipePosition->ingredient_group }}
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
@endforeach
|
||||||
@endforeach
|
@endif
|
||||||
@endif
|
</tbody>
|
||||||
</tbody>
|
</table>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mt-5">
|
<div class="row mt-5">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<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"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-target="#related-links">
|
</button>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
</button>
|
<a id="recipe-include-add-button"
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
class="btn btn-outline-primary btn-sm m-1 mt-md-0 mb-md-0 float-right" href="#">
|
||||||
id="related-links">
|
{{ $__t('Add') }}
|
||||||
<a id="recipe-include-add-button"
|
</a>
|
||||||
class="btn btn-outline-primary btn-sm m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="#">
|
</div>
|
||||||
{{ $__t('Add') }}
|
{{-- TODO: DataTables: dynamic data: recipes_nestings_resolved --}}
|
||||||
</a>
|
<table id="recipes-includes-table" class="table table-sm table-striped nowrap w-100">
|
||||||
</div>
|
<thead>
|
||||||
</div>
|
<tr>
|
||||||
<table id="recipes-includes-table"
|
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
||||||
class="table table-sm table-striped nowrap w-100">
|
data-toggle="tooltip" data-toggle="tooltip" title="{{ $__t('Table options') }}"
|
||||||
<thead>
|
data-table-selector="#recipes-includes-table" href="#"><i
|
||||||
<tr>
|
class="fas fa-eye"></i></a>
|
||||||
<th class="border-right"><a class="text-muted change-table-columns-visibility-button"
|
</th>
|
||||||
data-toggle="tooltip"
|
<th>{{ $__t('Recipe') }}</th>
|
||||||
data-toggle="tooltip"
|
<th>{{ $__t('Servings') }}</th>
|
||||||
title="{{ $__t('Table options') }}"
|
</tr>
|
||||||
data-table-selector="#recipes-includes-table"
|
</thead>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<tbody class="d-none">
|
||||||
</th>
|
@if ($mode == 'edit')
|
||||||
<th>{{ $__t('Recipe') }}</th>
|
@foreach ($recipeNestings as $recipeNesting)
|
||||||
<th>{{ $__t('Servings') }}</th>
|
<tr>
|
||||||
</tr>
|
<td class="fit-content border-right">
|
||||||
</thead>
|
<a class="btn btn-sm btn-info recipe-include-edit-button" href="#"
|
||||||
<tbody class="d-none">
|
data-recipe-include-id="{{ $recipeNesting->id }}"
|
||||||
@if($mode == "edit")
|
data-recipe-included-recipe-id="{{ $recipeNesting->includes_recipe_id }}"
|
||||||
@foreach($recipeNestings as $recipeNesting)
|
data-recipe-included-recipe-servings="{{ $recipeNesting->servings }}">
|
||||||
<tr>
|
<i class="fas fa-edit"></i>
|
||||||
<td class="fit-content border-right">
|
</a>
|
||||||
<a class="btn btn-sm btn-info recipe-include-edit-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-included-recipe-id="{{ $recipeNesting->includes_recipe_id }}"
|
<i class="fas fa-trash"></i>
|
||||||
data-recipe-included-recipe-servings="{{ $recipeNesting->servings }}">
|
</a>
|
||||||
<i class="fas fa-edit"></i>
|
</td>
|
||||||
</a>
|
<td>
|
||||||
<a class="btn btn-sm btn-danger recipe-include-delete-button"
|
{{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }}
|
||||||
href="#"
|
</td>
|
||||||
data-recipe-include-id="{{ $recipeNesting->id }}"
|
<td>
|
||||||
data-recipe-include-name="{{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }}">
|
{{ $recipeNesting->servings }}
|
||||||
<i class="fas fa-trash"></i>
|
</td>
|
||||||
</a>
|
</tr>
|
||||||
</td>
|
@endforeach
|
||||||
<td>
|
@endif
|
||||||
{{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->includes_recipe_id)->name }}
|
</tbody>
|
||||||
</td>
|
</table>
|
||||||
<td>
|
</div>
|
||||||
{{ $recipeNesting->servings }}
|
</div>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
@endif
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mt-5">
|
<div class="row mt-5">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h4>
|
<h4>
|
||||||
{{ $__t('Picture') }}
|
{{ $__t('Picture') }}
|
||||||
</h4>
|
</h4>
|
||||||
<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"
|
<label id="recipe-picture-label"
|
||||||
id="recipe-picture"
|
class="custom-file-label @if (empty($recipe->picture_file_name)) d-none @endif"
|
||||||
accept="image/*">
|
for="recipe-picture">
|
||||||
<label id="recipe-picture-label"
|
{{ $recipe->picture_file_name }}
|
||||||
class="custom-file-label @if(empty($recipe->picture_file_name)) d-none @endif"
|
</label>
|
||||||
for="recipe-picture">
|
<label id="recipe-picture-label-none"
|
||||||
{{ $recipe->picture_file_name }}
|
class="custom-file-label @if (!empty($recipe->picture_file_name)) d-none @endif"
|
||||||
</label>
|
for="recipe-picture">
|
||||||
<label id="recipe-picture-label-none"
|
{{ $__t('No file selected') }}
|
||||||
class="custom-file-label @if(!empty($recipe->picture_file_name)) d-none @endif"
|
</label>
|
||||||
for="recipe-picture">
|
</div>
|
||||||
{{ $__t('No file selected') }}
|
<div class="input-group-append">
|
||||||
</label>
|
<span class="input-group-text"><i class="fas fa-trash"
|
||||||
</div>
|
id="delete-current-recipe-picture-button"></i></span>
|
||||||
<div class="input-group-append">
|
</div>
|
||||||
<span class="input-group-text"><i class="fas fa-trash"
|
</div>
|
||||||
id="delete-current-recipe-picture-button"></i></span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@if (!empty($recipe->picture_file_name))
|
||||||
</div>
|
<img id="current-recipe-picture"
|
||||||
</div>
|
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))
|
class="img-fluid img-thumbnail mt-2 lazy mb-5">
|
||||||
<img id="current-recipe-picture"
|
<p id="delete-current-recipe-picture-on-save-hint"
|
||||||
data-src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture&best_fit_width=400') }}"
|
class="form-text text-muted font-italic d-none mb-5">
|
||||||
class="img-fluid img-thumbnail mt-2 lazy mb-5">
|
{{ $__t('The current picture will be deleted on save') }}</p>
|
||||||
<p id="delete-current-recipe-picture-on-save-hint"
|
@else
|
||||||
class="form-text text-muted font-italic d-none mb-5">{{ $__t('The current picture will be deleted on save') }}</p>
|
<p id="no-current-recipe-picture-hint" class="form-text text-muted font-italic mb-5">
|
||||||
@else
|
{{ $__t('No picture available') }}</p>
|
||||||
<p id="no-current-recipe-picture-hint"
|
@endif
|
||||||
class="form-text text-muted font-italic mb-5">{{ $__t('No picture available') }}</p>
|
</div>
|
||||||
@endif
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="title-related-links">
|
|
||||||
<h4>
|
|
||||||
<span class="ls-n1">{{ $__t('grocycode') }}</span>
|
|
||||||
<i class="fas fa-question-circle text-muted"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
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>
|
|
||||||
<p>
|
|
||||||
@if($mode == 'edit')
|
|
||||||
<img src="{{ $U('/recipe/' . $recipe->id . '/grocycode?size=60') }}"
|
|
||||||
class="float-lg-left">
|
|
||||||
@endif
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<a class="btn btn-outline-primary btn-sm"
|
|
||||||
href="{{ $U('/recipe/' . $recipe->id . '/grocycode?download=true') }}">{{ $__t('Download') }}</a>
|
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
|
||||||
<a class="btn btn-outline-primary btn-sm recipe-grocycode-label-print"
|
|
||||||
data-recipe-id="{{ $recipe->id }}"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Print on label printer') }}
|
|
||||||
</a>
|
|
||||||
@endif
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="title-related-links">
|
||||||
|
<h4>
|
||||||
|
<span class="ls-n1">{{ $__t('grocycode') }}</span>
|
||||||
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" 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>
|
||||||
|
<p>
|
||||||
|
@if ($mode == 'edit')
|
||||||
|
<img src="{{ $U('/recipe/' . $recipe->id . '/grocycode?size=60') }}"
|
||||||
|
class="float-lg-left">
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a class="btn btn-outline-primary btn-sm"
|
||||||
|
href="{{ $U('/recipe/' . $recipe->id . '/grocycode?download=true') }}">{{ $__t('Download') }}</a>
|
||||||
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
|
<a class="btn btn-outline-primary btn-sm recipe-grocycode-label-print"
|
||||||
|
data-recipe-id="{{ $recipe->id }}" href="#">
|
||||||
|
{{ $__t('Print on label printer') }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal fade"
|
</div>
|
||||||
id="recipe-include-editform-modal"
|
|
||||||
tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content text-center">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h4 id="recipe-include-editform-title"
|
|
||||||
class="modal-title w-100"></h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form id="recipe-include-form"
|
|
||||||
novalidate>
|
|
||||||
|
|
||||||
@include('components.recipepicker', array(
|
<div class="modal fade" id="recipe-include-editform-modal" tabindex="-1">
|
||||||
'recipes' => $recipes,
|
<div class="modal-dialog">
|
||||||
'isRequired' => true
|
<div class="modal-content text-center">
|
||||||
))
|
<div class="modal-header">
|
||||||
|
<h4 id="recipe-include-editform-title" class="modal-title w-100"></h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="recipe-include-form" novalidate>
|
||||||
|
|
||||||
@include('components.numberpicker', array(
|
@include('components.recipepicker', [
|
||||||
'id' => 'includes_servings',
|
'recipes' => $recipes,
|
||||||
'label' => 'Servings',
|
'isRequired' => true,
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
])
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
|
||||||
'value' => '1',
|
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
|
||||||
))
|
|
||||||
|
|
||||||
</form>
|
@include('components.numberpicker', [
|
||||||
</div>
|
'id' => 'includes_servings',
|
||||||
<div class="modal-footer">
|
'label' => 'Servings',
|
||||||
<button type="button"
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
class="btn btn-secondary"
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
'value' => '1',
|
||||||
<button id="save-recipe-include-button"
|
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount',
|
||||||
data-dismiss="modal"
|
])
|
||||||
class="btn btn-success">{{ $__t('Save') }}</button>
|
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Cancel') }}</button>
|
||||||
|
<button id="save-recipe-include-button" data-dismiss="modal"
|
||||||
|
class="btn btn-success">{{ $__t('Save') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,8 @@
|
||||||
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'
|
||||||
))
|
))
|
||||||
|
|
||||||
<div class="form-group mb-2 @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
|
<div class="form-group mb-2 @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
|
||||||
|
|
@ -66,9 +66,9 @@
|
||||||
@php if($mode == 'edit') { $value = $recipePos->amount; } else { $value = 1; } @endphp
|
@php if($mode == 'edit') { $value = $recipePos->amount; } else { $value = 1; } @endphp
|
||||||
@php if($mode == 'edit') { $initialQuId = $recipePos->qu_id; } else { $initialQuId = ''; } @endphp
|
@php if($mode == 'edit') { $initialQuId = $recipePos->qu_id; } else { $initialQuId = ''; } @endphp
|
||||||
@include('components.productamountpicker', array(
|
@include('components.productamountpicker', array(
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'initialQuId' => $initialQuId,
|
'initialQuId' => $initialQuId,
|
||||||
'additionalGroupCssClasses' => 'mb-2'
|
'additionalGroupCssClasses' => 'mb-2'
|
||||||
))
|
))
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
@ -116,15 +116,15 @@
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
|
||||||
@php if($mode == 'edit') { $value = $recipePos->price_factor; } else { $value = 1; } @endphp
|
@php if($mode == 'edit') { $value = $recipePos->price_factor; } else { $value = 1; } @endphp
|
||||||
@include('components.numberpicker', array(
|
@include('components.numberpicker', array(
|
||||||
'id' => 'price_factor',
|
'id' => 'price_factor',
|
||||||
'label' => 'Price factor',
|
'label' => 'Price factor',
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
'decimals' => $userSettings['stock_decimal_places_amounts'],
|
||||||
'value' => '',
|
'value' => '',
|
||||||
'hint' => $__t('The resulting price of this ingredient will be multiplied by this factor'),
|
'hint' => $__t('The resulting price of this ingredient will be multiplied by this factor'),
|
||||||
'isRequired' => true,
|
'isRequired' => true,
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
'additionalCssClasses' => 'locale-number-input locale-number-quantity-amount'
|
||||||
))
|
))
|
||||||
@else
|
@else
|
||||||
<input type="hidden"
|
<input type="hidden"
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,427 +5,433 @@
|
||||||
@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>
|
||||||
@endif
|
@endif
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<button class="btn btn-primary responsive-button d-md-none mt-2 order-1 order-md-3 show-as-dialog-link"
|
<button class="btn btn-primary responsive-button d-md-none mt-2 order-1 order-md-3 show-as-dialog-link"
|
||||||
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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
@if (GROCY_FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS)
|
||||||
</button>
|
<div class="my-auto float-right">
|
||||||
</div>
|
{{-- TODO: Select2: dynamic data: shopping_lists --}}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
<select class="custom-control custom-select custom-select-sm" id="selected-shopping-list">
|
||||||
id="related-links">
|
@foreach ($shoppingLists as $shoppingList)
|
||||||
@if(GROCY_FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS)
|
<option @if ($shoppingList->id == $selectedShoppingListId) selected="selected" @endif
|
||||||
<div class="my-auto float-right">
|
value="{{ $shoppingList->id }}">{{ $shoppingList->name }}</option>
|
||||||
<select class="custom-control custom-select custom-select-sm"
|
@endforeach
|
||||||
id="selected-shopping-list">
|
</select>
|
||||||
@foreach($shoppingLists as $shoppingList)
|
</div>
|
||||||
<option @if($shoppingList->id == $selectedShoppingListId) selected="selected" @endif value="{{ $shoppingList->id }}">{{ $shoppingList->name }}</option>
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
@endforeach
|
href="{{ $U('/shoppinglist/new?embedded') }}">
|
||||||
</select>
|
{{ $__t('New shopping list') }}
|
||||||
</div>
|
</a>
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
href="{{ $U('/shoppinglist/new?embedded') }}">
|
href="{{ $U('/shoppinglist/' . $selectedShoppingListId . '?embedded') }}">
|
||||||
{{ $__t('New shopping list') }}
|
{{ $__t('Edit shopping list') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
<a id="delete-selected-shopping-list"
|
||||||
href="{{ $U('/shoppinglist/' . $selectedShoppingListId . '?embedded') }}">
|
class="btn btn-outline-danger responsive-button m-1 mt-md-0 mb-md-0 float-right @if ($selectedShoppingListId == 1) disabled @endif"
|
||||||
{{ $__t('Edit shopping list') }}
|
href="#">
|
||||||
</a>
|
{{ $__t('Delete shopping list') }}
|
||||||
<a id="delete-selected-shopping-list"
|
</a>
|
||||||
class="btn btn-outline-danger responsive-button m-1 mt-md-0 mb-md-0 float-right @if($selectedShoppingListId == 1) disabled @endif"
|
@else
|
||||||
href="#">
|
<input type="hidden" name="selected-shopping-list" id="selected-shopping-list" value="1">
|
||||||
{{ $__t('Delete shopping list') }}
|
@endif
|
||||||
</a>
|
<a id="print-shopping-list-button"
|
||||||
@else
|
class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right" href="#">
|
||||||
<input type="hidden"
|
{{ $__t('Print') }}
|
||||||
name="selected-shopping-list"
|
</a>
|
||||||
id="selected-shopping-list"
|
</div>
|
||||||
value="1">
|
</div>
|
||||||
@endif
|
<div id="filter-container" class="border-top border-bottom my-2 py-1">
|
||||||
<a id="print-shopping-list-button"
|
<div id="table-filter-row" data-status-filter="belowminstockamount"
|
||||||
class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
class="collapse normal-message status-filter-message responsive-button @if (!GROCY_FEATURE_FLAG_STOCK) d-none @else d-md-inline-block @endif">
|
||||||
href="#">
|
<span class="d-block d-md-none">{{ count($missingProducts) }} <i
|
||||||
{{ $__t('Print') }}
|
class="fas fa-exclamation-circle"></i></span><span
|
||||||
</a>
|
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>
|
</div>
|
||||||
</div>
|
<div id="related-links" class="float-right mt-1 collapse d-md-block">
|
||||||
<div id="filter-container"
|
<a class="btn btn-primary responsive-button btn-sm mb-1 show-as-dialog-link d-none d-md-inline-block"
|
||||||
class="border-top border-bottom my-2 py-1">
|
href="{{ $U('/shoppinglistitem/new?embedded&list=' . $selectedShoppingListId) }}">
|
||||||
<div id="table-filter-row"
|
{{ $__t('Add item') }}
|
||||||
data-status-filter="belowminstockamount"
|
</a>
|
||||||
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>
|
<a id="clear-shopping-list"
|
||||||
<div id="related-links"
|
class="btn btn-outline-danger btn-sm mb-1 responsive-button @if ($listItems->count() == 0) disabled @endif"
|
||||||
class="float-right mt-1 collapse d-md-block">
|
href="#">
|
||||||
<a class="btn btn-primary responsive-button btn-sm mb-1 show-as-dialog-link d-none d-md-inline-block"
|
{{ $__t('Clear list') }}
|
||||||
href="{{ $U('/shoppinglistitem/new?embedded&list=' . $selectedShoppingListId) }}">
|
</a>
|
||||||
{{ $__t('Add item') }}
|
<a id="add-all-items-to-stock-button"
|
||||||
</a>
|
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
||||||
<a id="clear-shopping-list"
|
href="#">
|
||||||
class="btn btn-outline-danger btn-sm mb-1 responsive-button @if($listItems->count() == 0) disabled @endif"
|
{{ $__t('Add all list items to stock') }}
|
||||||
href="#">
|
</a>
|
||||||
{{ $__t('Clear list') }}
|
<a id="add-products-below-min-stock-amount"
|
||||||
</a>
|
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
||||||
<a id="add-all-items-to-stock-button"
|
href="#">
|
||||||
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
{{ $__t('Add products that are below defined min. stock amount') }}
|
||||||
href="#">
|
</a>
|
||||||
{{ $__t('Add all list items to stock') }}
|
<a id="add-overdue-expired-products"
|
||||||
</a>
|
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
||||||
<a id="add-products-below-min-stock-amount"
|
href="#">
|
||||||
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
{{ $__t('Add overdue/expired products') }}
|
||||||
href="#">
|
</a>
|
||||||
{{ $__t('Add products that are below defined min. stock amount') }}
|
</div>
|
||||||
</a>
|
</div>
|
||||||
<a id="add-overdue-expired-products"
|
</div>
|
||||||
class="btn btn-outline-primary btn-sm mb-1 responsive-button @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Add overdue/expired products') }}
|
|
||||||
</a>
|
|
||||||
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-4 col-lg-5">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
<div class="col-12 col-md-4 col-lg-5">
|
</div>
|
||||||
<div class="input-group">
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
<div class="input-group-prepend">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<option class="@if (!GROCY_FEATURE_FLAG_STOCK) d-none @endif" value="belowminstockamount">
|
||||||
</div>
|
{{ $__t('Below min. stock amount') }}</option>
|
||||||
<select class="custom-control custom-select"
|
<option value="xxDONExx">{{ $__t('Only done items') }}</option>
|
||||||
id="status-filter">
|
<option value="xxUNDONExx">{{ $__t('Only undone items') }}</option>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
</select>
|
||||||
<option class="@if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif"
|
</div>
|
||||||
value="belowminstockamount">{{ $__t('Below min. stock amount') }}</option>
|
</div>
|
||||||
<option value="xxDONExx">{{ $__t('Only done items') }}</option>
|
<div class="col">
|
||||||
<option value="xxUNDONExx">{{ $__t('Only undone items') }}</option>
|
<div class="float-right">
|
||||||
</select>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
</div>
|
</a>
|
||||||
<div class="col">
|
</div>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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" title="{{ $__t('Table options') }}"
|
||||||
data-toggle="tooltip"
|
data-table-selector="#shoppinglist-table" href="#"><i class="fas fa-eye"></i></a>
|
||||||
data-toggle="tooltip"
|
</th>
|
||||||
title="{{ $__t('Table options') }}"
|
<th class="allow-grouping">{{ $__t('Product') }} / <em>{{ $__t('Note') }}</em></th>
|
||||||
data-table-selector="#shoppinglist-table"
|
<th>{{ $__t('Amount') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th class="allow-grouping">{{ $__t('Product group') }}</th>
|
||||||
</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product') }} / <em>{{ $__t('Note') }}</em></th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price (Unit)') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price (Total)') }}
|
||||||
<th class="allow-grouping">{{ $__t('Product group') }}</th>
|
</th>
|
||||||
<th class="d-none">Hidden status</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price (Unit)') }}</th>
|
{{ $__t('Default store') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price (Total)') }}</th>
|
<th>{{ $__t('Barcodes') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif allow-grouping">{{ $__t('Default store') }}</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 }}"
|
title="{{ $__t('Mark this item as done') }}">
|
||||||
data-toggle="tooltip"
|
<i class="fas fa-check"></i>
|
||||||
data-placement="right"
|
</a>
|
||||||
title="{{ $__t('Mark this item as done') }}">
|
<a class="btn btn-sm btn-info show-as-dialog-link"
|
||||||
<i class="fas fa-check"></i>
|
href="{{ $U('/shoppinglistitem/' . $listItem->id . '?embedded&list=' . $selectedShoppingListId) }}"
|
||||||
</a>
|
data-toggle="tooltip" data-placement="right" title="{{ $__t('Edit this item') }}">
|
||||||
<a class="btn btn-sm btn-info show-as-dialog-link"
|
<i class="fas fa-edit"></i>
|
||||||
href="{{ $U('/shoppinglistitem/' . $listItem->id . '?embedded&list=' . $selectedShoppingListId ) }}"
|
</a>
|
||||||
data-toggle="tooltip"
|
<a class="btn btn-sm btn-danger shoppinglist-delete-button" href="#"
|
||||||
data-placement="right"
|
data-shoppinglist-id="{{ $listItem->id }}" data-toggle="tooltip"
|
||||||
title="{{ $__t('Edit this item') }}">
|
data-placement="right" title="{{ $__t('Delete this item') }}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-sm btn-danger shoppinglist-delete-button"
|
<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="#"
|
href="{{ $U('/purchase?embedded&flow=shoppinglistitemtostock&product=') }}{{ $listItem->product_id }}&amount={{ $listItem->amount }}&listitemid={{ $listItem->id }}&quId={{ $listItem->qu_id }}"
|
||||||
data-shoppinglist-id="{{ $listItem->id }}"
|
@if (!empty($listItem->product_id)) data-toggle="tooltip" title="{{ $__t('Add this item to stock') }}" @endif>
|
||||||
data-toggle="tooltip"
|
<i class="fas fa-box"></i>
|
||||||
data-placement="right"
|
</a>
|
||||||
title="{{ $__t('Delete this item') }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td class="product-name-cell cursor-link" data-product-id="{{ $listItem->product_id }}">
|
||||||
</a>
|
@if (!empty($listItem->product_id))
|
||||||
<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"
|
{{ $listItem->product_name }}<br>
|
||||||
href="{{ $U('/purchase?embedded&flow=shoppinglistitemtostock&product=') }}{{ $listItem->product_id }}&amount={{ $listItem->amount }}&listitemid={{ $listItem->id }}&quId={{ $listItem->qu_id }}"
|
@endif
|
||||||
@if(!empty($listItem->product_id)) data-toggle="tooltip" title="{{ $__t('Add this item to stock') }}" @endif>
|
<em>
|
||||||
<i class="fas fa-box"></i>
|
{!! nl2br($listItem->note) !!}</em>
|
||||||
</a>
|
</td>
|
||||||
</td>
|
@if (!empty($listItem->product_id))
|
||||||
<td class="product-name-cell cursor-link"
|
@php
|
||||||
data-product-id="{{ $listItem->product_id }}">
|
$listItem->amount_origin_qu = $listItem->amount;
|
||||||
@if(!empty($listItem->product_id)) {{ $listItem->product_name }}<br>@endif<em>{!! nl2br($listItem->note) !!}</em>
|
$product = FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id);
|
||||||
</td>
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
||||||
@if(!empty($listItem->product_id))
|
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
||||||
@php
|
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $listItem->qu_id);
|
||||||
$listItem->amount_origin_qu = $listItem->amount;
|
if ($productQuConversion) {
|
||||||
$product = FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id);
|
$listItem->amount = $listItem->amount * $productQuConversion->factor;
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
|
}
|
||||||
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
|
@endphp
|
||||||
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $listItem->qu_id);
|
@endif
|
||||||
if ($productQuConversion)
|
<td data-order={{ <td data-order=$listItem->amount }}>
|
||||||
{
|
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span>
|
||||||
$listItem->amount = $listItem->amount * $productQuConversion->factor;
|
@if (!empty($listItem->product_id))
|
||||||
}
|
{{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}
|
||||||
@endphp
|
@endif
|
||||||
@endif
|
</td>
|
||||||
<td data-order={{
|
<td>
|
||||||
$listItem->amount }}>
|
@if (!empty($listItem->product_group_name))
|
||||||
<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
|
{{ $listItem->product_group_name }}
|
||||||
</td>
|
@else
|
||||||
<td>
|
<span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span>
|
||||||
@if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else <span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span> @endif
|
@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
|
||||||
</td>
|
@if ($listItem->done == 1)
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
xxDONExx
|
||||||
<span class="locale-number locale-number-currency">{{ $listItem->last_price_unit }}</span>
|
@else
|
||||||
</td>
|
xxUNDONExx
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
@endif
|
||||||
<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">
|
<span
|
||||||
{{ $listItem->default_shopping_location_name }}
|
class="locale-number locale-number-currency">{{ $listItem->last_price_unit }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
||||||
@foreach(explode(',', $listItem->product_barcodes) as $barcode)
|
<span
|
||||||
@if(!empty($barcode))
|
class="locale-number locale-number-currency">{{ $listItem->last_price_total }}</span>
|
||||||
<img class="barcode img-fluid pr-2"
|
</td>
|
||||||
data-barcode="{{ $barcode }}">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
||||||
@endif
|
{{ $listItem->default_shopping_location_name }}
|
||||||
@endforeach
|
</td>
|
||||||
</td>
|
<td>
|
||||||
|
@foreach (explode(',', $listItem->product_barcodes) as $barcode)
|
||||||
|
@if (!empty($barcode))
|
||||||
|
<img class="barcode img-fluid pr-2" data-barcode="{{ $barcode }}">
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</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',
|
||||||
'userfields' => $productUserfields,
|
$listItem->id
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($productUserfieldValues, 'object_id', $listItem->product_id)
|
),
|
||||||
))
|
])
|
||||||
|
@include('components.userfields_tbody', [
|
||||||
|
'userfields' => $productUserfields,
|
||||||
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
|
$productUserfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$listItem->product_id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</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>
|
name="description">{{ FindObjectInArrayByPropertyValue($shoppingLists, 'id', $selectedShoppingListId)->description }}</textarea>
|
||||||
<a id="clear-description-button"
|
</div>
|
||||||
class="btn btn-danger btn-sm ml-1 mb-2"
|
</div>
|
||||||
href="#">{{ $__t('Clear') }}</a>
|
</div>
|
||||||
<textarea class="form-control wysiwyg-editor"
|
|
||||||
id="description"
|
|
||||||
name="description">{{ FindObjectInArrayByPropertyValue($shoppingLists, 'id', $selectedShoppingListId)->description }}</textarea>
|
|
||||||
</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"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-dialog">
|
<div class="modal-body">
|
||||||
<div class="modal-content text-center">
|
<iframe id="shopping-list-stock-add-workflow-purchase-form-frame" class="embed-responsive"
|
||||||
<div class="modal-body">
|
src=""></iframe>
|
||||||
<iframe id="shopping-list-stock-add-workflow-purchase-form-frame"
|
</div>
|
||||||
class="embed-responsive"
|
<div class="modal-footer">
|
||||||
src=""></iframe>
|
<span id="shopping-list-stock-add-workflow-purchase-item-count" class="d-none mr-auto"></span>
|
||||||
</div>
|
<button id="shopping-list-stock-add-workflow-skip-button" type="button"
|
||||||
<div class="modal-footer">
|
class="btn btn-primary">{{ $__t('Skip') }}</button>
|
||||||
<span id="shopping-list-stock-add-workflow-purchase-item-count"
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
class="d-none mr-auto"></span>
|
</div>
|
||||||
<button id="shopping-list-stock-add-workflow-skip-button"
|
</div>
|
||||||
type="button"
|
</div>
|
||||||
class="btn btn-primary">{{ $__t('Skip') }}</button>
|
</div>
|
||||||
<button type="button"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
|
||||||
</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>
|
@endif
|
||||||
@endif
|
<h6 class="text-center mb-4">
|
||||||
<h6 class="text-center mb-4">
|
{{ $__t('Time of printing') }}:
|
||||||
{{ $__t('Time of printing') }}:
|
<span class="d-inline print-timestamp"></span>
|
||||||
<span class="d-inline print-timestamp"></span>
|
</h6>
|
||||||
</h6>
|
</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>
|
{{-- TODO: DataTables: dynamic data: uihelper_shopping_list --}}
|
||||||
<table id="shopping-list-print-shadow-table"
|
<table id="shopping-list-print-shadow-table" class="table table-sm table-striped nowrap">
|
||||||
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))
|
||||||
</td>
|
{{ $listItem->product_name }}<br>
|
||||||
<td>
|
@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
|
<em>
|
||||||
</td>
|
{!! nl2br($listItem->note) !!}</em>
|
||||||
<td>
|
</td>
|
||||||
@if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else <span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span> @endif
|
<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
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@if (!empty($listItem->product_group_name))
|
||||||
|
{{ $listItem->product_group_name }}
|
||||||
|
@else
|
||||||
|
<span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span>
|
||||||
|
@endif
|
||||||
|
</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',
|
||||||
'userfields' => $productUserfields,
|
$listItem->id
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($productUserfieldValues, 'object_id', $listItem->product_id)
|
),
|
||||||
))
|
])
|
||||||
|
@include('components.userfields_tbody', [
|
||||||
|
'userfields' => $productUserfields,
|
||||||
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
|
$productUserfieldValues,
|
||||||
|
'object_id',
|
||||||
|
$listItem->product_id
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</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))
|
||||||
</div><br>
|
{{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}
|
||||||
@endforeach
|
@endif
|
||||||
</div>
|
@if (!empty($listItem->product_id))
|
||||||
<div class="w-75 pt-3">
|
{{ $listItem->product_name }}<br>
|
||||||
<div>
|
@endif
|
||||||
<h5>{{ $__t('Notes') }}</h5>
|
<em>{!! nl2br($listItem->note) !!}</em>
|
||||||
<p id="description-for-print"></p>
|
</div><br>
|
||||||
</div>
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="w-75 pt-3">
|
||||||
<div class="modal fade"
|
<div>
|
||||||
id="shoppinglist-productcard-modal"
|
<h5>{{ $__t('Notes') }}</h5>
|
||||||
tabindex="-1">
|
<p id="description-for-print"></p>
|
||||||
<div class="modal-dialog">
|
</div>
|
||||||
<div class="modal-content text-center">
|
</div>
|
||||||
<div class="modal-body">
|
</div>
|
||||||
@include('components.productcard')
|
<div class="modal fade" id="shoppinglist-productcard-modal" tabindex="-1">
|
||||||
</div>
|
<div class="modal-dialog">
|
||||||
<div class="modal-footer">
|
<div class="modal-content text-center">
|
||||||
<button type="button"
|
<div class="modal-body">
|
||||||
class="btn btn-secondary"
|
@include('components.productcard')
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
</div>
|
||||||
</div>
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
</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>
|
||||||
&&
|
@endforeach
|
||||||
$shoppingList->id == $listItem->shopping_list_id) selected="selected" @endif value="{{ $shoppingList->id }}">{{ $shoppingList->name }}</option>
|
</select>
|
||||||
@endforeach
|
</div>
|
||||||
</select>
|
@else
|
||||||
</div>
|
<input type="hidden" id="shopping_list_id" name="shopping_list_id" value="1">
|
||||||
@else
|
@endif
|
||||||
<input type="hidden"
|
|
||||||
id="shopping_list_id"
|
|
||||||
name="shopping_list_id"
|
|
||||||
value="1">
|
|
||||||
@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;
|
||||||
'nextInputSelector' => '#amount',
|
} else {
|
||||||
'isRequired' => true,
|
$productId = '';
|
||||||
'prefillById' => $productId,
|
}
|
||||||
'validationMessage' => 'A product or a note is required'
|
@endphp
|
||||||
))
|
@include('components.productpicker', [
|
||||||
</div>
|
'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase',
|
||||||
|
'nextInputSelector' => '#amount',
|
||||||
|
'isRequired' => true,
|
||||||
|
'prefillById' => $productId,
|
||||||
|
'validationMessage' => 'A product or a note is required',
|
||||||
|
])
|
||||||
|
</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;
|
||||||
'value' => $value,
|
} else {
|
||||||
'initialQuId' => $initialQuId,
|
$value = 1;
|
||||||
'min' => $DEFAULT_MIN_AMOUNT,
|
}
|
||||||
'isRequired' => false
|
@endphp
|
||||||
))
|
@php
|
||||||
|
if ($mode == 'edit') {
|
||||||
|
$initialQuId = $listItem->qu_id;
|
||||||
|
} else {
|
||||||
|
$initialQuId = '';
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
@include('components.productamountpicker', [
|
||||||
|
'value' => $value,
|
||||||
|
'initialQuId' => $initialQuId,
|
||||||
|
'min' => $DEFAULT_MIN_AMOUNT,
|
||||||
|
'isRequired' => false,
|
||||||
|
])
|
||||||
|
|
||||||
<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,122 +5,109 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
</button>
|
href="{{ $U('/shoppinglocation/new?embedded') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary 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 show-as-dialog-link"
|
href="{{ $U('/userfields?entity=shopping_locations') }}">
|
||||||
href="{{ $U('/shoppinglocation/new?embedded') }}">
|
{{ $__t('Configure userfields') }}
|
||||||
{{ $__t('Add') }}
|
</a>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=shopping_locations') }}">
|
</div>
|
||||||
{{ $__t('Configure userfields') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#shoppinglocations-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Description') }}</th>
|
||||||
</th>
|
|
||||||
<th>{{ $__t('Name') }}</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" href="#"
|
||||||
<a class="btn btn-danger btn-sm shoppinglocation-delete-button"
|
data-shoppinglocation-id="{{ $shoppinglocation->id }}"
|
||||||
href="#"
|
data-shoppinglocation-name="{{ $shoppinglocation->name }}" data-toggle="tooltip"
|
||||||
data-shoppinglocation-id="{{ $shoppinglocation->id }}"
|
title="{{ $__t('Delete this item') }}">
|
||||||
data-shoppinglocation-name="{{ $shoppinglocation->name }}"
|
<i class="fas fa-trash"></i>
|
||||||
data-toggle="tooltip"
|
</a>
|
||||||
title="{{ $__t('Delete this item') }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td>
|
||||||
</a>
|
{{ $shoppinglocation->name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $shoppinglocation->name }}
|
{{ $shoppinglocation->description }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
{{ $shoppinglocation->description }}
|
|
||||||
</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,303 +4,273 @@
|
||||||
@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-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
</div>
|
||||||
</button>
|
</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', [
|
||||||
@include('components.productpicker', array(
|
'productsQuery' => 'query%5B%5D=active%3D1&order=name%3Acollate%20nocase',
|
||||||
'products' => $products,
|
'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" class="btn btn-sm btn-outline-info" href="#">
|
||||||
<a id="clear-filter-button"
|
{{ $__t('Clear filter') }}
|
||||||
class="btn btn-sm btn-outline-info"
|
</a>
|
||||||
href="#">
|
</div>
|
||||||
{{ $__t('Clear filter') }}
|
</div>
|
||||||
</a>
|
</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') }}"
|
</th>
|
||||||
data-table-selector="#stockentries-table"
|
<th class="d-none">Hidden product_id</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<!-- This must be in the first column for searching -->
|
||||||
</th>
|
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
||||||
<th class="d-none">Hidden product_id</th> <!-- This must be in the first column for searching -->
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif allow-grouping">{{ $__t('Due date') }}
|
||||||
<th>{{ $__t('Amount') }}</th>
|
</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_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}
|
||||||
<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_PRICE_TRACKING) d-none @endif allow-grouping">{{ $__t('Store') }}
|
||||||
<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">{{ $__t('Price') }}</th>
|
||||||
data-shadow-rowgroup-column="9">{{ $__t('Purchased date') }}</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-product-id="{{ $stockEntry->product_id }}"
|
||||||
data-placement="left"
|
data-stock-id="{{ $stockEntry->stock_id }}"
|
||||||
title="{{ $__t('Consume this stock entry') }}"
|
data-stockrow-id="{{ $stockEntry->id }}"
|
||||||
data-product-id="{{ $stockEntry->product_id }}"
|
data-location-id="{{ $stockEntry->location_id }}"
|
||||||
data-stock-id="{{ $stockEntry->stock_id }}"
|
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
||||||
data-stockrow-id="{{ $stockEntry->id }}"
|
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
||||||
data-location-id="{{ $stockEntry->location_id }}"
|
data-consume-amount="{{ $stockEntry->amount }}">
|
||||||
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
<i class="fas fa-utensils"></i>
|
||||||
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
</a>
|
||||||
data-consume-amount="{{ $stockEntry->amount }}">
|
@if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
||||||
<i class="fas fa-utensils"></i>
|
<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>
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
title="{{ $__t('Mark this stock entry as open') }}"
|
||||||
<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"
|
data-product-id="{{ $stockEntry->product_id }}"
|
||||||
href="#"
|
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
||||||
data-toggle="tooltip"
|
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
||||||
data-placement="left"
|
data-stock-id="{{ $stockEntry->stock_id }}"
|
||||||
title="{{ $__t('Mark this stock entry as open') }}"
|
data-stockrow-id="{{ $stockEntry->id }}">
|
||||||
data-product-id="{{ $stockEntry->product_id }}"
|
<i class="fas fa-box-open"></i>
|
||||||
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
</a>
|
||||||
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
@endif
|
||||||
data-stock-id="{{ $stockEntry->stock_id }}"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
data-stockrow-id="{{ $stockEntry->id }}">
|
href="{{ $U('/stockentry/' . $stockEntry->id . '?embedded') }}" data-toggle="tooltip"
|
||||||
<i class="fas fa-box-open"></i>
|
data-placement="left" title="{{ $__t('Edit stock entry') }}">
|
||||||
</a>
|
<i class="fas fa-edit"></i>
|
||||||
@endif
|
</a>
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<div class="dropdown d-inline-block">
|
||||||
href="{{ $U('/stockentry/' . $stockEntry->id . '?embedded') }}"
|
<button class="btn btn-sm btn-light text-secondary" type="button"
|
||||||
data-toggle="tooltip"
|
data-toggle="dropdown">
|
||||||
data-placement="left"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
title="{{ $__t('Edit stock entry') }}">
|
</button>
|
||||||
<i class="fas fa-edit"></i>
|
<div class="dropdown-menu">
|
||||||
</a>
|
@if (GROCY_FEATURE_FLAG_SHOPPINGLIST)
|
||||||
<div class="dropdown d-inline-block">
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
<button class="btn btn-sm btn-light text-secondary"
|
href="{{ $U('/shoppinglistitem/new?embedded&updateexistingproduct&product=' . $stockEntry->product_id) }}">
|
||||||
type="button"
|
<i class="fas fa-shopping-cart"></i> {{ $__t('Add to shopping list') }}
|
||||||
data-toggle="dropdown">
|
</a>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<div class="dropdown-divider"></div>
|
||||||
</button>
|
@endif
|
||||||
<div class="dropdown-menu">
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
@if(GROCY_FEATURE_FLAG_SHOPPINGLIST)
|
href="{{ $U('/purchase?embedded&product=' . $stockEntry->product_id) }}">
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<i class="fas fa-cart-plus"></i> {{ $__t('Purchase') }}
|
||||||
type="button"
|
</a>
|
||||||
href="{{ $U('/shoppinglistitem/new?embedded&updateexistingproduct&product=' . $stockEntry->product_id ) }}">
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
<i class="fas fa-shopping-cart"></i> {{ $__t('Add to shopping list') }}
|
href="{{ $U('/consume?embedded&product=' .$stockEntry->product_id .'&locationId=' .$stockEntry->location_id .'&stockId=' .$stockEntry->stock_id) }}">
|
||||||
</a>
|
<i class="fas fa-utensils"></i> {{ $__t('Consume') }}
|
||||||
<div class="dropdown-divider"></div>
|
</a>
|
||||||
@endif
|
@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('/purchase?embedded&product=' . $stockEntry->product_id ) }}">
|
<i class="fas fa-exchange-alt"></i> {{ $__t('Transfer') }}
|
||||||
<i class="fas fa-cart-plus"></i> {{ $__t('Purchase') }}
|
</a>
|
||||||
</a>
|
@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('/consume?embedded&product=' . $stockEntry->product_id . '&locationId=' . $stockEntry->location_id . '&stockId=' . $stockEntry->stock_id) }}">
|
<i class="fas fa-list"></i> {{ $__t('Inventory') }}
|
||||||
<i class="fas fa-utensils"></i> {{ $__t('Consume') }}
|
</a>
|
||||||
</a>
|
<div class="dropdown-divider"></div>
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
<a class="dropdown-item stock-consume-button stock-consume-button-spoiled"
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
type="button" href="#" data-product-id="{{ $stockEntry->product_id }}"
|
||||||
type="button"
|
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
||||||
href="{{ $U('/transfer?embedded&product=' . $stockEntry->product_id . '&locationId=' . $stockEntry->location_id . '&stockId=' . $stockEntry->stock_id) }}">
|
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits,'id',FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
||||||
<i class="fas fa-exchange-alt"></i> {{ $__t('Transfer') }}
|
data-stock-id="{{ $stockEntry->stock_id }}"
|
||||||
</a>
|
data-stockrow-id="{{ $stockEntry->id }}"
|
||||||
@endif
|
data-location-id="{{ $stockEntry->location_id }}" data-consume-amount="1">
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
{{ $__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) }}
|
||||||
type="button"
|
</a>
|
||||||
href="{{ $U('/inventory?embedded&product=' . $stockEntry->product_id ) }}">
|
@if (GROCY_FEATURE_FLAG_RECIPES)
|
||||||
<i class="fas fa-list"></i> {{ $__t('Inventory') }}
|
<a class="dropdown-item" type="button"
|
||||||
</a>
|
href="{{ $U('/recipes?search=') }}{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}">
|
||||||
<div class="dropdown-divider"></div>
|
{{ $__t('Search for recipes containing this product') }}
|
||||||
<a class="dropdown-item stock-consume-button stock-consume-button-spoiled"
|
</a>
|
||||||
type="button"
|
@endif
|
||||||
href="#"
|
<div class="dropdown-divider"></div>
|
||||||
data-product-id="{{ $stockEntry->product_id }}"
|
<a class="dropdown-item product-name-cell"
|
||||||
data-product-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}"
|
data-product-id="{{ $stockEntry->product_id }}" type="button" href="#">
|
||||||
data-product-qu-name="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name }}"
|
{{ $__t('Product overview') }}
|
||||||
data-stock-id="{{ $stockEntry->stock_id }}"
|
</a>
|
||||||
data-stockrow-id="{{ $stockEntry->id }}"
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
data-location-id="{{ $stockEntry->location_id }}"
|
href="{{ $U('/stockjournal?embedded&product=') }}{{ $stockEntry->product_id }}">
|
||||||
data-consume-amount="1">
|
{{ $__t('Stock journal') }}
|
||||||
{{ $__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>
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
@if(GROCY_FEATURE_FLAG_RECIPES)
|
href="{{ $U('/stockjournal/summary?embedded&product=') }}{{ $stockEntry->product_id }}">
|
||||||
<a class="dropdown-item"
|
{{ $__t('Stock journal summary') }}
|
||||||
type="button"
|
</a>
|
||||||
href="{{ $U('/recipes?search=') }}{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}">
|
<a class="dropdown-item link-return" type="button"
|
||||||
{{ $__t('Search for recipes containing this product') }}
|
data-href="{{ $U('/product/') }}{{ $stockEntry->product_id }}">
|
||||||
</a>
|
{{ $__t('Edit product') }}
|
||||||
@endif
|
</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item product-name-cell"
|
<a class="dropdown-item" type="button"
|
||||||
data-product-id="{{ $stockEntry->product_id }}"
|
href="{{ $U('/stockentry/' . $stockEntry->id . '/grocycode?download=true') }}">
|
||||||
type="button"
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Stock entry'))) !!}
|
||||||
href="#">
|
</a>
|
||||||
{{ $__t('Product overview') }}
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
</a>
|
<a class="dropdown-item stockentry-grocycode-label-print"
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
data-stock-id="{{ $stockEntry->id }}" type="button" href="#">
|
||||||
type="button"
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Stock entry'))) !!}
|
||||||
href="{{ $U('/stockjournal?embedded&product=') }}{{ $stockEntry->product_id }}">
|
</a>
|
||||||
{{ $__t('Stock journal') }}
|
@endif
|
||||||
</a>
|
<a class="dropdown-item stockentry-label-link" type="button" target="_blank"
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
href="{{ $U('/stockentry/' . $stockEntry->id . '/label') }}">
|
||||||
type="button"
|
{{ $__t('Open stock entry label in new window') }}
|
||||||
href="{{ $U('/stockjournal/summary?embedded&product=') }}{{ $stockEntry->product_id }}">
|
</a>
|
||||||
{{ $__t('Stock journal summary') }}
|
</div>
|
||||||
</a>
|
</div>
|
||||||
<a class="dropdown-item link-return"
|
</td>
|
||||||
type="button"
|
<td class="d-none" data-product-id="{{ $stockEntry->product_id }}">
|
||||||
data-href="{{ $U('/product/') }}{{ $stockEntry->product_id }}">
|
{{ $stockEntry->product_id }}
|
||||||
{{ $__t('Edit product') }}
|
</td>
|
||||||
</a>
|
<td class="product-name-cell cursor-link" data-product-id="{{ $stockEntry->product_id }}">
|
||||||
<div class="dropdown-divider"></div>
|
{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}
|
||||||
<a class="dropdown-item"
|
</td>
|
||||||
type="button"
|
<td data-order="{{ $stockEntry->amount }}">
|
||||||
href="{{ $U('/stockentry/' . $stockEntry->id . '/grocycode?download=true') }}">
|
<span id="stock-{{ $stockEntry->id }}-amount"
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Stock entry'))) !!}
|
class="locale-number locale-number-quantity-amount">{{ $stockEntry->amount }}</span>
|
||||||
</a>
|
<span
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
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>
|
||||||
<a class="dropdown-item stockentry-grocycode-label-print"
|
<span id="stock-{{ $stockEntry->id }}-opened-amount" class="small font-italic">
|
||||||
data-stock-id="{{ $stockEntry->id }}"
|
@if ($stockEntry->open == 1)
|
||||||
type="button"
|
{{ $__t('Opened') }}@endif
|
||||||
href="#">
|
</span>
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Stock entry'))) !!}
|
</td>
|
||||||
</a>
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
|
||||||
@endif
|
<span
|
||||||
<a class="dropdown-item stockentry-label-link"
|
id="stock-{{ $stockEntry->id }}-due-date">{{ $stockEntry->best_before_date }}</span>
|
||||||
type="button"
|
<time id="stock-{{ $stockEntry->id }}-due-date-timeago"
|
||||||
target="_blank"
|
class="timeago timeago-contextual"
|
||||||
href="{{ $U('/stockentry/' . $stockEntry->id . '/label') }}">
|
@if ($stockEntry->best_before_date != '') datetime="{{ $stockEntry->best_before_date }} 23:59:59" @endif></time>
|
||||||
{{ $__t('Open stock entry label in new window') }}
|
</td>
|
||||||
</a>
|
<td id="stock-{{ $stockEntry->id }}-location"
|
||||||
</div>
|
class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif"
|
||||||
</div>
|
data-location-id="{{ $stockEntry->location_id }}">
|
||||||
</td>
|
{{ FindObjectInArrayByPropertyValue($locations, 'id', $stockEntry->location_id)->name }}
|
||||||
<td class="d-none"
|
</td>
|
||||||
data-product-id="{{ $stockEntry->product_id }}">
|
<td id="stock-{{ $stockEntry->id }}-shopping-location"
|
||||||
{{ $stockEntry->product_id }}
|
class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif"
|
||||||
</td>
|
data-shopping-location-id="{{ $stockEntry->shopping_location_id }}">
|
||||||
<td class="product-name-cell cursor-link"
|
@if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id) !== null)
|
||||||
data-product-id="{{ $stockEntry->product_id }}">
|
{{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id)->name }}
|
||||||
{{ FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->name }}
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td data-order="{{ $stockEntry->amount }}">
|
<td id="stock-{{ $stockEntry->id }}-price"
|
||||||
<span id="stock-{{ $stockEntry->id }}-amount"
|
class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif"
|
||||||
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-currency" data-price-id="{{ $stockEntry->price }}">
|
||||||
<span id="stock-{{ $stockEntry->id }}-opened-amount"
|
{{ $stockEntry->price }}
|
||||||
class="small font-italic">@if($stockEntry->open == 1){{ $__t('Opened') }}@endif</span>
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
|
<span
|
||||||
<span id="stock-{{ $stockEntry->id }}-due-date">{{ $stockEntry->best_before_date }}</span>
|
id="stock-{{ $stockEntry->id }}-purchased-date">{{ $stockEntry->purchased_date }}</span>
|
||||||
<time id="stock-{{ $stockEntry->id }}-due-date-timeago"
|
<time id="stock-{{ $stockEntry->id }}-purchased-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 (!empty($stockEntry->purchased_date)) datetime="{{ $stockEntry->purchased_date }} 23:59:59" @endif></time>
|
||||||
</td>
|
</td>
|
||||||
<td id="stock-{{ $stockEntry->id }}-location"
|
<td class="d-none">{{ $stockEntry->purchased_date }}</td>
|
||||||
class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif"
|
<td>
|
||||||
data-location-id="{{ $stockEntry->location_id }}">
|
<span>{{ $stockEntry->row_created_timestamp }}</span>
|
||||||
{{ FindObjectInArrayByPropertyValue($locations, 'id', $stockEntry->location_id)->name }}
|
<time class="timeago timeago-contextual"
|
||||||
</td>
|
datetime="{{ $stockEntry->row_created_timestamp }}"></time>
|
||||||
<td id="stock-{{ $stockEntry->id }}-shopping-location"
|
</td>
|
||||||
class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif"
|
|
||||||
data-shopping-location-id="{{ $stockEntry->shopping_location_id }}">
|
|
||||||
@if (FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id) !== null)
|
|
||||||
{{ FindObjectInArrayByPropertyValue($shoppinglocations, 'id', $stockEntry->shopping_location_id)->name }}
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
<td id="stock-{{ $stockEntry->id }}-price"
|
|
||||||
class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif"
|
|
||||||
class="locale-number locale-number-currency"
|
|
||||||
data-price-id="{{ $stockEntry->price }}">
|
|
||||||
{{ $stockEntry->price }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span id="stock-{{ $stockEntry->id }}-purchased-date">{{ $stockEntry->purchased_date }}</span>
|
|
||||||
<time id="stock-{{ $stockEntry->id }}-purchased-date-timeago"
|
|
||||||
class="timeago timeago-contextual"
|
|
||||||
@if(!empty($stockEntry->purchased_date)) datetime="{{ $stockEntry->purchased_date }} 23:59:59" @endif></time>
|
|
||||||
</td>
|
|
||||||
<td class="d-none">{{ $stockEntry->purchased_date }}</td>
|
|
||||||
<td>
|
|
||||||
<span>{{ $stockEntry->row_created_timestamp }}</span>
|
|
||||||
<time class="timeago timeago-contextual"
|
|
||||||
datetime="{{ $stockEntry->row_created_timestamp }}"></time>
|
|
||||||
</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"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-dialog">
|
<div class="modal-body">
|
||||||
<div class="modal-content text-center">
|
@include('components.productcard')
|
||||||
<div class="modal-body">
|
</div>
|
||||||
@include('components.productcard')
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
<div class="modal-footer">
|
</div>
|
||||||
<button type="button"
|
</div>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,198 +5,180 @@
|
||||||
@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-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3 hide-when-embedded" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3 hide-when-embedded"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
href="{{ $U('/stockjournal/summary') }}">
|
||||||
</div>
|
{{ $__t('Journal summary') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
</div>
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/stockjournal/summary') }}">
|
|
||||||
{{ $__t('Journal summary') }}
|
|
||||||
</a>
|
|
||||||
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
<select class="select2 custom-control custom-select" id="product-filter">
|
||||||
<div class="input-group-prepend">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product') }}</span>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<select class="custom-control custom-select"
|
</div>
|
||||||
id="product-filter">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<div class="input-group">
|
||||||
@foreach($products as $product)
|
<div class="input-group-prepend">
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
<span class="input-group-text"><i
|
||||||
@endforeach
|
class="fas fa-filter"></i> {{ $__t('Transaction type') }}</span>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
{{-- TODO: Select2: static data --}}
|
||||||
</div>
|
<select class="custom-control custom-select" id="transaction-type-filter">
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<div class="input-group">
|
@foreach ($transactionTypes as $transactionType)
|
||||||
<div class="input-group-prepend">
|
<option value="{{ $transactionType }}">{{ $__t($transactionType) }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Transaction type') }}</span>
|
@endforeach
|
||||||
</div>
|
</select>
|
||||||
<select class="custom-control custom-select"
|
</div>
|
||||||
id="transaction-type-filter">
|
</div>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
@foreach($transactionTypes as $transactionType)
|
<div class="input-group">
|
||||||
<option value="{{ $transactionType }}">{{ $__t($transactionType) }}</option>
|
<div class="input-group-prepend">
|
||||||
@endforeach
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Location') }}</span>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
</div>
|
<select class="custom-control custom-select" id="location-filter">
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<div class="input-group">
|
@foreach ($locations as $location)
|
||||||
<div class="input-group-prepend">
|
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Location') }}</span>
|
@endforeach
|
||||||
</div>
|
</select>
|
||||||
<select class="custom-control custom-select"
|
</div>
|
||||||
id="location-filter">
|
</div>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<div class="col-12 col-md-6 col-xl-2 mt-1">
|
||||||
@foreach($locations as $location)
|
<div class="input-group">
|
||||||
<option value="{{ $location->id }}">{{ $location->name }}</option>
|
<div class="input-group-prepend">
|
||||||
@endforeach
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('User') }}</span>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
{{-- TODO: Select2: dynamic data: users --}}
|
||||||
</div>
|
<select class="custom-control custom-select" id="user-filter">
|
||||||
<div class="col-12 col-md-6 col-xl-2 mt-1">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<div class="input-group">
|
@foreach ($users as $user)
|
||||||
<div class="input-group-prepend">
|
<option value="{{ $user->id }}">{{ $user->display_name }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('User') }}</span>
|
@endforeach
|
||||||
</div>
|
</select>
|
||||||
<select class="custom-control custom-select"
|
</div>
|
||||||
id="user-filter">
|
</div>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<div class="col-12 col-md-6 col-xl-3 mt-1">
|
||||||
@foreach($users as $user)
|
<div class="input-group">
|
||||||
<option value="{{ $user->id }}">{{ $user->display_name }}</option>
|
<div class="input-group-prepend">
|
||||||
@endforeach
|
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
<select class="custom-control custom-select" id="daterange-filter">
|
||||||
</div>
|
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
||||||
<div class="col-12 col-md-6 col-xl-3 mt-1">
|
<option value="6" selected>{{ $__n(6, '%s month', '%s months') }}</option>
|
||||||
<div class="input-group">
|
<option value="12">{{ $__n(1, '%s year', '%s years') }}</option>
|
||||||
<div class="input-group-prepend">
|
<option value="24">{{ $__n(2, '%s month', '%s years') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-clock"></i> {{ $__t('Date range') }}</span>
|
<option value="9999">{{ $__t('All') }}</option>
|
||||||
</div>
|
</select>
|
||||||
<select class="custom-control custom-select"
|
</div>
|
||||||
id="daterange-filter">
|
</div>
|
||||||
<option value="1">{{ $__n(1, '%s month', '%s months') }}</option>
|
<div class="col">
|
||||||
<option value="6"
|
<div class="float-right mt-1">
|
||||||
selected>{{ $__n(6, '%s month', '%s months') }}</option>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
<option value="12">{{ $__n(1, '%s year', '%s years') }}</option>
|
{{ $__t('Clear filter') }}
|
||||||
<option value="24">{{ $__n(2, '%s month', '%s years') }}</option>
|
</a>
|
||||||
<option value="9999">{{ $__t('All') }}</option>
|
</div>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div class="float-right mt-1">
|
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#stock-journal-table"
|
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Transaction time') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}
|
||||||
<th>{{ $__t('Transaction time') }}</th>
|
</th>
|
||||||
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif allow-grouping">{{ $__t('Location') }}</th>
|
</tr>
|
||||||
<th class="allow-grouping">{{ $__t('Done by') }}</th>
|
</thead>
|
||||||
</tr>
|
<tbody class="d-none">
|
||||||
</thead>
|
@foreach ($stockLog as $stockLogEntry)
|
||||||
<tbody class="d-none">
|
<tr id="stock-booking-{{ $stockLogEntry->id }}-row"
|
||||||
@foreach($stockLog as $stockLogEntry)
|
class="@if ($stockLogEntry->undone == 1) text-muted @endif stock-booking-correlation-{{ $stockLogEntry->correlation_id }}"
|
||||||
<tr id="stock-booking-{{ $stockLogEntry->id }}-row"
|
data-correlation-id="{{ $stockLogEntry->correlation_id }}">
|
||||||
class="@if($stockLogEntry->undone == 1) text-muted @endif stock-booking-correlation-{{ $stockLogEntry->correlation_id }}"
|
<td class="fit-content border-right">
|
||||||
data-correlation-id="{{ $stockLogEntry->correlation_id }}">
|
<a class="btn btn-secondary btn-xs undo-stock-booking-button @if ($stockLogEntry->undone == 1) disabled @endif"
|
||||||
<td class="fit-content border-right">
|
href="#" data-booking-id="{{ $stockLogEntry->id }}" data-toggle="tooltip"
|
||||||
<a class="btn btn-secondary btn-xs undo-stock-booking-button @if($stockLogEntry->undone == 1) disabled @endif"
|
data-placement="left" title="{{ $__t('Undo transaction') }}">
|
||||||
href="#"
|
<i class="fas fa-undo"></i>
|
||||||
data-booking-id="{{ $stockLogEntry->id }}"
|
</a>
|
||||||
data-toggle="tooltip"
|
</td>
|
||||||
data-placement="left"
|
<td>
|
||||||
title="{{ $__t('Undo transaction') }}">
|
<span
|
||||||
<i class="fas fa-undo"></i>
|
class="name-anchor @if ($stockLogEntry->undone == 1) text-strike-through @endif">{{ $stockLogEntry->product_name }}</span>
|
||||||
</a>
|
@if ($stockLogEntry->undone == 1)
|
||||||
</td>
|
<br>
|
||||||
<td>
|
{{ $__t('Undone on') . ' ' . $stockLogEntry->undone_timestamp }}
|
||||||
<span class="name-anchor @if($stockLogEntry->undone == 1) text-strike-through @endif">{{ $stockLogEntry->product_name }}</span>
|
<time class="timeago timeago-contextual"
|
||||||
@if($stockLogEntry->undone == 1)
|
datetime="{{ $stockLogEntry->undone_timestamp }}"></time>
|
||||||
<br>
|
@endif
|
||||||
{{ $__t('Undone on') . ' ' . $stockLogEntry->undone_timestamp }}
|
</td>
|
||||||
<time class="timeago timeago-contextual"
|
<td>
|
||||||
datetime="{{ $stockLogEntry->undone_timestamp }}"></time>
|
<span
|
||||||
@endif
|
class="locale-number locale-number-quantity-amount">{{ $stockLogEntry->amount }}</span>
|
||||||
</td>
|
{{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural, true) }}
|
||||||
<td>
|
</td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $stockLogEntry->amount }}</span> {{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural, true) }}
|
<td>
|
||||||
</td>
|
{{ $stockLogEntry->row_created_timestamp }}
|
||||||
<td>
|
<time class="timeago timeago-contextual"
|
||||||
{{ $stockLogEntry->row_created_timestamp }}
|
datetime="{{ $stockLogEntry->row_created_timestamp }}"></time>
|
||||||
<time class="timeago timeago-contextual"
|
</td>
|
||||||
datetime="{{ $stockLogEntry->row_created_timestamp }}"></time>
|
<td>
|
||||||
</td>
|
{{ $__t($stockLogEntry->transaction_type) }}
|
||||||
<td>
|
@if ($stockLogEntry->spoiled == 1)
|
||||||
{{ $__t($stockLogEntry->transaction_type) }}
|
<span class="font-italic text-muted">{{ $__t('Spoiled') }}</span>
|
||||||
@if ($stockLogEntry->spoiled == 1)
|
@endif
|
||||||
<span class="font-italic text-muted">{{ $__t('Spoiled') }}</span>
|
</td>
|
||||||
@endif
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
||||||
</td>
|
{{ $stockLogEntry->location_name }}
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) d-none @endif">
|
</td>
|
||||||
{{ $stockLogEntry->location_name }}
|
<td>
|
||||||
</td>
|
{{ $stockLogEntry->user_display_name }}
|
||||||
<td>
|
</td>
|
||||||
{{ $stockLogEntry->user_display_name }}
|
</tr>
|
||||||
</td>
|
@endforeach
|
||||||
</tr>
|
</tbody>
|
||||||
@endforeach
|
</table>
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,127 +5,117 @@
|
||||||
@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-target="#table-filter-row">
|
||||||
data-toggle="collapse"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
</div>
|
||||||
</button>
|
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
{{-- TODO: Select2: dynamic data: products --}}
|
||||||
<div class="input-group-prepend">
|
<select class="select2 custom-control custom-select" id="product-filter">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product') }}</span>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
</div>
|
</select>
|
||||||
<select class="custom-control custom-select"
|
</div>
|
||||||
id="product-filter">
|
</div>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
@foreach($products as $product)
|
<div class="input-group">
|
||||||
<option value="{{ $product->id }}">{{ $product->name }}</option>
|
<div class="input-group-prepend">
|
||||||
@endforeach
|
<span class="input-group-text"><i
|
||||||
</select>
|
class="fas fa-filter"></i> {{ $__t('Transaction type') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{-- TODO: Select2: static data --}}
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<select class="custom-control custom-select" id="transaction-type-filter">
|
||||||
<div class="input-group">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<div class="input-group-prepend">
|
@foreach ($transactionTypes as $transactionType)
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Transaction type') }}</span>
|
<option value="{{ $transactionType }}">{{ $__t($transactionType) }}</option>
|
||||||
</div>
|
@endforeach
|
||||||
<select class="custom-control custom-select"
|
</select>
|
||||||
id="transaction-type-filter">
|
</div>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
</div>
|
||||||
@foreach($transactionTypes as $transactionType)
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<option value="{{ $transactionType }}">{{ $__t($transactionType) }}</option>
|
<div class="input-group">
|
||||||
@endforeach
|
<div class="input-group-prepend">
|
||||||
</select>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('User') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{-- TODO: Select2: dynamic data: users --}}
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<select class="custom-control custom-select" id="user-filter">
|
||||||
<div class="input-group">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<div class="input-group-prepend">
|
@foreach ($users as $user)
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('User') }}</span>
|
<option value="{{ $user->id }}">{{ $user->display_name }}</option>
|
||||||
</div>
|
@endforeach
|
||||||
<select class="custom-control custom-select"
|
</select>
|
||||||
id="user-filter">
|
</div>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
</div>
|
||||||
@foreach($users as $user)
|
<div class="col">
|
||||||
<option value="{{ $user->id }}">{{ $user->display_name }}</option>
|
<div class="float-right mt-1">
|
||||||
@endforeach
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</select>
|
{{ $__t('Clear filter') }}
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
</div>
|
||||||
<div class="float-right mt-1">
|
</div>
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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"
|
</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
||||||
</th>
|
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product') }}</th>
|
<th class="allow-grouping">{{ $__t('User') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Transaction type') }}</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('User') }}</th>
|
</tr>
|
||||||
<th>{{ $__t('Amount') }}</th>
|
</thead>
|
||||||
</tr>
|
<tbody class="d-none">
|
||||||
</thead>
|
@foreach ($entries as $journalEntry)
|
||||||
<tbody class="d-none">
|
<tr>
|
||||||
@foreach($entries as $journalEntry)
|
<td class="fit-content border-right"></td>
|
||||||
<tr>
|
<td>
|
||||||
<td class="fit-content border-right"></td>
|
{{ $journalEntry->product_name }}
|
||||||
<td>
|
</td>
|
||||||
{{ $journalEntry->product_name }}
|
<td>
|
||||||
</td>
|
{{ $__t($journalEntry->transaction_type) }}
|
||||||
<td>
|
</td>
|
||||||
{{ $__t($journalEntry->transaction_type) }}
|
<td>
|
||||||
</td>
|
{{ $journalEntry->user_display_name }}
|
||||||
<td>
|
</td>
|
||||||
{{ $journalEntry->user_display_name }}
|
<td>
|
||||||
</td>
|
<span
|
||||||
<td>
|
class="locale-number locale-number-quantity-amount">{{ $journalEntry->amount }}</span>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $journalEntry->amount }}</span> {{ $__n($journalEntry->amount, $journalEntry->qu_name, $journalEntry->qu_name_plural, true) }}
|
{{ $__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,446 +5,438 @@
|
||||||
@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" type="button"
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3"
|
data-toggle="collapse" data-target="#related-links">
|
||||||
type="button"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-toggle="collapse"
|
</button>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
href="{{ $U('/stockjournal') }}">
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
{{ $__t('Journal') }}
|
||||||
id="related-links">
|
</a>
|
||||||
<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('/stockentries') }}">
|
||||||
{{ $__t('Journal') }}
|
{{ $__t('Stock entries') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
@if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
href="{{ $U('/stockentries') }}">
|
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
||||||
{{ $__t('Stock entries') }}
|
href="{{ $U('/locationcontentsheet') }}">
|
||||||
</a>
|
{{ $__t('Location Content Sheet') }}
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
</a>
|
||||||
<a class="btn btn-outline-dark responsive-button m-1 mt-md-0 mb-md-0 float-right"
|
@endif
|
||||||
href="{{ $U('/locationcontentsheet') }}">
|
</div>
|
||||||
{{ $__t('Location Content Sheet') }}
|
</div>
|
||||||
</a>
|
<div class="border-top border-bottom my-2 py-1">
|
||||||
@endif
|
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||||
</div>
|
<div id="info-expired-products" data-status-filter="expired"
|
||||||
</div>
|
class="error-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div class="border-top border-bottom my-2 py-1">
|
<div id="info-overdue-products" data-status-filter="overdue"
|
||||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
class="secondary-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div id="info-expired-products"
|
<div id="info-duesoon-products" data-next-x-days="{{ $nextXDays }}" data-status-filter="duesoon"
|
||||||
data-status-filter="expired"
|
class="warning-message status-filter-message responsive-button mr-2"></div>
|
||||||
class="error-message status-filter-message responsive-button mr-2"></div>
|
@endif
|
||||||
<div id="info-overdue-products"
|
<div id="info-missing-products" data-status-filter="belowminstockamount"
|
||||||
data-status-filter="overdue"
|
class="normal-message status-filter-message responsive-button"></div>
|
||||||
class="secondary-message status-filter-message responsive-button mr-2"></div>
|
<div class="float-right">
|
||||||
<div id="info-duesoon-products"
|
<a class="btn btn-sm btn-outline-info d-md-none mt-1" data-toggle="collapse" href="#table-filter-row"
|
||||||
data-next-x-days="{{ $nextXDays }}"
|
role="button">
|
||||||
data-status-filter="duesoon"
|
<i class="fas fa-filter"></i>
|
||||||
class="warning-message status-filter-message responsive-button mr-2"></div>
|
</a>
|
||||||
@endif
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info mt-1" href="#">
|
||||||
<div id="info-missing-products"
|
{{ $__t('Clear filter') }}
|
||||||
data-status-filter="belowminstockamount"
|
</a>
|
||||||
class="normal-message status-filter-message responsive-button"></div>
|
</div>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a class="btn btn-sm btn-outline-info d-md-none mt-1"
|
</div>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
href="#table-filter-row"
|
<div class="row collapse d-md-flex" id="table-filter-row">
|
||||||
role="button">
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
<i class="fas fa-filter"></i>
|
<div class="input-group">
|
||||||
</a>
|
<div class="input-group-prepend">
|
||||||
<a id="clear-filter-button"
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
class="btn btn-sm btn-outline-info mt-1"
|
</div>
|
||||||
href="#">
|
<input type="text" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
{{ $__t('Clear filter') }}
|
</div>
|
||||||
</a>
|
</div>
|
||||||
</div>
|
@if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
</div>
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
</div>
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
<div class="row collapse d-md-flex"
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Location') }}</span>
|
||||||
id="table-filter-row">
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
{{-- TODO: Select2: dynamic data: locations --}}
|
||||||
<div class="input-group">
|
<select class="custom-control custom-select" id="location-filter">
|
||||||
<div class="input-group-prepend">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
@foreach ($locations as $location)
|
||||||
</div>
|
<option value="{{ $location->name }}">{{ $location->name }}</option>
|
||||||
<input type="text"
|
@endforeach
|
||||||
id="search"
|
</select>
|
||||||
class="form-control"
|
</div>
|
||||||
placeholder="{{ $__t('Search') }}">
|
</div>
|
||||||
</div>
|
@endif
|
||||||
</div>
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
<div class="input-group">
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<div class="input-group-prepend">
|
||||||
<div class="input-group">
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product group') }}</span>
|
||||||
<div class="input-group-prepend">
|
</div>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Location') }}</span>
|
{{-- TODO: Select2: dynamic data: product_groups --}}
|
||||||
</div>
|
<select class="custom-control custom-select" id="product-group-filter">
|
||||||
<select class="custom-control custom-select"
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
id="location-filter">
|
@foreach ($productGroups as $productGroup)
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="{{ $productGroup->name }}">{{ $productGroup->name }}</option>
|
||||||
@foreach($locations as $location)
|
@endforeach
|
||||||
<option value="{{ $location->name }}">{{ $location->name }}</option>
|
</select>
|
||||||
@endforeach
|
</div>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
</div>
|
<div class="input-group">
|
||||||
@endif
|
<div class="input-group-prepend">
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
<div class="input-group">
|
</div>
|
||||||
<div class="input-group-prepend">
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Product group') }}</span>
|
<option class="bg-white" value="all">{{ $__t('All') }}</option>
|
||||||
</div>
|
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||||
<select class="custom-control custom-select"
|
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
||||||
id="product-group-filter">
|
<option value="overdue">{{ $__t('Overdue') }}</option>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
<option value="expired">{{ $__t('Expired') }}</option>
|
||||||
@foreach($productGroups as $productGroup)
|
@endif
|
||||||
<option value="{{ $productGroup->name }}">{{ $productGroup->name }}</option>
|
<option value="belowminstockamount">{{ $__t('Below min. stock amount') }}</option>
|
||||||
@endforeach
|
<option value="instockX">{{ $__t('In-stock products') }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
|
||||||
</div>
|
|
||||||
<select class="custom-control custom-select"
|
|
||||||
id="status-filter">
|
|
||||||
<option class="bg-white"
|
|
||||||
value="all">{{ $__t('All') }}</option>
|
|
||||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
|
||||||
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
|
||||||
<option value="overdue">{{ $__t('Overdue') }}</option>
|
|
||||||
<option value="expired">{{ $__t('Expired') }}</option>
|
|
||||||
@endif
|
|
||||||
<option value="belowminstockamount">{{ $__t('Below min. stock amount') }}</option>
|
|
||||||
<option value="instockX">{{ $__t('In-stock products') }}</option>
|
|
||||||
</select>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#stock-overview-table"
|
<th>{{ $__t('Product') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th class="allow-grouping">{{ $__t('Product group') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Amount') }}</th>
|
||||||
<th>{{ $__t('Product') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Value') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Product group') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif allow-grouping">
|
||||||
<th>{{ $__t('Amount') }}</th>
|
{{ $__t('Next due date') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Value') }}</th>
|
<th class="d-none">Hidden location</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 status</th>
|
||||||
<th class="d-none">Hidden location</th>
|
<th class="d-none">Hidden product group</th>
|
||||||
<th class="d-none">Hidden status</th>
|
<th>{{ $__t('Calories') }} ({{ $__t('Per stock quantity unit') }})</th>
|
||||||
<th class="d-none">Hidden product group</th>
|
<th>{{ $__t('Calories') }}</th>
|
||||||
<th>{{ $__t('Calories') }} ({{ $__t('Per stock quantity unit') }})</th>
|
<th class="allow-grouping">{{ $__t('Last purchased') }}</th>
|
||||||
<th>{{ $__t('Calories') }}</th>
|
<th class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Last purchased') }}</th>
|
<th class="allow-grouping">{{ $__t('Min. stock amount') }}</th>
|
||||||
<th class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">{{ $__t('Last price') }}</th>
|
<th>{{ $__t('Product description') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Min. stock amount') }}</th>
|
<th class="allow-grouping">{{ $__t('Parent product') }}</th>
|
||||||
<th>{{ $__t('Product description') }}</th>
|
<th class="allow-grouping">{{ $__t('Default location') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Parent product') }}</th>
|
<th>{{ $__t('Product picture') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Default location') }}</th>
|
<th>{{ $__t('Average price') }}</th>
|
||||||
<th>{{ $__t('Product picture') }}</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
|
||||||
<td class="fit-content border-right">
|
@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)
|
||||||
<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"
|
table-warning
|
||||||
href="#"
|
@elseif ($currentStockEntry->product_missing)
|
||||||
data-toggle="tooltip"
|
table-info @endif">
|
||||||
data-placement="left"
|
<td class="fit-content border-right">
|
||||||
title="{{ $__t('Consume %1$s of %2$s', floatval($currentStockEntry->quick_consume_amount) . ' ' . $currentStockEntry->qu_unit_name, $currentStockEntry->product_name) }}"
|
<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"
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
data-product-name="{{ $currentStockEntry->product_name }}"
|
title="{{ $__t('Consume %1$s of %2$s',floatval($currentStockEntry->quick_consume_amount) . ' ' . $currentStockEntry->qu_unit_name,$currentStockEntry->product_name) }}"
|
||||||
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
data-product-id="{{ $currentStockEntry->product_id }}"
|
||||||
data-consume-amount="{{ $currentStockEntry->quick_consume_amount }}">
|
data-product-name="{{ $currentStockEntry->product_name }}"
|
||||||
<i class="fas fa-utensils"></i> <span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
|
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
||||||
</a>
|
data-consume-amount="{{ $currentStockEntry->quick_consume_amount }}">
|
||||||
<a id="product-{{ $currentStockEntry->product_id }}-consume-all-button"
|
<i class="fas fa-utensils"></i> <span
|
||||||
class="permission-STOCK_CONSUME btn btn-danger btn-sm product-consume-button @if($currentStockEntry->amount_aggregated == 0) disabled @endif"
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</span>
|
||||||
href="#"
|
</a>
|
||||||
data-toggle="tooltip"
|
<a id="product-{{ $currentStockEntry->product_id }}-consume-all-button"
|
||||||
data-placement="right"
|
class="permission-STOCK_CONSUME btn btn-danger btn-sm product-consume-button @if ($currentStockEntry->amount_aggregated == 0) disabled @endif"
|
||||||
title="{{ $__t('Consume all %s which are currently in stock', $currentStockEntry->product_name) }}"
|
href="#" data-toggle="tooltip" data-placement="right"
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
title="{{ $__t('Consume all %s which are currently in stock', $currentStockEntry->product_name) }}"
|
||||||
data-product-name="{{ $currentStockEntry->product_name }}"
|
data-product-id="{{ $currentStockEntry->product_id }}"
|
||||||
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
data-product-name="{{ $currentStockEntry->product_name }}"
|
||||||
data-consume-amount="@if($currentStockEntry->enable_tare_weight_handling == 1){{$currentStockEntry->tare_weight}}@else{{$currentStockEntry->amount}}@endif"
|
data-product-qu-name="{{ $currentStockEntry->qu_unit_name }}"
|
||||||
data-original-total-stock-amount="{{$currentStockEntry->amount}}">
|
data-consume-amount="@if ($currentStockEntry->enable_tare_weight_handling == 1) {{ $currentStockEntry->tare_weight }}@else{{ $currentStockEntry->amount }} @endif"
|
||||||
<i class="fas fa-utensils"></i> {{ $__t('All') }}
|
data-original-total-stock-amount="{{ $currentStockEntry->amount }}">
|
||||||
</a>
|
<i class="fas fa-utensils"></i> {{ $__t('All') }}
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
</a>
|
||||||
<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"
|
@if (GROCY_FEATURE_FLAG_STOCK_PRODUCT_OPENED_TRACKING)
|
||||||
href="#"
|
<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"
|
||||||
data-toggle="tooltip"
|
href="#" data-toggle="tooltip" data-placement="left"
|
||||||
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) }}"
|
||||||
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
|
||||||
<i class="fas fa-box-open"></i> <span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->quick_consume_amount }}</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-icon"><i class="fas fa-shopping-cart"></i></span> <span class="dropdown-item-text">{{ $__t('Add to shopping list') }}</span>
|
<span
|
||||||
</a>
|
class="dropdown-item-text">{{ $__t('Add to shopping list') }}</span>
|
||||||
<div class="dropdown-divider"></div>
|
</a>
|
||||||
@endif
|
<div class="dropdown-divider"></div>
|
||||||
<a class="dropdown-item show-as-dialog-link permission-STOCK_PURCHASE"
|
@endif
|
||||||
type="button"
|
<a class="dropdown-item show-as-dialog-link permission-STOCK_PURCHASE" 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 class="dropdown-item-text">{{ $__t('Purchase') }}</span>
|
<span class="dropdown-item-icon"><i class="fas fa-cart-plus"></i></span> <span
|
||||||
</a>
|
class="dropdown-item-text">{{ $__t('Purchase') }}</span>
|
||||||
<a class="dropdown-item show-as-dialog-link permission-STOCK_CONSUME @if($currentStockEntry->amount_aggregated <= 0) disabled @endif"
|
</a>
|
||||||
type="button"
|
<a class="dropdown-item show-as-dialog-link permission-STOCK_CONSUME @if ($currentStockEntry->amount_aggregated <= 0) disabled @endif"
|
||||||
href="{{ $U('/consume?embedded&product=' . $currentStockEntry->product_id ) }}">
|
type="button"
|
||||||
<span class="dropdown-item-icon"><i class="fas fa-utensils"></i></span> <span class="dropdown-item-text">{{ $__t('Consume') }}</span>
|
href="{{ $U('/consume?embedded&product=' . $currentStockEntry->product_id) }}">
|
||||||
</a>
|
<span class="dropdown-item-icon"><i class="fas fa-utensils"></i></span> <span
|
||||||
@if(GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
class="dropdown-item-text">{{ $__t('Consume') }}</span>
|
||||||
<a class="dropdown-item show-as-dialog-link permission-STOCK_TRANSFER @if($currentStockEntry->amount <= 0) disabled @endif"
|
</a>
|
||||||
type="button"
|
@if (GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
|
||||||
href="{{ $U('/transfer?embedded&product=' . $currentStockEntry->product_id) }}">
|
<a class="dropdown-item show-as-dialog-link permission-STOCK_TRANSFER @if ($currentStockEntry->amount <= 0) disabled @endif"
|
||||||
<span class="dropdown-item-icon"><i class="fas fa-exchange-alt"></i></span> <span class="dropdown-item-text">{{ $__t('Transfer') }}</span>
|
type="button"
|
||||||
</a>
|
href="{{ $U('/transfer?embedded&product=' . $currentStockEntry->product_id) }}">
|
||||||
@endif
|
<span class="dropdown-item-icon"><i class="fas fa-exchange-alt"></i></span>
|
||||||
<a class="dropdown-item show-as-dialog-link permission-STOCK_INVENTORY"
|
<span class="dropdown-item-text">{{ $__t('Transfer') }}</span>
|
||||||
type="button"
|
</a>
|
||||||
href="{{ $U('/inventory?embedded&product=' . $currentStockEntry->product_id ) }}">
|
@endif
|
||||||
<span class="dropdown-item-icon"><i class="fas fa-list"></i></span> <span class="dropdown-item-text">{{ $__t('Inventory') }}</span>
|
<a class="dropdown-item show-as-dialog-link permission-STOCK_INVENTORY"
|
||||||
</a>
|
type="button"
|
||||||
@if(GROCY_FEATURE_FLAG_RECIPES)
|
href="{{ $U('/inventory?embedded&product=' . $currentStockEntry->product_id) }}">
|
||||||
<a class="dropdown-item"
|
<span class="dropdown-item-icon"><i class="fas fa-list"></i></span> <span
|
||||||
type="button"
|
class="dropdown-item-text">{{ $__t('Inventory') }}</span>
|
||||||
href="{{ $U('/recipes?search=') }}{{ $currentStockEntry->product_name }}">
|
</a>
|
||||||
<span class="dropdown-item-text">{{ $__t('Search for recipes containing this product') }}</span>
|
@if (GROCY_FEATURE_FLAG_RECIPES)
|
||||||
</a>
|
<a class="dropdown-item" type="button"
|
||||||
@endif
|
href="{{ $U('/recipes?search=') }}{{ $currentStockEntry->product_name }}">
|
||||||
<div class="dropdown-divider"></div>
|
<span
|
||||||
<a class="dropdown-item product-name-cell"
|
class="dropdown-item-text">{{ $__t('Search for recipes containing this product') }}</span>
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
</a>
|
||||||
type="button"
|
@endif
|
||||||
href="#">
|
<div class="dropdown-divider"></div>
|
||||||
<span class="dropdown-item-text">{{ $__t('Product overview') }}</span>
|
<a class="dropdown-item product-name-cell"
|
||||||
</a>
|
data-product-id="{{ $currentStockEntry->product_id }}" type="button"
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
href="#">
|
||||||
type="button"
|
<span class="dropdown-item-text">{{ $__t('Product overview') }}</span>
|
||||||
href="{{ $U('/stockentries?embedded&product=') }}{{ $currentStockEntry->product_id }}"
|
</a>
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}">
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
<span class="dropdown-item-text">{{ $__t('Stock entries') }}</span>
|
href="{{ $U('/stockentries?embedded&product=') }}{{ $currentStockEntry->product_id }}"
|
||||||
</a>
|
data-product-id="{{ $currentStockEntry->product_id }}">
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<span class="dropdown-item-text">{{ $__t('Stock entries') }}</span>
|
||||||
type="button"
|
</a>
|
||||||
href="{{ $U('/stockjournal?embedded&product=') }}{{ $currentStockEntry->product_id }}">
|
<a class="dropdown-item show-as-dialog-link" type="button"
|
||||||
<span class="dropdown-item-text">{{ $__t('Stock journal') }}</span>
|
href="{{ $U('/stockjournal?embedded&product=') }}{{ $currentStockEntry->product_id }}">
|
||||||
</a>
|
<span class="dropdown-item-text">{{ $__t('Stock journal') }}</span>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
</a>
|
||||||
type="button"
|
<a class="dropdown-item show-as-dialog-link" 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" type="button"
|
||||||
<a class="dropdown-item"
|
href="{{ $U('/product/' . $currentStockEntry->product_id . '/grocycode?download=true') }}">
|
||||||
type="button"
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Product'))) !!}
|
||||||
href="{{ $U('/product/' . $currentStockEntry->product_id . '/grocycode?download=true') }}">
|
</a>
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Download %s grocycode', $__t('Product'))) !!}
|
@if (GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
||||||
</a>
|
<a class="dropdown-item product-grocycode-label-print"
|
||||||
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER)
|
data-product-id="{{ $currentStockEntry->product_id }}" type="button"
|
||||||
<a class="dropdown-item product-grocycode-label-print"
|
href="#">
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}"
|
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Product'))) !!}
|
||||||
type="button"
|
</a>
|
||||||
href="#">
|
@endif
|
||||||
{!! str_replace('grocycode', '<span class="ls-n1">grocycode</span>', $__t('Print %s grocycode on label printer', $__t('Product'))) !!}
|
</div>
|
||||||
</a>
|
</div>
|
||||||
@endif
|
</td>
|
||||||
</div>
|
<td class="product-name-cell cursor-link"
|
||||||
</div>
|
data-product-id="{{ $currentStockEntry->product_id }}">
|
||||||
</td>
|
{{ $currentStockEntry->product_name }}
|
||||||
<td class="product-name-cell cursor-link"
|
<span class="d-none">{{ $currentStockEntry->product_barcodes }}</span>
|
||||||
data-product-id="{{ $currentStockEntry->product_id }}">
|
</td>
|
||||||
{{ $currentStockEntry->product_name }}
|
<td>
|
||||||
<span class="d-none">{{ $currentStockEntry->product_barcodes }}</span>
|
@if ($currentStockEntry->product_group_name !== null)
|
||||||
</td>
|
{{ $currentStockEntry->product_group_name }}@endif
|
||||||
<td>
|
</td>
|
||||||
@if($currentStockEntry->product_group_name !== null){{ $currentStockEntry->product_group_name }}@endif
|
<td data-order="{{ $currentStockEntry->amount }}">
|
||||||
</td>
|
<span id="product-{{ $currentStockEntry->product_id }}-amount"
|
||||||
<td data-order="{{ $currentStockEntry->amount }}">
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span>
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-amount"
|
<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>
|
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)
|
||||||
<span class="pl-1 text-secondary">
|
{{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif
|
||||||
<i class="fas fa-custom-sigma-sign"></i> <span id="product-{{ $currentStockEntry->product_id }}-amount-aggregated"
|
</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) }}
|
@if ($currentStockEntry->is_aggregated_amount == 1)
|
||||||
@if($currentStockEntry->amount_opened_aggregated > 0)<span id="product-{{ $currentStockEntry->product_id }}-opened-amount-aggregated"
|
<span class="pl-1 text-secondary">
|
||||||
class="small font-italic">{{ $__t('%s opened', $currentStockEntry->amount_opened_aggregated) }}</span>@endif
|
<i class="fas fa-custom-sigma-sign"></i> <span
|
||||||
</span>
|
id="product-{{ $currentStockEntry->product_id }}-amount-aggregated"
|
||||||
@endif
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount_aggregated }}</span>
|
||||||
@if(boolval($userSettings['show_icon_on_stock_overview_page_when_product_is_on_shopping_list']))
|
{{ $__n($currentStockEntry->amount_aggregated,$currentStockEntry->qu_unit_name,$currentStockEntry->qu_unit_name_plural,true) }}
|
||||||
@if($currentStockEntry->on_shopping_list)
|
@if ($currentStockEntry->amount_opened_aggregated > 0)<span
|
||||||
<span class="text-muted cursor-normal"
|
id="product-{{ $currentStockEntry->product_id }}-opened-amount-aggregated"
|
||||||
data-toggle="tooltip"
|
class="small font-italic">{{ $__t('%s opened', $currentStockEntry->amount_opened_aggregated) }}</span>
|
||||||
title="{{ $__t('This product is currently on a shopping list') }}">
|
@endif
|
||||||
<i class="fas fa-shopping-cart"></i>
|
</span>
|
||||||
</span>
|
@endif
|
||||||
@endif
|
@if (boolval($userSettings['show_icon_on_stock_overview_page_when_product_is_on_shopping_list']))
|
||||||
@endif
|
@if ($currentStockEntry->on_shopping_list)
|
||||||
</td>
|
<span class="text-muted cursor-normal" data-toggle="tooltip"
|
||||||
<td>
|
title="{{ $__t('This product is currently on a shopping list') }}">
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-value"
|
<i class="fas fa-shopping-cart"></i>
|
||||||
class="locale-number locale-number-currency">{{ $currentStockEntry->value }}</span>
|
</span>
|
||||||
</td>
|
@endif
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
|
@endif
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-next-due-date">{{ $currentStockEntry->best_before_date }}</span>
|
</td>
|
||||||
<time id="product-{{ $currentStockEntry->product_id }}-next-due-date-timeago"
|
<td>
|
||||||
class="timeago timeago-contextual"
|
<span id="product-{{ $currentStockEntry->product_id }}-value"
|
||||||
@if(!empty($currentStockEntry->best_before_date)) datetime="{{ $currentStockEntry->best_before_date }} 23:59:59" @endif></time>
|
class="locale-number locale-number-currency">{{ $currentStockEntry->value }}</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
|
||||||
@foreach(FindAllObjectsInArrayByPropertyValue($currentStockLocations, 'product_id', $currentStockEntry->product_id) as $locationsForProduct)
|
<span
|
||||||
xx{{ FindObjectInArrayByPropertyValue($locations, 'id', $locationsForProduct->location_id)->name }}xx
|
id="product-{{ $currentStockEntry->product_id }}-next-due-date">{{ $currentStockEntry->best_before_date }}</span>
|
||||||
@endforeach
|
<time id="product-{{ $currentStockEntry->product_id }}-next-due-date-timeago"
|
||||||
</td>
|
class="timeago timeago-contextual"
|
||||||
<td class="d-none">
|
@if (!empty($currentStockEntry->best_before_date)) datetime="{{ $currentStockEntry->best_before_date }} 23:59:59" @endif></time>
|
||||||
@if($currentStockEntry->best_before_date < date('Y-m-d
|
</td>
|
||||||
|
<td class="d-none">
|
||||||
|
@foreach (FindAllObjectsInArrayByPropertyValue($currentStockLocations, 'product_id', $currentStockEntry->product_id) as $locationsForProduct)
|
||||||
|
xx{{ FindObjectInArrayByPropertyValue($locations, 'id', $locationsForProduct->location_id)->name }}xx
|
||||||
|
@endforeach
|
||||||
|
</td>
|
||||||
|
<td class="d-none">
|
||||||
|
@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
|
</td>
|
||||||
@if ($currentStockEntry->product_missing) belowminstockamount @endif
|
<td class="d-none">
|
||||||
</td>
|
xx{{ $currentStockEntry->product_group_name }}xx
|
||||||
<td class="d-none">
|
</td>
|
||||||
xx{{ $currentStockEntry->product_group_name }}xx
|
<td>
|
||||||
</td>
|
<span
|
||||||
<td>
|
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
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->calories }}</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
|
||||||
</td>
|
class="locale-number locale-number-currency">{{ $currentStockEntry->last_price }}</span>
|
||||||
<td>
|
</td>
|
||||||
<span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->min_stock_amount }}</span>
|
<td>
|
||||||
</td>
|
<span
|
||||||
<td>
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->min_stock_amount }}</span>
|
||||||
{!! $currentStockEntry->product_description !!}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td class="product-name-cell cursor-link"
|
{!! $currentStockEntry->product_description !!}
|
||||||
data-product-id="{{ $currentStockEntry->parent_product_id }}">
|
</td>
|
||||||
{{ $currentStockEntry->parent_product_name }}
|
<td class="product-name-cell cursor-link"
|
||||||
</td>
|
data-product-id="{{ $currentStockEntry->parent_product_id }}">
|
||||||
<td>
|
{{ $currentStockEntry->parent_product_name }}
|
||||||
{{ $currentStockEntry->product_default_location_name }}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{{ $currentStockEntry->product_default_location_name }}
|
||||||
@if(!empty($currentStockEntry->product_picture_file_name))
|
</td>
|
||||||
<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') }}"
|
<td>
|
||||||
class="lazy">
|
@if (!empty($currentStockEntry->product_picture_file_name))
|
||||||
@endif
|
<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') }}"
|
||||||
</td>
|
class="lazy">
|
||||||
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
@endif
|
||||||
<span class="locale-number locale-number-currency">{{ $currentStockEntry->average_price }}</span>
|
</td>
|
||||||
</td>
|
<td class="@if (!GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING) d-none @endif">
|
||||||
|
<span
|
||||||
|
class="locale-number locale-number-currency">{{ $currentStockEntry->average_price }}</span>
|
||||||
|
</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"
|
<div class="modal-dialog">
|
||||||
tabindex="-1">
|
<div class="modal-content text-center">
|
||||||
<div class="modal-dialog">
|
<div class="modal-body">
|
||||||
<div class="modal-content text-center">
|
@include('components.productcard')
|
||||||
<div class="modal-body">
|
</div>
|
||||||
@include('components.productcard')
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ $__t('Close') }}</button>
|
||||||
<div class="modal-footer">
|
</div>
|
||||||
<button type="button"
|
</div>
|
||||||
class="btn btn-secondary"
|
</div>
|
||||||
data-dismiss="modal">{{ $__t('Close') }}</button>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,202 +5,189 @@
|
||||||
@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>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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"
|
for="product_presets_treat_opened_as_out_of_stock">
|
||||||
for="product_presets_treat_opened_as_out_of_stock">
|
{{ $__t('Treat opened as out of stock') }}
|
||||||
{{ $__t('Treat opened as out of stock') }}
|
</label>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@endif
|
||||||
@endif
|
</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"
|
for="show_icon_on_stock_overview_page_when_product_is_on_shopping_list">
|
||||||
for="show_icon_on_stock_overview_page_when_product_is_on_shopping_list">
|
{{ $__t('Show an icon if the product is already on the shopping list') }}
|
||||||
{{ $__t('Show an icon if the product is already on the shopping list') }}
|
</label>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
</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">
|
{{ $__t('Show purchased date on purchase and inventory page (otherwise the purchased date defaults to today)') }}
|
||||||
<label class="form-check-label custom-control-label"
|
</label>
|
||||||
for="show_purchased_date_on_purchase">
|
</div>
|
||||||
{{ $__t('Show purchased date on purchase and inventory page (otherwise the purchased date defaults to today)') }}
|
</div>
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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"
|
for="show_warning_on_purchase_when_due_date_is_earlier_than_next">
|
||||||
for="show_warning_on_purchase_when_due_date_is_earlier_than_next">
|
{{ $__t('Show a warning when the due date of the purchased product is earlier than the next due date in stock') }}
|
||||||
{{ $__t('Show a warning when the due date of the purchased product is earlier than the next due date in stock') }}
|
</label>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
</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"
|
for="stock_default_consume_amount_use_quick_consume_amount">
|
||||||
for="stock_default_consume_amount_use_quick_consume_amount">
|
{{ $__t('Use the products "Quick consume amount"') }}
|
||||||
{{ $__t('Use the products "Quick consume amount"') }}
|
</label>
|
||||||
</label>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<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">
|
{{ $__t('Add decimal separator automatically for price inputs') }}
|
||||||
<label class="form-check-label custom-control-label"
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-trigger="hover click"
|
||||||
for="stock_auto_decimal_separator_prices">
|
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>
|
||||||
{{ $__t('Add decimal separator automatically for price inputs') }}
|
</label>
|
||||||
<i class="fas fa-question-circle text-muted"
|
</div>
|
||||||
data-toggle="tooltip"
|
</div>
|
||||||
data-trigger="hover click"
|
@endif
|
||||||
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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@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,122 +5,108 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100" id="related-links">
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
||||||
</button>
|
href="{{ $U('/taskcategory/new?embedded') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary" href="{{ $U('/userfields?entity=task_categories') }}">
|
||||||
<a class="btn btn-primary responsive-button m-1 mt-md-0 mb-md-0 float-right show-as-dialog-link"
|
{{ $__t('Configure userfields') }}
|
||||||
href="{{ $U('/taskcategory/new?embedded') }}">
|
</a>
|
||||||
{{ $__t('Add') }}
|
</div>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=task_categories') }}">
|
</div>
|
||||||
{{ $__t('Configure userfields') }}
|
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#taskcategories-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Description') }}</th>
|
||||||
</th>
|
|
||||||
<th>{{ $__t('Name') }}</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" href="#"
|
||||||
<a class="btn btn-danger btn-sm task-category-delete-button"
|
data-category-id="{{ $taskCategory->id }}"
|
||||||
href="#"
|
data-category-name="{{ $taskCategory->name }}" data-toggle="tooltip"
|
||||||
data-category-id="{{ $taskCategory->id }}"
|
title="{{ $__t('Delete this item') }}">
|
||||||
data-category-name="{{ $taskCategory->name }}"
|
<i class="fas fa-trash"></i>
|
||||||
data-toggle="tooltip"
|
</a>
|
||||||
title="{{ $__t('Delete this item') }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td>
|
||||||
</a>
|
{{ $taskCategory->name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $taskCategory->name }}
|
{{ $taskCategory->description }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
{{ $taskCategory->description }}
|
|
||||||
</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,116 +1,109 @@
|
||||||
@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
|
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
|
||||||
id="name"
|
</div>
|
||||||
name="name"
|
|
||||||
value="@if($mode == 'edit'){{ $task->name }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('A name is required') }}</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
|
||||||
</div>
|
</textarea>
|
||||||
|
</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', [
|
||||||
@include('components.datetimepicker', array(
|
'id' => 'due_date',
|
||||||
'id' => 'due_date',
|
'label' => 'Due',
|
||||||
'label' => 'Due',
|
'format' => 'YYYY-MM-DD',
|
||||||
'format' => 'YYYY-MM-DD',
|
'initWithNow' => false,
|
||||||
'initWithNow' => false,
|
'initialValue' => $initialDueDate,
|
||||||
'initialValue' => $initialDueDate,
|
'limitEndToNow' => false,
|
||||||
'limitEndToNow' => false,
|
'limitStartToNow' => false,
|
||||||
'limitStartToNow' => false,
|
'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' && $taskCategory->id == $task->category_id) selected="selected" @endif
|
||||||
<option @if($mode=='edit'
|
value="{{ $taskCategory->id }}">{{ $taskCategory->name }}</option>
|
||||||
&&
|
@endforeach
|
||||||
$taskCategory->id == $task->category_id) selected="selected" @endif value="{{ $taskCategory->id }}">{{ $taskCategory->name }}</option>
|
</select>
|
||||||
@endforeach
|
</div>
|
||||||
</select>
|
|
||||||
</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', [
|
||||||
@include('components.userpicker', array(
|
'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
|
||||||
@endif
|
class="btn btn-primary save-task-button add-another">{{ $__t('Save & add another task') }}</button>
|
||||||
</form>
|
@endif
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,200 +5,178 @@
|
||||||
@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"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
data-target="#related-links">
|
</button>
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
||||||
</button>
|
id="related-links">
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
<a class="btn btn-primary responsive-button show-as-dialog-link" href="{{ $U('/task/new?embedded') }}">
|
||||||
id="related-links">
|
{{ $__t('Add') }}
|
||||||
<a class="btn btn-primary responsive-button show-as-dialog-link"
|
</a>
|
||||||
href="{{ $U('/task/new?embedded') }}">
|
</div>
|
||||||
{{ $__t('Add') }}
|
</div>
|
||||||
</a>
|
<div class="border-top border-bottom my-2 py-1">
|
||||||
</div>
|
<div id="info-overdue-tasks" data-status-filter="overdue"
|
||||||
</div>
|
class="error-message status-filter-message responsive-button mr-2"></div>
|
||||||
<div class="border-top border-bottom my-2 py-1">
|
<div id="info-due-today-tasks" data-status-filter="duetoday"
|
||||||
<div id="info-overdue-tasks"
|
class="normal-message status-filter-message responsive-button mr-2"></div>
|
||||||
data-status-filter="overdue"
|
<div id="info-due-soon-tasks" data-status-filter="duesoon" data-next-x-days="{{ $nextXDays }}"
|
||||||
class="error-message status-filter-message responsive-button mr-2"></div>
|
class="warning-message status-filter-message responsive-button @if ($nextXDays == 0) d-none @endif">
|
||||||
<div id="info-due-today-tasks"
|
</div>
|
||||||
data-status-filter="duetoday"
|
<div class="float-right">
|
||||||
class="normal-message status-filter-message responsive-button mr-2"></div>
|
<a class="btn btn-sm btn-outline-info d-md-none mt-1" data-toggle="collapse" href="#table-filter-row"
|
||||||
<div id="info-due-soon-tasks"
|
role="button">
|
||||||
data-status-filter="duesoon"
|
<i class="fas fa-filter"></i>
|
||||||
data-next-x-days="{{ $nextXDays }}"
|
</a>
|
||||||
class="warning-message status-filter-message responsive-button @if($nextXDays == 0) d-none @endif"></div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info mt-1" href="#">
|
||||||
<div class="float-right">
|
{{ $__t('Clear filter') }}
|
||||||
<a class="btn btn-sm btn-outline-info d-md-none mt-1"
|
</a>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
href="#table-filter-row"
|
</div>
|
||||||
role="button">
|
</div>
|
||||||
<i class="fas fa-filter"></i>
|
</div>
|
||||||
</a>
|
|
||||||
<a id="clear-filter-button"
|
|
||||||
class="btn btn-sm btn-outline-info mt-1"
|
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
<select class="custom-control custom-select" id="status-filter">
|
||||||
<div class="input-group-prepend">
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Status') }}</span>
|
<option value="overdue">{{ $__t('Overdue') }}</option>
|
||||||
</div>
|
<option value="duetoday">{{ $__t('Due today') }}</option>
|
||||||
<select class="custom-control custom-select"
|
@if ($nextXDays > 0)
|
||||||
id="status-filter">
|
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
@endif
|
||||||
<option value="overdue">{{ $__t('Overdue') }}</option>
|
</select>
|
||||||
<option value="duetoday">{{ $__t('Due today') }}</option>
|
</div>
|
||||||
@if($nextXDays > 0)
|
</div>
|
||||||
<option value="duesoon">{{ $__t('Due soon') }}</option>
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
@endif
|
<div class="form-check custom-control custom-checkbox">
|
||||||
</select>
|
<input class="form-check-input custom-control-input" type="checkbox" id="show-done-tasks">
|
||||||
</div>
|
<label class="form-check-label custom-control-label" for="show-done-tasks">
|
||||||
</div>
|
{{ $__t('Show done tasks') }}
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</label>
|
||||||
<div class="form-check custom-control custom-checkbox">
|
</div>
|
||||||
<input class="form-check-input custom-control-input"
|
</div>
|
||||||
type="checkbox"
|
</div>
|
||||||
id="show-done-tasks">
|
|
||||||
<label class="form-check-label custom-control-label"
|
|
||||||
for="show-done-tasks">
|
|
||||||
{{ $__t('Show done tasks') }}
|
|
||||||
</label>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#tasks-table"
|
<th>{{ $__t('Task') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th class="allow-grouping">{{ $__t('Due') }}</th>
|
||||||
</th>
|
<th class="allow-grouping" data-shadow-rowgroup-column="6">{{ $__t('Category') }}</th>
|
||||||
<th>{{ $__t('Task') }}</th>
|
<th class="allow-grouping">{{ $__t('Assigned to') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Due') }}</th>
|
<th class="d-none">Hidden status</th>
|
||||||
<th class="allow-grouping"
|
<th class="d-none">Hidden category_id</th>
|
||||||
data-shadow-rowgroup-column="6">{{ $__t('Category') }}</th>
|
|
||||||
<th class="allow-grouping">{{ $__t('Assigned to') }}</th>
|
|
||||||
<th class="d-none">Hidden status</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"
|
<i class="fas fa-check"></i>
|
||||||
title="{{ $__t('Mark task as completed') }}"
|
</a>
|
||||||
data-task-id="{{ $task->id }}"
|
@else
|
||||||
data-task-name="{{ $task->name }}">
|
<a class="btn btn-secondary btn-sm undo-task-button" href="#" data-toggle="tooltip"
|
||||||
<i class="fas fa-check"></i>
|
data-placement="left" title="{{ $__t('Undo task', $task->name) }}"
|
||||||
</a>
|
data-task-id="{{ $task->id }}" data-task-name="{{ $task->name }}">
|
||||||
@else
|
<i class="fas fa-undo"></i>
|
||||||
<a class="btn btn-secondary btn-sm undo-task-button"
|
</a>
|
||||||
href="#"
|
@endif
|
||||||
data-toggle="tooltip"
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
data-placement="left"
|
href="{{ $U('/task/') }}{{ $task->id }}?embedded" data-toggle="tooltip"
|
||||||
title="{{ $__t('Undo task', $task->name) }}"
|
title="{{ $__t('Edit this item') }}">
|
||||||
data-task-id="{{ $task->id }}"
|
<i class="fas fa-edit"></i>
|
||||||
data-task-name="{{ $task->name }}">
|
</a>
|
||||||
<i class="fas fa-undo"></i>
|
<a class="btn btn-sm btn-danger delete-task-button" href="#"
|
||||||
</a>
|
data-task-id="{{ $task->id }}" data-task-name="{{ $task->name }}"
|
||||||
@endif
|
data-toggle="tooltip" title="{{ $__t('Delete this item') }}">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<i class="fas fa-trash"></i>
|
||||||
href="{{ $U('/task/') }}{{ $task->id }}?embedded"
|
</a>
|
||||||
data-toggle="tooltip"
|
</td>
|
||||||
title="{{ $__t('Edit this item') }}">
|
<td id="task-{{ $task->id }}-name"
|
||||||
<i class="fas fa-edit"></i>
|
class="@if ($task->done == 1) text-strike-through @endif">
|
||||||
</a>
|
{{ $task->name }}
|
||||||
<a class="btn btn-sm btn-danger delete-task-button"
|
</td>
|
||||||
href="#"
|
<td>
|
||||||
data-task-id="{{ $task->id }}"
|
<span>{{ $task->due_date }}</span>
|
||||||
data-task-name="{{ $task->name }}"
|
<time class="timeago timeago-contextual" datetime="{{ $task->due_date }}"></time>
|
||||||
data-toggle="tooltip"
|
</td>
|
||||||
title="{{ $__t('Delete this item') }}">
|
<td>
|
||||||
<i class="fas fa-trash"></i>
|
@if ($task->category_id != null)
|
||||||
</a>
|
<span>{{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }}</span>
|
||||||
</td>
|
@else
|
||||||
<td id="task-{{ $task->id }}-name"
|
<span class="font-italic font-weight-light">{{ $__t('Uncategorized') }}</span>
|
||||||
class="@if($task->done == 1) text-strike-through @endif">
|
@endif
|
||||||
{{ $task->name }}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
@if ($task->assigned_to_user_id != null)
|
||||||
<span>{{ $task->due_date }}</span>
|
<span>{{ GetUserDisplayName(FindObjectInArrayByPropertyValue($users, 'id', $task->assigned_to_user_id)) }}</span>
|
||||||
<time class="timeago timeago-contextual"
|
@endif
|
||||||
datetime="{{ $task->due_date }}"></time>
|
</td>
|
||||||
</td>
|
<td class="d-none">
|
||||||
<td>
|
{{ $task->due_type }}
|
||||||
@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->due_type == 'duetoday')
|
||||||
</td>
|
duesoon
|
||||||
<td>
|
@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">
|
@if ($task->category_id != null)
|
||||||
{{ $task->due_type }}
|
{{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }}
|
||||||
@if($task->due_type == 'duetoday')
|
@else
|
||||||
duesoon
|
{{ $__t('Uncategorized') }}
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none">
|
@include('components.userfields_tbody', [
|
||||||
@if($task->category_id != null) {{ FindObjectInArrayByPropertyValue($taskCategories, 'id', $task->category_id)->name }} @else {{ $__t('Uncategorized') }} @endif
|
'userfields' => $userfields,
|
||||||
</td>
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
@include('components.userfields_tbody',
|
$userfieldValues,
|
||||||
array( 'userfields'=> $userfields,
|
'object_id',
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $task->id)
|
$task->id
|
||||||
))
|
),
|
||||||
|
])
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,94 +5,88 @@
|
||||||
@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 }}" data-is-freezer="{{ $location->is_freezer }}">
|
||||||
<option value="{{ $location->id }}"
|
{{ $location->name }}</option>
|
||||||
data-is-freezer="{{ $location->is_freezer }}">{{ $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 }}" data-is-freezer="{{ $location->is_freezer }}">
|
||||||
<option value="{{ $location->id }}"
|
{{ $location->name }}</option>
|
||||||
data-is-freezer="{{ $location->is_freezer }}">{{ $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>
|
|
||||||
|
|
||||||
<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"
|
<label class="form-check-label custom-control-label"
|
||||||
name="use_specific_stock_entry"
|
for="use_specific_stock_entry">{{ $__t('Use a specific stock item') }}
|
||||||
value="1">
|
<i class="fas fa-question-circle text-muted" data-toggle="tooltip"
|
||||||
<label class="form-check-label custom-control-label"
|
data-trigger="hover click"
|
||||||
for="use_specific_stock_entry">{{ $__t('Use a specific stock item') }}
|
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>
|
||||||
<i class="fas fa-question-circle text-muted"
|
</label>
|
||||||
data-toggle="tooltip"
|
</div>
|
||||||
data-trigger="hover click"
|
<select disabled class="custom-control custom-select mt-2" id="specific_stock_entry"
|
||||||
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>
|
name="specific_stock_entry">
|
||||||
</label>
|
<option></option>
|
||||||
</div>
|
</select>
|
||||||
<select disabled
|
</div>
|
||||||
class="custom-control custom-select mt-2"
|
|
||||||
id="specific_stock_entry"
|
|
||||||
name="specific_stock_entry">
|
|
||||||
<option></option>
|
|
||||||
</select>
|
|
||||||
</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>
|
||||||
|
|
||||||
<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,111 +5,95 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
id="related-links">
|
||||||
</button>
|
<a class="btn btn-primary responsive-button show-as-dialog-link"
|
||||||
</div>
|
href="{{ $U('/userentity/new?embedded') }}">
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
{{ $__t('Add') }}
|
||||||
id="related-links">
|
</a>
|
||||||
<a class="btn btn-primary responsive-button show-as-dialog-link"
|
</div>
|
||||||
href="{{ $U('/userentity/new?embedded') }}">
|
</div>
|
||||||
{{ $__t('Add') }}
|
</div>
|
||||||
</a>
|
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#userentities-table"
|
<th>{{ $__t('Name') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Caption') }}</th>
|
||||||
</th>
|
</tr>
|
||||||
<th>{{ $__t('Name') }}</th>
|
</thead>
|
||||||
<th>{{ $__t('Caption') }}</th>
|
<tbody class="d-none">
|
||||||
</tr>
|
@foreach ($userentities as $userentity)
|
||||||
</thead>
|
<tr>
|
||||||
<tbody class="d-none">
|
<td class="fit-content border-right">
|
||||||
@foreach($userentities as $userentity)
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
<tr>
|
href="{{ $U('/userentity/') }}{{ $userentity->id }}?embedded" data-toggle="tooltip"
|
||||||
<td class="fit-content border-right">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<i class="fas fa-edit"></i>
|
||||||
href="{{ $U('/userentity/') }}{{ $userentity->id }}?embedded"
|
</a>
|
||||||
data-toggle="tooltip"
|
<a class="btn btn-danger btn-sm userentity-delete-button" href="#"
|
||||||
title="{{ $__t('Edit this item') }}">
|
data-userentity-id="{{ $userentity->id }}"
|
||||||
<i class="fas fa-edit"></i>
|
data-userentity-name="{{ $userentity->name }}" data-toggle="tooltip"
|
||||||
</a>
|
title="{{ $__t('Delete this item') }}">
|
||||||
<a class="btn btn-danger btn-sm userentity-delete-button"
|
<i class="fas fa-trash"></i>
|
||||||
href="#"
|
</a>
|
||||||
data-userentity-id="{{ $userentity->id }}"
|
<a class="btn btn-secondary btn-sm"
|
||||||
data-userentity-name="{{ $userentity->name }}"
|
href="{{ $U('/userfields?entity=userentity-') }}{{ $userentity->name }}">
|
||||||
data-toggle="tooltip"
|
<i class="fas fa-th-list"></i> {{ $__t('Configure fields') }}
|
||||||
title="{{ $__t('Delete this item') }}">
|
</a>
|
||||||
<i class="fas fa-trash"></i>
|
</td>
|
||||||
</a>
|
<td>
|
||||||
<a class="btn btn-secondary btn-sm"
|
{{ $userentity->name }}
|
||||||
href="{{ $U('/userfields?entity=userentity-') }}{{ $userentity->name }}">
|
</td>
|
||||||
<i class="fas fa-th-list"></i> {{ $__t('Configure fields') }}
|
<td>
|
||||||
</a>
|
{{ $userentity->caption }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
</tr>
|
||||||
{{ $userentity->name }}
|
@endforeach
|
||||||
</td>
|
</tbody>
|
||||||
<td>
|
</table>
|
||||||
{{ $userentity->caption }}
|
</div>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -1,153 +1,138 @@
|
||||||
@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"
|
<option></option>
|
||||||
name="entity">
|
@foreach ($entities as $entity)
|
||||||
<option></option>
|
<option @if ($mode == 'edit' && $userfield->entity == $entity) selected="selected" @endif
|
||||||
@foreach($entities as $entity)
|
value="{{ $entity }}">{{ $entity }}</option>
|
||||||
<option @if($mode=='edit'
|
@endforeach
|
||||||
&&
|
</select>
|
||||||
$userfield->entity == $entity) selected="selected" @endif value="{{ $entity }}">{{ $entity }}</option>
|
<div class="invalid-feedback">{{ $__t('A entity is required') }}</div>
|
||||||
@endforeach
|
</div>
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback">{{ $__t('A entity is required') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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"
|
title="{{ $__t('This is the internal field name, e. g. for the API') }}"></i>
|
||||||
data-trigger="hover click"
|
</label>
|
||||||
title="{{ $__t('This is the internal field name, e. g. for the API') }}"></i>
|
<input type="text" class="form-control" required pattern="^[a-zA-Z0-9]*$" id="name" name="name"
|
||||||
</label>
|
value="@if ($mode == 'edit') {{ $userfield->name }} @endif">
|
||||||
<input type="text"
|
<div class="invalid-feedback">{{ $__t('This is required and can only contain letters and numbers') }}
|
||||||
class="form-control"
|
</div>
|
||||||
required
|
</div>
|
||||||
pattern="^[a-zA-Z0-9]*$"
|
|
||||||
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 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"
|
title="{{ $__t('This is used to display the field on the frontend') }}"></i>
|
||||||
data-trigger="hover click"
|
</label>
|
||||||
title="{{ $__t('This is used to display the field on the frontend') }}"></i>
|
<input type="text" class="form-control" required id="caption" name="caption"
|
||||||
</label>
|
value="@if ($mode == 'edit') {{ $userfield->caption }} @endif">
|
||||||
<input type="text"
|
<div class="invalid-feedback">{{ $__t('A caption is required') }}</div>
|
||||||
class="form-control"
|
</div>
|
||||||
required
|
|
||||||
id="caption"
|
|
||||||
name="caption"
|
|
||||||
value="@if($mode == 'edit'){{ $userfield->caption }}@endif">
|
|
||||||
<div class="invalid-feedback">{{ $__t('A caption is required') }}</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)) {
|
||||||
'id' => 'sort_number',
|
$value = $userfield->sort_number;
|
||||||
'label' => 'Sort number',
|
} else {
|
||||||
'min' => 0,
|
$value = '';
|
||||||
'value' => $value,
|
}
|
||||||
'isRequired' => false,
|
@endphp
|
||||||
'hint' => $__t('Multiple Userfields will be ordered by that number on the input form')
|
@include('components.numberpicker', [
|
||||||
))
|
'id' => 'sort_number',
|
||||||
|
'label' => 'Sort number',
|
||||||
|
'min' => 0,
|
||||||
|
'value' => $value,
|
||||||
|
'isRequired' => false,
|
||||||
|
'hint' => $__t('Multiple Userfields will be ordered by that number on the input form'),
|
||||||
|
])
|
||||||
|
|
||||||
<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"
|
<option></option>
|
||||||
name="type">
|
@foreach ($userfieldTypes as $userfieldType)
|
||||||
<option></option>
|
<option @if ($mode == 'edit' && $userfield->type == $userfieldType) selected="selected" @endif
|
||||||
@foreach($userfieldTypes as $userfieldType)
|
value="{{ $userfieldType }}">{{ $__t($userfieldType) }}</option>
|
||||||
<option @if($mode=='edit'
|
@endforeach
|
||||||
&&
|
</select>
|
||||||
$userfield->type == $userfieldType) selected="selected" @endif value="{{ $userfieldType }}">{{ $__t($userfieldType) }}</option>
|
<div class="invalid-feedback">{{ $__t('A type is required') }}</div>
|
||||||
@endforeach
|
</div>
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback">{{ $__t('A type is required') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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
|
||||||
</div>
|
</textarea>
|
||||||
|
</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>
|
||||||
</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->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" data-toggle="tooltip"
|
||||||
<i class="fas fa-question-circle text-muted"
|
data-trigger="hover click"
|
||||||
data-toggle="tooltip"
|
title="{{ $__t('When enabled, then this field must be filled on the destination form') }}"></i>
|
||||||
data-trigger="hover click"
|
</label>
|
||||||
title="{{ $__t('When enabled, then this field must be filled on the destination form') }}"></i>
|
</div>
|
||||||
</label>
|
</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,134 +5,117 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
id="related-links">
|
||||||
</button>
|
<a id="new-userfield-button" class="btn btn-primary responsive-button show-as-dialog-link"
|
||||||
</div>
|
href="{{ $U('/userfield/new?embedded') }}">
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
{{ $__t('Add') }}
|
||||||
id="related-links">
|
</a>
|
||||||
<a id="new-userfield-button"
|
</div>
|
||||||
class="btn btn-primary responsive-button show-as-dialog-link"
|
</div>
|
||||||
href="{{ $U('/userfield/new?embedded') }}">
|
</div>
|
||||||
{{ $__t('Add') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col-12 col-md-6 col-xl-3">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="input-group">
|
||||||
</div>
|
<div class="input-group-prepend">
|
||||||
</div>
|
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Entity') }}</span>
|
||||||
<div class="col-12 col-md-6 col-xl-3">
|
</div>
|
||||||
<div class="input-group">
|
{{-- TODO: Select2: dynamic data: userfields --}}
|
||||||
<div class="input-group-prepend">
|
<select class="custom-control custom-select" id="entity-filter">
|
||||||
<span class="input-group-text"><i class="fas fa-filter"></i> {{ $__t('Entity') }}</span>
|
<option value="all">{{ $__t('All') }}</option>
|
||||||
</div>
|
@foreach ($entities as $entity)
|
||||||
<select class="custom-control custom-select"
|
<option value="{{ $entity }}">{{ $entity }}</option>
|
||||||
id="entity-filter">
|
@endforeach
|
||||||
<option value="all">{{ $__t('All') }}</option>
|
</select>
|
||||||
@foreach($entities as $entity)
|
</div>
|
||||||
<option value="{{ $entity }}">{{ $entity }}</option>
|
</div>
|
||||||
@endforeach
|
<div class="col">
|
||||||
</select>
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#userfields-table"
|
<th class="allow-grouping">{{ $__t('Entity') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('Name') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Caption') }}</th>
|
||||||
<th class="allow-grouping">{{ $__t('Entity') }}</th>
|
<th class="allow-grouping">{{ $__t('Type') }}</th>
|
||||||
<th>{{ $__t('Name') }}</th>
|
<th>{{ $__t('Sort number') }}</th>
|
||||||
<th>{{ $__t('Caption') }}</th>
|
</tr>
|
||||||
<th class="allow-grouping">{{ $__t('Type') }}</th>
|
</thead>
|
||||||
<th>{{ $__t('Sort number') }}</th>
|
<tbody class="d-none">
|
||||||
</tr>
|
@foreach ($userfields as $userfield)
|
||||||
</thead>
|
<tr>
|
||||||
<tbody class="d-none">
|
<td class="fit-content border-right">
|
||||||
@foreach($userfields as $userfield)
|
<a class="btn btn-info btn-sm show-as-dialog-link"
|
||||||
<tr>
|
href="{{ $U('/userfield/') }}{{ $userfield->id }}?embedded" data-toggle="tooltip"
|
||||||
<td class="fit-content border-right">
|
title="{{ $__t('Edit this item') }}">
|
||||||
<a class="btn btn-info btn-sm show-as-dialog-link"
|
<i class="fas fa-edit"></i>
|
||||||
href="{{ $U('/userfield/') }}{{ $userfield->id }}?embedded"
|
</a>
|
||||||
data-toggle="tooltip"
|
<a class="btn btn-danger btn-sm userfield-delete-button" href="#"
|
||||||
title="{{ $__t('Edit this item') }}">
|
data-userfield-id="{{ $userfield->id }}"
|
||||||
<i class="fas fa-edit"></i>
|
data-userfield-name="{{ $userfield->name }}" data-toggle="tooltip"
|
||||||
</a>
|
title="{{ $__t('Delete this item') }}">
|
||||||
<a class="btn btn-danger btn-sm userfield-delete-button"
|
<i class="fas fa-trash"></i>
|
||||||
href="#"
|
</a>
|
||||||
data-userfield-id="{{ $userfield->id }}"
|
</td>
|
||||||
data-userfield-name="{{ $userfield->name }}"
|
<td>
|
||||||
data-toggle="tooltip"
|
{{ $userfield->entity }}
|
||||||
title="{{ $__t('Delete this item') }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td>
|
||||||
</a>
|
{{ $userfield->name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $userfield->entity }}
|
{{ $userfield->caption }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $userfield->name }}
|
{{ $__t($userfield->type) }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $userfield->caption }}
|
{{ $userfield->sort_number }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
</tr>
|
||||||
{{ $__t($userfield->type) }}
|
@endforeach
|
||||||
</td>
|
</tbody>
|
||||||
<td>
|
</table>
|
||||||
{{ $userfield->sort_number }}
|
</div>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@stop
|
@stop
|
||||||
|
|
|
||||||
|
|
@ -5,112 +5,103 @@
|
||||||
@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">
|
||||||
@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 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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
id="related-links">
|
||||||
</button>
|
<a class="btn btn-primary responsive-button mr-1 show-as-dialog-link"
|
||||||
</div>
|
href="{{ $U('/userobject/' . $userentity->name . '/new?embedded') }}">
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
{{ $__t('Add') }}
|
||||||
id="related-links">
|
</a>
|
||||||
<a class="btn btn-primary responsive-button mr-1 show-as-dialog-link"
|
<a class="btn btn-outline-secondary d-print-none"
|
||||||
href="{{ $U('/userobject/' . $userentity->name . '/new?embedded') }}">
|
href="{{ $U('/userfields?entity=' . 'userentity-' . $userentity->name) }}">
|
||||||
{{ $__t('Add') }}
|
{{ $__t('Configure fields') }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-outline-secondary d-print-none"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=' . 'userentity-' . $userentity->name) }}">
|
</div>
|
||||||
{{ $__t('Configure fields') }}
|
</div>
|
||||||
</a>
|
</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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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" href="#"
|
||||||
<a class="btn btn-danger btn-sm userobject-delete-button"
|
data-userobject-id="{{ $userobject->id }}" data-toggle="tooltip"
|
||||||
href="#"
|
title="{{ $__t('Delete this item') }}">
|
||||||
data-userobject-id="{{ $userobject->id }}"
|
<i class="fas fa-trash"></i>
|
||||||
data-toggle="tooltip"
|
</a>
|
||||||
title="{{ $__t('Delete this item') }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</a>
|
|
||||||
</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,130 +5,114 @@
|
||||||
@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"
|
<i class="fas fa-filter"></i>
|
||||||
data-target="#table-filter-row">
|
</button>
|
||||||
<i class="fas fa-filter"></i>
|
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3" type="button"
|
||||||
</button>
|
data-toggle="collapse" data-target="#related-links">
|
||||||
<button class="btn btn-outline-dark d-md-none mt-2 order-1 order-md-3"
|
<i class="fas fa-ellipsis-v"></i>
|
||||||
type="button"
|
</button>
|
||||||
data-toggle="collapse"
|
</div>
|
||||||
data-target="#related-links">
|
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
||||||
<i class="fas fa-ellipsis-v"></i>
|
id="related-links">
|
||||||
</button>
|
<a class="btn btn-primary responsive-button" href="{{ $U('/user/new') }}">
|
||||||
</div>
|
{{ $__t('Add') }}
|
||||||
<div class="related-links collapse d-md-flex order-2 width-xs-sm-100 m-1 mt-md-0 mb-md-0 float-right"
|
</a>
|
||||||
id="related-links">
|
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
||||||
<a class="btn btn-primary responsive-button"
|
href="{{ $U('/userfields?entity=users') }}">
|
||||||
href="{{ $U('/user/new') }}">
|
{{ $__t('Configure userfields') }}
|
||||||
{{ $__t('Add') }}
|
</a>
|
||||||
</a>
|
</div>
|
||||||
<a class="btn btn-outline-secondary m-1 mt-md-0 mb-md-0 float-right"
|
</div>
|
||||||
href="{{ $U('/userfields?entity=users') }}">
|
</div>
|
||||||
{{ $__t('Configure userfields') }}
|
</div>
|
||||||
</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-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" id="search" class="form-control" placeholder="{{ $__t('Search') }}">
|
||||||
<input type="text"
|
</div>
|
||||||
id="search"
|
</div>
|
||||||
class="form-control"
|
<div class="col">
|
||||||
placeholder="{{ $__t('Search') }}">
|
<div class="float-right">
|
||||||
</div>
|
<a id="clear-filter-button" class="btn btn-sm btn-outline-info" href="#">
|
||||||
</div>
|
{{ $__t('Clear filter') }}
|
||||||
<div class="col">
|
</a>
|
||||||
<div class="float-right">
|
</div>
|
||||||
<a id="clear-filter-button"
|
</div>
|
||||||
class="btn btn-sm btn-outline-info"
|
</div>
|
||||||
href="#">
|
|
||||||
{{ $__t('Clear filter') }}
|
|
||||||
</a>
|
|
||||||
</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') }}"
|
</th>
|
||||||
data-table-selector="#users-table"
|
<th>{{ $__t('Username') }}</th>
|
||||||
href="#"><i class="fas fa-eye"></i></a>
|
<th>{{ $__t('First name') }}</th>
|
||||||
</th>
|
<th>{{ $__t('Last name') }}</th>
|
||||||
<th>{{ $__t('Username') }}</th>
|
|
||||||
<th>{{ $__t('First 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"
|
<i class="fas fa-edit"></i>
|
||||||
title="{{ $__t('Edit this item') }}">
|
</a>
|
||||||
<i class="fas fa-edit"></i>
|
<a class="btn btn-info btn-sm" href="{{ $U('/user/' . $user->id . '/permissions') }}"
|
||||||
</a>
|
data-toggle="tooltip" title="{{ $__t('Configure user permissions') }}">
|
||||||
<a class="btn btn-info btn-sm"
|
<i class="fas fa-lock"></i>
|
||||||
href="{{ $U('/user/' . $user->id . '/permissions') }}"
|
</a>
|
||||||
data-toggle="tooltip"
|
<a class="btn btn-danger btn-sm user-delete-button @if ($user->id == GROCY_USER_ID) disabled @endif"
|
||||||
title="{{ $__t('Configure user permissions') }}">
|
href="#" data-user-id="{{ $user->id }}"
|
||||||
<i class="fas fa-lock"></i>
|
data-user-username="{{ $user->username }}" data-toggle="tooltip"
|
||||||
</a>
|
title="{{ $__t('Delete this item') }}">
|
||||||
<a class="btn btn-danger btn-sm user-delete-button @if($user->id == GROCY_USER_ID) disabled @endif"
|
<i class="fas fa-trash"></i>
|
||||||
href="#"
|
</a>
|
||||||
data-user-id="{{ $user->id }}"
|
</td>
|
||||||
data-user-username="{{ $user->username }}"
|
<td>
|
||||||
data-toggle="tooltip"
|
{{ $user->username }}
|
||||||
title="{{ $__t('Delete this item') }}">
|
</td>
|
||||||
<i class="fas fa-trash"></i>
|
<td>
|
||||||
</a>
|
{{ $user->first_name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ $user->username }}
|
{{ $user->last_name }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
{{ $user->first_name }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ $user->last_name }}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
@include('components.userfields_tbody', array(
|
@include('components.userfields_tbody', [
|
||||||
'userfields' => $userfields,
|
'userfields' => $userfields,
|
||||||
'userfieldValues' => FindAllObjectsInArrayByPropertyValue($userfieldValues, 'object_id', $user->id)
|
'userfieldValues' => FindAllObjectsInArrayByPropertyValue(
|
||||||
))
|
$userfieldValues,
|
||||||
</tr>
|
'object_id',
|
||||||
@endforeach
|
$user->id
|
||||||
</tbody>
|
),
|
||||||
</table>
|
])
|
||||||
</div>
|
</tr>
|
||||||
</div>
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</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