Documentation

Configuration of the Order Printer

The Order Printer offers extensive configuration options to adapt the system to your specific requirements.

Environment Configuration

The main configuration is done via the .env.local file. Here are the most important settings:

Shopware API Configuration

# Shopware API Access
SHOPWARE_HOST=https://your-shopware-domain.de
SHOPWARE_CLIENT_ID=your_client_id
SHOPWARE_CLIENT_SECRET=your_client_secret

# API Timeout (in seconds)
SHOPWARE_API_TIMEOUT=30

# API Rate Limiting
SHOPWARE_API_RATE_LIMIT=100
SHOPWARE_API_RATE_LIMIT_INTERVAL=60

Printer Configuration

# Printer connection: file:///dev/usb/lp0, tcp://<host>:9100 or dummy://
PRINTER_DSN=file:///dev/usb/lp0

# Optional: restaurant name on test receipts (bin/console printer:test), defaults to the SHOPWARE_HOST domain
SHOP_NAME="Masala Mio"

# Printer resolution (DPI)
PRINTER_DPI=203

# Characters per line
PRINTER_CHARACTERS_PER_LINE=42

# Print speed (1-5, 1 = slow, 5 = fast)
PRINTER_SPEED=3

# Printer density (1-15)
PRINTER_DENSITY=10

System Configuration

# Polling interval (in seconds)
POLLING_INTERVAL=10

# Maximum number of concurrent print jobs
MAX_CONCURRENT_PRINTS=5

# Queue timeout (in seconds)
QUEUE_TIMEOUT=300

# Data directory for receipt archive
DATA_DIR="/data/receipts/"

# Log level (debug, info, notice, warning, error, critical, alert, emergency)
LOG_LEVEL=info

Receipt Formatting

Standard Receipt Layout

The Order Printer generates receipts with the following standard layout:

┌────────────────────────────────────────┐
│              YOUR SHOP NAME             │
│    Sample Street 123 • 12345 Sample City │
│          Tel: 01234/567890              │
├────────────────────────────────────────┤
│                RECEIPT #1001             │
│            11.01.2024 14:30            │
├────────────────────────────────────────┤
│ Customer: Max Mustermann                 │
│ Tel: 0176/12345678                       │
├────────────────────────────────────────┤
│ 1x Pizza Margherita              8,99 € │
│ 2x Spaghetti Bolognese          15,98 € │
│ 1x Salad Caesar                  5,99 € │
├────────────────────────────────────────┤
│ Subtotal:                        30,96 € │
│ Delivery costs:                   2,50 € │
│ Total:                           33,46 € │
├────────────────────────────────────────┤
│ Payment method: Cash                      │
│ Delivery type: Pickup                     │
├────────────────────────────────────────┤
│           Thank you for your             │
│                purchase!                 │
└────────────────────────────────────────┘

Customize Receipt Layout

You can change the receipt layout by adjusting the ReceiptFormatter class:

// In src/Infra/Printer/Epson/ReceiptFormatter.php

public function formatHeader(): self
{
    $this->content .= self::ALIGN_CENTER;
    $this->content .= self::DOUBLE_WIDTH_ON;
    $this->content .= "YOUR SHOP NAME\n";
    $this->content .= self::DOUBLE_WIDTH_OFF;
    $this->content .= self::ALIGN_CENTER;
    $this->content .= "Sample Street 123 • 12345 Sample City\n";
    $this->content .= "Tel: 01234/567890\n";
    $this->content .= self::FEED;
    
    return $this;
}

To add a logo to the receipt, you need to convert the logo to ESC/POS bitmap:

# Convert logo (requires ImageMagick)
convert logo.png -resize 384x128 -colorspace Gray -dither None logo.bmp

# Convert logo to ESC/POS format
php bin/console order-printer:convert-logo logo.bmp logo.escpos

Then you can include the logo in the ReceiptFormatter class:

public function addLogo(): self
{
    $logoPath = __DIR__ . '/../../../public/logo.escpos';
    if (file_exists($logoPath)) {
        $this->content .= file_get_contents($logoPath);
        $this->content .= self::FEED;
    }
    
    return $this;
}

Retries on Print Failures

