mirror of
https://github.com/grocy/grocy.git
synced 2026-04-05 12:26: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)
|
||||
{
|
||||
if ($args['productGroupId'] == 'new')
|
||||
|
|
@ -436,11 +464,24 @@ class StockController extends BaseController
|
|||
$gc = new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id]);
|
||||
$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('Cache-Control', 'no-cache')
|
||||
->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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2374,3 +2374,18 @@ msgstr "Druckoptionen"
|
|||
|
||||
msgid "A product or a note is required"
|
||||
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"
|
||||
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" }));
|
||||
|
||||
// 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)
|
||||
{
|
||||
$('#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 Slim\Routing\RouteCollectorProxy;
|
||||
|
||||
$app->group('', function (RouteCollectorProxy $group)
|
||||
{
|
||||
$app->group('', function (RouteCollectorProxy $group) {
|
||||
// System routes
|
||||
$group->get('/', '\Grocy\Controllers\SystemController:Root')->setName('root');
|
||||
$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('/productgroups', '\Grocy\Controllers\StockController:ProductGroupsList');
|
||||
$group->get('/productgroup/{productGroupId}', '\Grocy\Controllers\StockController:ProductGroupEditForm');
|
||||
$group->get('/product/{productId}/grocycode', '\Grocy\Controllers\StockController:ProductGrocycodeImage');
|
||||
|
||||
// Stock handling routes
|
||||
if (GROCY_FEATURE_FLAG_STOCK)
|
||||
|
|
@ -140,8 +140,7 @@ $app->group('', function (RouteCollectorProxy $group)
|
|||
$group->get('/manageapikeys/new', '\Grocy\Controllers\OpenApiController:CreateNewApiKey');
|
||||
});
|
||||
|
||||
$app->group('/api', function (RouteCollectorProxy $group)
|
||||
{
|
||||
$app->group('/api', function (RouteCollectorProxy $group) {
|
||||
// OpenAPI
|
||||
$group->get('/openapi/specification', '\Grocy\Controllers\OpenApiController:DocumentationSpec');
|
||||
|
||||
|
|
@ -247,7 +246,6 @@ $app->group('/api', function (RouteCollectorProxy $group)
|
|||
})->add(JsonMiddleware::class);
|
||||
|
||||
// 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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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_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>
|
||||
<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"
|
||||
data-src=""
|
||||
|
|
@ -68,4 +73,4 @@
|
|||
class="font-italic d-none">{{ $__t('No price history available') }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -25,7 +25,11 @@
|
|||
|
||||
@if($mode == 'edit')
|
||||
<script>
|
||||
Grocy.EditObjectId = {{ $product->id }};
|
||||
Grocy.EditObjectId = {
|
||||
{
|
||||
$product - > id
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@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') }}
|
||||
<i class="fas fa-question-circle text-muted"
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -426,7 +435,24 @@
|
|||
</div>
|
||||
|
||||
<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="title-related-links">
|
||||
<h4>
|
||||
|
|
@ -667,4 +693,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
@stop
|
||||
|
|
@ -185,6 +185,11 @@
|
|||
href="#">
|
||||
{{ $__t('Product overview') }}
|
||||
</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"
|
||||
type="button"
|
||||
href="{{ $U('/stockjournal?embedded&product=') }}{{ $stockEntry->product_id }}">
|
||||
|
|
@ -279,4 +284,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
@stop
|
||||
|
|
@ -277,6 +277,11 @@
|
|||
href="#">
|
||||
<span class="dropdown-item-text">{{ $__t('Product overview') }}</span>
|
||||
</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"
|
||||
type="button"
|
||||
href="{{ $U('/stockentries?embedded&product=') }}{{ $currentStockEntry->product_id }}"
|
||||
|
|
@ -308,7 +313,8 @@
|
|||
<td>
|
||||
@if($currentStockEntry->product_group_name !== null){{ $currentStockEntry->product_group_name }}@endif
|
||||
</td>
|
||||
<td data-order={{ $currentStockEntry->amount }}>
|
||||
<td data-order={{
|
||||
$currentStockEntry->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>
|
||||
<span id="product-{{ $currentStockEntry->product_id }}-opened-amount"
|
||||
|
|
@ -413,4 +419,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
@stop
|
||||
Loading…
Reference in New Issue
Block a user