mirror of
https://github.com/grocy/grocy.git
synced 2026-04-05 20:36:15 +02:00
Grocycode: Display in UI, make Images downloadable
This commit is contained in:
parent
aa4675589c
commit
866e64acc0
|
|
@ -172,6 +172,34 @@ class StockController extends BaseController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function ProductGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||||
|
{
|
||||||
|
$product = $this->getDatabase()->products($args['productId']);
|
||||||
|
|
||||||
|
$gc = new Grocycode(Grocycode::PRODUCT, $product->id);
|
||||||
|
$png = (new DatamatrixFactory())->setCode((string) $gc)->getDatamatrixPngData();
|
||||||
|
|
||||||
|
$isDownload = $request->getQueryParam('download', false);
|
||||||
|
|
||||||
|
if ($isDownload)
|
||||||
|
{
|
||||||
|
$response = $response->withHeader('Content-Type', 'application/octet-stream')
|
||||||
|
->withHeader('Content-Disposition', 'attachment; filename=grocycode.png')
|
||||||
|
->withHeader('Content-Length', strlen($png))
|
||||||
|
->withHeader('Cache-Control', 'no-cache')
|
||||||
|
->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$response = $response->withHeader('Content-Type', 'image/png')
|
||||||
|
->withHeader('Content-Length', strlen($png))
|
||||||
|
->withHeader('Cache-Control', 'no-cache')
|
||||||
|
->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');
|
||||||
|
}
|
||||||
|
$response->getBody()->write($png);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
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')
|
||||||
|
|
@ -436,11 +464,24 @@ class StockController extends BaseController
|
||||||
$gc = new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id]);
|
$gc = new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id]);
|
||||||
$png = (new DatamatrixFactory())->setCode((string) $gc)->getDatamatrixPngData();
|
$png = (new DatamatrixFactory())->setCode((string) $gc)->getDatamatrixPngData();
|
||||||
|
|
||||||
$response = $response->withHeader('Content-Type', 'image/png')
|
$isDownload = $request->getQueryParam('download', false);
|
||||||
|
|
||||||
|
if ($isDownload)
|
||||||
|
{
|
||||||
|
$response = $response->withHeader('Content-Type', 'application/octet-stream')
|
||||||
|
->withHeader('Content-Disposition', 'attachment; filename=grocycode.png')
|
||||||
->withHeader('Content-Length', strlen($png))
|
->withHeader('Content-Length', strlen($png))
|
||||||
->withHeader('Cache-Control', 'no-cache')
|
->withHeader('Cache-Control', 'no-cache')
|
||||||
->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');
|
->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');
|
||||||
$response->getBody()->write($png);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$response = $response->withHeader('Content-Type', 'image/png')
|
||||||
|
->withHeader('Content-Length', strlen($png))
|
||||||
|
->withHeader('Cache-Control', 'no-cache')
|
||||||
|
->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');
|
||||||
|
$response->getBody()->write($png);
|
||||||
|
}
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2374,3 +2374,18 @@ msgstr "Druckoptionen"
|
||||||
|
|
||||||
msgid "A product or a note is required"
|
msgid "A product or a note is required"
|
||||||
msgstr "Ein Produkt oder eine Notiz ist erforderlich"
|
msgstr "Ein Produkt oder eine Notiz ist erforderlich"
|
||||||
|
|
||||||
|
msgid "Grocycode"
|
||||||
|
msgstr "Grocycode"
|
||||||
|
|
||||||
|
msgid "Download"
|
||||||
|
msgstr "Herunterladen"
|
||||||
|
|
||||||
|
msgid "Download stock entry grocycode"
|
||||||
|
msgstr "Bestandseingrags-Grocycode herunterladen"
|
||||||
|
|
||||||
|
msgid "Download product grocycode"
|
||||||
|
msgstr "Produkt-Grocycode herunterladen"
|
||||||
|
|
||||||
|
msgid "Grocycode is a unique referer to this product in your grocy instance. Print it onto a label and scan it like any other barcode!"
|
||||||
|
msgstr "Grocycode ist eine eindeutige Referenz zu diesem Produkt in dieser Grocy-Instanz. Ausgedruckt kann es wie jeder andere Barcode gescannt werden!"
|
||||||
|
|
@ -2077,3 +2077,26 @@ msgstr ""
|
||||||
|
|
||||||
msgid "A product or a note is required"
|
msgid "A product or a note is required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Grocycode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Download"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Download stock entry grocycode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Download product grocycode"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"If enabled, the min. stock amount of sub products will be accumulated into this product, means the sub product will never be \"\n"
|
||||||
|
"\t\t\t\t\t\t\tmissing\",\n"
|
||||||
|
"\t\t\t\t\t\t\tonly\n"
|
||||||
|
"\t\t\t\t\t\t\tthis\n"
|
||||||
|
"\t\t\t\t\t\t\tproduct"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Grocycode is a unique referer to this product in your grocy instance. Print it onto a label and scan it like any other barcode!"
|
||||||
|
msgstr ""
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,10 @@ Grocy.Components.ProductCard.Refresh = function(productId)
|
||||||
}
|
}
|
||||||
$('#productcard-product-spoil-rate').text((parseFloat(productDetails.spoil_rate_percent) / 100).toLocaleString(undefined, { style: "percent" }));
|
$('#productcard-product-spoil-rate').text((parseFloat(productDetails.spoil_rate_percent) / 100).toLocaleString(undefined, { style: "percent" }));
|
||||||
|
|
||||||
|
// grocycode
|
||||||
|
$("#productcard-product-grocycode-image").attr("src", U('/product/' + productDetails.product.id + '/grocycode'));
|
||||||
|
$("#productcard-product-grocycode-image-link").attr("href", U('/product/' + productDetails.product.id + '/grocycode?download=true'));
|
||||||
|
|
||||||
if (productDetails.is_aggregated_amount == 1)
|
if (productDetails.is_aggregated_amount == 1)
|
||||||
{
|
{
|
||||||
$('#productcard-product-stock-amount-aggregated').text(productDetails.stock_amount_aggregated);
|
$('#productcard-product-stock-amount-aggregated').text(productDetails.stock_amount_aggregated);
|
||||||
|
|
|
||||||
10
routes.php
10
routes.php
|
|
@ -5,8 +5,7 @@ use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
use Slim\Routing\RouteCollectorProxy;
|
use Slim\Routing\RouteCollectorProxy;
|
||||||
|
|
||||||
$app->group('', function (RouteCollectorProxy $group)
|
$app->group('', function (RouteCollectorProxy $group) {
|
||||||
{
|
|
||||||
// System routes
|
// System routes
|
||||||
$group->get('/', '\Grocy\Controllers\SystemController:Root')->setName('root');
|
$group->get('/', '\Grocy\Controllers\SystemController:Root')->setName('root');
|
||||||
$group->get('/about', '\Grocy\Controllers\SystemController:About');
|
$group->get('/about', '\Grocy\Controllers\SystemController:About');
|
||||||
|
|
@ -41,6 +40,7 @@ $app->group('', function (RouteCollectorProxy $group)
|
||||||
$group->get('/quantityunitconversion/{quConversionId}', '\Grocy\Controllers\StockController:QuantityUnitConversionEditForm');
|
$group->get('/quantityunitconversion/{quConversionId}', '\Grocy\Controllers\StockController:QuantityUnitConversionEditForm');
|
||||||
$group->get('/productgroups', '\Grocy\Controllers\StockController:ProductGroupsList');
|
$group->get('/productgroups', '\Grocy\Controllers\StockController:ProductGroupsList');
|
||||||
$group->get('/productgroup/{productGroupId}', '\Grocy\Controllers\StockController:ProductGroupEditForm');
|
$group->get('/productgroup/{productGroupId}', '\Grocy\Controllers\StockController:ProductGroupEditForm');
|
||||||
|
$group->get('/product/{productId}/grocycode', '\Grocy\Controllers\StockController:ProductGrocycodeImage');
|
||||||
|
|
||||||
// Stock handling routes
|
// Stock handling routes
|
||||||
if (GROCY_FEATURE_FLAG_STOCK)
|
if (GROCY_FEATURE_FLAG_STOCK)
|
||||||
|
|
@ -140,8 +140,7 @@ $app->group('', function (RouteCollectorProxy $group)
|
||||||
$group->get('/manageapikeys/new', '\Grocy\Controllers\OpenApiController:CreateNewApiKey');
|
$group->get('/manageapikeys/new', '\Grocy\Controllers\OpenApiController:CreateNewApiKey');
|
||||||
});
|
});
|
||||||
|
|
||||||
$app->group('/api', function (RouteCollectorProxy $group)
|
$app->group('/api', function (RouteCollectorProxy $group) {
|
||||||
{
|
|
||||||
// OpenAPI
|
// OpenAPI
|
||||||
$group->get('/openapi/specification', '\Grocy\Controllers\OpenApiController:DocumentationSpec');
|
$group->get('/openapi/specification', '\Grocy\Controllers\OpenApiController:DocumentationSpec');
|
||||||
|
|
||||||
|
|
@ -247,7 +246,6 @@ $app->group('/api', function (RouteCollectorProxy $group)
|
||||||
})->add(JsonMiddleware::class);
|
})->add(JsonMiddleware::class);
|
||||||
|
|
||||||
// Handle CORS preflight OPTIONS requests
|
// Handle CORS preflight OPTIONS requests
|
||||||
$app->options('/api/{routes:.+}', function (Request $request, Response $response): Response
|
$app->options('/api/{routes:.+}', function (Request $request, Response $response): Response {
|
||||||
{
|
|
||||||
return $response->withStatus(204);
|
return $response->withStatus(204);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,11 @@
|
||||||
@if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)<strong>{{ $__t('Average price') }}:</strong> <span id="productcard-product-average-price"></span><br>@endif
|
@if (GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)<strong>{{ $__t('Average price') }}:</strong> <span id="productcard-product-average-price"></span><br>@endif
|
||||||
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)<strong>{{ $__t('Average shelf life') }}:</strong> <span id="productcard-product-average-shelf-life"></span><br>@endif
|
@if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)<strong>{{ $__t('Average shelf life') }}:</strong> <span id="productcard-product-average-shelf-life"></span><br>@endif
|
||||||
<strong>{{ $__t('Spoil rate') }}:</strong> <span id="productcard-product-spoil-rate"></span>
|
<strong>{{ $__t('Spoil rate') }}:</strong> <span id="productcard-product-spoil-rate"></span>
|
||||||
|
<p><strong>{{ $__t('Grocycode') }}:</strong><br><img id="productcard-product-grocycode-image"
|
||||||
|
data-src=""
|
||||||
|
class="lazy"><br><a href="#"
|
||||||
|
target="_blank"
|
||||||
|
id="productcard-product-grocycode-image-link">{{ $__t('Download') }}</a></p>
|
||||||
|
|
||||||
<p class="w-75 mt-3 mx-auto"><img id="productcard-product-picture"
|
<p class="w-75 mt-3 mx-auto"><img id="productcard-product-picture"
|
||||||
data-src=""
|
data-src=""
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,11 @@
|
||||||
|
|
||||||
@if($mode == 'edit')
|
@if($mode == 'edit')
|
||||||
<script>
|
<script>
|
||||||
Grocy.EditObjectId = {{ $product->id }};
|
Grocy.EditObjectId = {
|
||||||
|
{
|
||||||
|
$product - > id
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@if(!empty($product->picture_file_name))
|
@if(!empty($product->picture_file_name))
|
||||||
|
|
@ -145,7 +149,12 @@
|
||||||
for="cumulate_min_stock_amount_of_sub_products">{{ $__t('Accumulate sub products min. stock amount') }}
|
for="cumulate_min_stock_amount_of_sub_products">{{ $__t('Accumulate sub products min. stock amount') }}
|
||||||
<i class="fas fa-question-circle text-muted"
|
<i class="fas fa-question-circle text-muted"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
title="{{ $__t('If enabled, the min. stock amount of sub products will be accumulated into this product, means the sub product will never be "missing", only this product') }}"></i>
|
title="{{ $__t('If enabled, the min. stock amount of sub products will be accumulated into this product, means the sub product will never be "
|
||||||
|
missing",
|
||||||
|
only
|
||||||
|
this
|
||||||
|
product')
|
||||||
|
}}"></i>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -426,7 +435,24 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-lg-6 col-xs-12 @if($mode == 'create') d-none @endif">
|
<div class="col-lg-6 col-xs-12 @if($mode == 'create') d-none @endif">
|
||||||
<div class="row @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif">
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col clearfix">
|
||||||
|
<div class="title-related-links">
|
||||||
|
<h4>
|
||||||
|
{{ $__t('Grocycode') }}
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
<img src="{{ $U('/product/' . $product->id . '/grocycode') }}"
|
||||||
|
class="float-lg-left mr-2">
|
||||||
|
{{ $__t('Grocycode is a unique referer to this product in your grocy instance. Print it onto a label and scan it like any other barcode!') }}<br>
|
||||||
|
<a href="{{ $U('/product/' . $product->id . '/grocycode?download=true') }}">{{ $__t('Download') }}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row @if(!GROCY_FEATURE_FLAG_STOCK) d-none @endif mt-5">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="title-related-links">
|
<div class="title-related-links">
|
||||||
<h4>
|
<h4>
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,11 @@
|
||||||
href="#">
|
href="#">
|
||||||
{{ $__t('Product overview') }}
|
{{ $__t('Product overview') }}
|
||||||
</a>
|
</a>
|
||||||
|
<a class="dropdown-item stockentry-grocycode-link"
|
||||||
|
type="button"
|
||||||
|
href="{{ $U('/stockentry/' . $stockEntry->id . '/grocycode?download=true') }}">
|
||||||
|
{{ $__t('Download stock entry grocycode') }}
|
||||||
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link"
|
||||||
type="button"
|
type="button"
|
||||||
href="{{ $U('/stockjournal?embedded&product=') }}{{ $stockEntry->product_id }}">
|
href="{{ $U('/stockjournal?embedded&product=') }}{{ $stockEntry->product_id }}">
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,11 @@
|
||||||
href="#">
|
href="#">
|
||||||
<span class="dropdown-item-text">{{ $__t('Product overview') }}</span>
|
<span class="dropdown-item-text">{{ $__t('Product overview') }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="dropdown-item stockentry-grocycode-link"
|
||||||
|
type="button"
|
||||||
|
href="{{ $U('/product/' . $currentStockEntry->product_id . '/grocycode?download=true') }}">
|
||||||
|
{{ $__t('Download product grocycode') }}
|
||||||
|
</a>
|
||||||
<a class="dropdown-item show-as-dialog-link"
|
<a class="dropdown-item show-as-dialog-link"
|
||||||
type="button"
|
type="button"
|
||||||
href="{{ $U('/stockentries?embedded&product=') }}{{ $currentStockEntry->product_id }}"
|
href="{{ $U('/stockentries?embedded&product=') }}{{ $currentStockEntry->product_id }}"
|
||||||
|
|
@ -308,7 +313,8 @@
|
||||||
<td>
|
<td>
|
||||||
@if($currentStockEntry->product_group_name !== null){{ $currentStockEntry->product_group_name }}@endif
|
@if($currentStockEntry->product_group_name !== null){{ $currentStockEntry->product_group_name }}@endif
|
||||||
</td>
|
</td>
|
||||||
<td data-order={{ $currentStockEntry->amount }}>
|
<td data-order={{
|
||||||
|
$currentStockEntry->amount }}>
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-amount"
|
<span id="product-{{ $currentStockEntry->product_id }}-amount"
|
||||||
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural) }}</span>
|
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural) }}</span>
|
||||||
<span id="product-{{ $currentStockEntry->product_id }}-opened-amount"
|
<span id="product-{{ $currentStockEntry->product_id }}-opened-amount"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user