Short outages are normal: the Pi reboots, the restaurant WLAN drops, the printer is out of paper. The Order Printer therefore never gives up after a single failed attempt:

  • A failed print job is retried 10 times with increasing delays: 10 s, 20 s, 40 s, 80 s, 160 s and then every 5 minutes, about 30 minutes in total.
  • The order stays open in Shopware until the receipt was actually printed. Only a successful print sets it to in progress.
  • While a job is waiting for its retry, the poll does not queue the same order again. When the printer is back, every order is printed exactly once.
  • After the last retry the job is marked as failed and an error log line with the order number is written, for example Printing order 10556 failed permanently after 11 attempt(s): Cannot connect to printer "tcp://…". Use it for monitoring. Because the order is still open, the next poll queues it again and a new retry window starts, so nothing is lost as long as the printer comes back eventually.

Permanently failed jobs can be listed and cleaned up:

bin/console messenger:failed:show
bin/console messenger:failed:remove <id>

To reprint one order by hand:

bin/console app:print-order --order-number=10556

Advanced Configuration

Multiple Printers

One Order Printer instance prints to exactly one PRINTER_DSN. To drive several printers (for example kitchen and counter), run one instance per printer, each with its own .env.local, DATA_DIR and DATABASE_URL, pointing at the same Shopware shop. Because every instance marks printed orders as in progress, only one of them should run with --mark-in-progress; start the others with bin/console app:print-order --all-open --no-mark-in-progress on their own schedule, or filter orders per instance as described below.

Order Filtering

You can filter the orders to be retrieved by adjusting the OrderRepository class:

// In src/Infra/Shopware/OrderRepository.php

public function findNewNumbers(): array
{
    // Only orders with certain payment methods
    $paymentMethods = ['cash', 'card'];
    
    // Only orders above a certain value
    $minOrderValue = 5.00;
    
    // Only orders for certain delivery types
    $deliveryTypes = ['delivery', 'takeaway'];
    
    return $this->shopwareClient->getOrders(
        $paymentMethods,
        $minOrderValue,
        $deliveryTypes
    );
}

Notifications

You can set up notifications for certain events:

# In config/packages/messenger.yaml

framework:
    messenger:
        routing:
            'Veliu\OrderPrinter\Domain\Event\OrderPrintedEvent': async
            'Veliu\OrderPrinter\Domain\Event\PrintFailedEvent': failed

Then you can create event listeners:

#[AsMessageHandler]
final class OrderPrintedNotificationHandler
{
    public function __construct(
        private MailerInterface $mailer,
        private string $adminEmail
    ) {}
    
    public function __invoke(OrderPrintedEvent $event): void
    {
        $email = (new Email())
            ->from('noreply@shopbite.de')
            ->to($this->adminEmail)
            ->subject('Order printed: ' . $event->orderNumber)
            ->text('The order ' . $event->orderNumber . ' has been successfully printed.');
        
        $this->mailer->send($email);
    }
}

Performance Optimization

Caching

Enable caching for frequently retrieved data:

# In config/packages/cache.yaml

framework:
    cache:
        app: cache.adapter.filesystem
        default_redis_provider: 'redis://localhost'
        pools:
            shopware.cache:
                adapter: cache.adapter.redis
                default_lifetime: 3600

Batch Processing

For high order volumes, you can enable batch processing:

# Batch Configuration
BATCH_SIZE=10
BATCH_INTERVAL=30

Load Distribution

For systems with high throughput, you can set up multiple workers:

# Start multiple workers
bin/console messenger:consume async --limit=10 --time-limit=3600 &
bin/console messenger:consume async --limit=10 --time-limit=3600 &
bin/console messenger:consume async --limit=10 --time-limit=3600 &

Security

API Security

  • Enforce HTTPS: Ensure your Shopware instance uses HTTPS
  • IP Restriction: Restrict API access to specific IP addresses
  • Rate Limiting: Configure appropriate rate limits

Printer Security

  • Printer IP Restriction: Restrict access to the printer
  • Printer Password: Set up a printer password
  • Encryption: Use encrypted connections for network printers

Maintenance Configuration

Log Rotation

Set up log rotation to save disk space:

# Logrotate Configuration (/etc/logrotate.d/order-printer)
/var/log/order-printer-*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 644 www-data www-data
}

Data Cleanup

Set up regular data cleanup:

# Cron job for data cleanup (daily at 3 AM)
0 3 * * * /path/to/project/bin/console order-printer:cleanup --days=30

Next Steps