mirror of
https://github.com/grocy/grocy.git
synced 2025-08-20 12:20:22 +00:00
Add support for printing shoppinglist with thermal printer (#1273)
* Added escpos-php library * Added button to shoppinglist print menu * Added to translation * Added basic printing logic and API call * Working implementation for printing with the API * Added openapi json * Correctly parsing boolean parameter * Working button in UI * Change to grocy formatting * Add Date * Only show thermal print button when Feature Flag is set * Fixed API call and added error message parsing * Undo translation * Add flag to print quantities as well * Added printing notes * Added quantity conversion * Increse feed * Fixed that checkbox was undefined, as dialog was already closed * Added padding * Formatting * Added note about user permission * Fixed error when using notes instead of products * Review - Default FEATURE_FLAG_THERMAL_PRINTER to disabled - Added missing localization strings (and slightly adjusted one) * Fixed merge conflicts Co-authored-by: Bernd Bestel <bernd@berrnd.de>
This commit is contained in:
@@ -66,4 +66,10 @@ class BaseService
|
||||
{
|
||||
return UsersService::getInstance();
|
||||
}
|
||||
|
||||
protected function getPrintService()
|
||||
{
|
||||
return PrintService::getInstance();
|
||||
}
|
||||
|
||||
}
|
||||
|
84
services/PrintService.php
Normal file
84
services/PrintService.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Services;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use Mike42\Escpos\PrintConnectors\NetworkPrintConnector;
|
||||
use Mike42\Escpos\PrintConnectors\FilePrintConnector;
|
||||
use Mike42\Escpos\Printer;
|
||||
|
||||
class PrintService extends BaseService
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Initialises the printer
|
||||
* @return Printer Printer handle
|
||||
* @throws Exception If unable to connect to printer, an exception is thrown
|
||||
*/
|
||||
private static function getPrinterHandle()
|
||||
{
|
||||
if (GROCY_TPRINTER_IS_NETWORK_PRINTER) {
|
||||
$connector = new NetworkPrintConnector(GROCY_TPRINTER_IP, GROCY_TPRINTER_PORT);
|
||||
} else {
|
||||
$connector = new FilePrintConnector(GROCY_TPRINTER_CONNECTOR);
|
||||
}
|
||||
return new Printer($connector);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the grocy logo and date
|
||||
* @param Printer $printer Printer handle
|
||||
*/
|
||||
private static function printHeader(Printer $printer)
|
||||
{
|
||||
$date = new DateTime();
|
||||
$dateFormatted = $date->format('d/m/Y H:i');
|
||||
|
||||
$printer->setJustification(Printer::JUSTIFY_CENTER);
|
||||
$printer->selectPrintMode(Printer::MODE_DOUBLE_WIDTH);
|
||||
$printer->setTextSize(4, 4);
|
||||
$printer->setReverseColors(true);
|
||||
$printer->text("grocy");
|
||||
$printer->setJustification();
|
||||
$printer->setTextSize(1, 1);
|
||||
$printer->setReverseColors(false);
|
||||
$printer->feed(2);
|
||||
$printer->text($dateFormatted);
|
||||
$printer->selectPrintMode();
|
||||
$printer->feed(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $printHeader Printing of Grocy logo
|
||||
* @param string[] $lines Items to print
|
||||
* @return string[] Returns array with result OK if no exception
|
||||
* @throws Exception If unable to print, an exception is thrown
|
||||
*/
|
||||
public function printShoppingList(bool $printHeader, array $lines): array
|
||||
{
|
||||
$printer = self::getPrinterHandle();
|
||||
if ($printer === false)
|
||||
throw new Exception("Unable to connect to printer");
|
||||
|
||||
if ($printHeader)
|
||||
{
|
||||
self::printHeader($printer);
|
||||
}
|
||||
|
||||
foreach ($lines as $line)
|
||||
{
|
||||
$printer->text($line);
|
||||
$printer->feed();
|
||||
}
|
||||
|
||||
$printer->feed(3);
|
||||
$printer->cut();
|
||||
$printer->close();
|
||||
return [
|
||||
'result' => "OK"
|
||||
];
|
||||
}
|
||||
}
|
@@ -970,6 +970,88 @@ class StockService extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shoppinglist as an array with lines for a printer
|
||||
* @param int $listId ID of shopping list
|
||||
* @return string[] Returns an array in the format "[amount] [name of product]"
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetShoppinglistInPrintableStrings($listId = 1): array
|
||||
{
|
||||
if (!$this->ShoppingListExists($listId))
|
||||
{
|
||||
throw new \Exception('Shopping list does not exist');
|
||||
}
|
||||
|
||||
$result_product = array();
|
||||
$result_quantity = array();
|
||||
$rowsShoppingListProducts = $this->getDatabase()->uihelper_shopping_list()->where('shopping_list_id = :1', $listId)->fetchAll();
|
||||
foreach ($rowsShoppingListProducts as $row)
|
||||
{
|
||||
$isValidProduct = ($row->product_id != null && $row->product_id != "");
|
||||
if ($isValidProduct)
|
||||
{
|
||||
$product = $this->getDatabase()->products()->where('id = :1', $row->product_id)->fetch();
|
||||
$conversion = $this->getDatabase()->quantity_unit_conversions_resolved()->where('product_id = :1 AND from_qu_id = :2 AND to_qu_id = :3', $product->id, $product->qu_id_stock, $row->qu_id)->fetch();
|
||||
$factor = 1.0;
|
||||
if ($conversion != null)
|
||||
{
|
||||
$factor = floatval($conversion->factor);
|
||||
}
|
||||
$amount = round($row->amount * $factor);
|
||||
$note = "";
|
||||
if (GROCY_TPRINTER_PRINT_NOTES)
|
||||
{
|
||||
if ($row->note != "") {
|
||||
$note = ' (' . $row->note . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (GROCY_TPRINTER_PRINT_QUANTITY_NAME && $isValidProduct)
|
||||
{
|
||||
$quantityname = $row->qu_name;
|
||||
if ($amount > 1)
|
||||
{
|
||||
$quantityname = $row->qu_name_plural;
|
||||
}
|
||||
array_push($result_quantity, $amount . ' ' . $quantityname);
|
||||
array_push($result_product, $row->product_name . $note);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($isValidProduct)
|
||||
{
|
||||
array_push($result_quantity, $amount);
|
||||
array_push($result_product, $row->product_name . $note);
|
||||
}
|
||||
else
|
||||
{
|
||||
array_push($result_quantity, round($row->amount));
|
||||
array_push($result_product, $row->note);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//Add padding to look nicer
|
||||
$maxlength = 1;
|
||||
foreach ($result_quantity as $quantity)
|
||||
{
|
||||
if (strlen($quantity) > $maxlength)
|
||||
{
|
||||
$maxlength = strlen($quantity);
|
||||
}
|
||||
}
|
||||
$result = array();
|
||||
$length = count($result_quantity);
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
{
|
||||
$quantity = str_pad($result_quantity[$i], $maxlength);
|
||||
array_push($result, $quantity . ' ' . $result_product[$i]);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function TransferProduct(int $productId, float $amount, int $locationIdFrom, int $locationIdTo, $specificStockEntryId = 'default', &$transactionId = null)
|
||||
{
|
||||
if (!$this->ProductExists($productId))
|
||||
|
Reference in New Issue
Block a user