Shopware Backend - Dokumente

Dokumente-im-Querformat

In diesem Artikel finden Sie eine detaillierte Beschreibung, wie Sie Rechnungen, Lieferscheine usw. in Ihrem Shopware-Shop auf Querformat umstellen können. Durch die Umstellung auf Querformat kann die Positionentabelle mehr Spalten aufnehmen und es bieten sich neue Möglichkeiten in der Layout Gestaltung.

Vielleicht haben Sie zuvor bereits, die Shopware-Dokumentation und sämtliche Forumsbeiträge zum Thema gelesen. Nicht ohne Grund findet man kaum eine Lösung für ein scheinbar so einfaches Problem. Obwohl Shopware normalerweise hervorragende Erweiterungsmöglichkeiten für nahezu alle Bereiche bietet, stellt der Bereich der Dokumentenerzeugung eine Ausnahme dar. Die hier präsentierte Lösung erfüllt trotzdem ihre Aufgabe im vollen Umfang. Sie ist jedoch, aus der „code quality“-Sicht nicht unbedingt eine Elegante. Aufgrund der ungeschickten Implementierung von Shopware in diesem Bereich, müssen wir auf Hooks zurückgreifen und relativ viel Code duplizieren.

Wie funktioniert es?

Die Erzeugung von PDF-Dokumenten läuft in mehreren Schritten ab. Im ersten Schritt wird, mit Hilfe der Smarty-Engine aus einem, mit Daten angereicherten Template (.tpl-Datei) HTML generiert. Aus diesem HTML wird mit Hilfe der „mPDF“-Library eine PDF-Datei erzeugt. Diese PDF-Dateien können zusätzlich, in der Stapelverarbeitung der Bestellungenübersicht mit Hilfe der „FPDF“-Library zu einer PDF-Datei zusammengefasst werden.

Also besteht die Lösung darin „mPDF“ und „FDPF“ anzuweisen Dateien in Querformat zu erstellen.

PDF-Erzeugung mit mPDF anpassen.

Die Action „createDocumentAction“ im „Order“-Controller ist für die Erzeugung der PDF-Dokumente zuständig. Die Action delegiert jedoch die Aufgabe an die Klasse „Shopware_Components_Document“. In der „render“-Methode dieser Klasse findet der eigentliche „mPDF“-Aufruf statt:

$mpdf = new mPDF("utf-8", "A4", "", "", 
                  $this->_document["left"], $this->_document["right"],
                  $this->_document["top"],  $this->_document["bottom"]);
$mpdf->WriteHTML($data);
$mpdf->Output($path, "F");

Um das Ganze auf Querformat umzustellen würde es genügen den Parameter „A4“ auf „A4-L“ (L für Landscape) umzustellen. Es werden in der ganzen Klasse keine Events geworfen. Uns bleibt hier nur die Notlösung über einen Hook.

Die Methode „render“ beinhaltet sehr viel Logik. Zuviel um sie, mit Hilfe eines Hooks sauber überschreiben zu können. Obwohl wir nur sehr kleine Anpassungen an der Methode machen wollen, müssen wir die gesamte Methode in einem „replace“-Hook kopieren. Es wird reichlich auf Klassen-Variablen zugegriffen und, als ob Shopware es uns zusätzlich schwer machen wollte, haben einige davon die Sichtbarkeit „protected“. Diese müssen über Umwege zusätzlich beschaffen werden. Unter anderem brauchen wir dafür einen zusätzlichen Hook. In der install-Methode:

public function install() {
  $this->subscribeEvent (
    'Shopware_Components_Document::render::replace',
    'replaceRender' );
  $this->subscribeEvent (
    'Shopware_Components_Document::setDocumentId::after',
    'afterSetDocumentId' );
  return true;
}

Die “replaceRender”-Methode:

public function replaceRender(Enlight_Hook_HookArgs $args) {
  $controller = $args->getSubject ();
  $controller->assignValues ();
	
  if (! empty ( $controller->_subshop ['doc_template_id'] )) {
    $template = Shopware ()->Container ()->get ( 'models' )->find (
      'Shopware\Models\Shop\Template',
      $controller->_subshop ['doc_template_id'] );	
    $inheritance = Shopware()->Container()->get('theme_inheritance')-> 
      getTemplateDirectories($template);
    $controller->_template->setTemplateDir ( $inheritance );
  }
  $documentType = $controller->_config ["DocumentId"];
  $_document = $this->getDocument( $controller->_config["DocumentId"]);
  $data = $controller->_template->fetch(
    "documents/". $_document["template"], $controller->_view );
  $_preview = $controller->_config ["_preview"];
  if ($_preview == true) {
    $mpdf = new mPDF ( 
      "utf-8", "A4-L", "", "", $_document ["left"], $_document ["right"], 
      $_document ["top"], $_document ["bottom"] );
    $mpdf->WriteHTML ( $data );
    $mpdf->Output ();
    exit ();
  } else {
    $orderId = $controller->_order->id;
    $sql = 'SELECT od.hash FROM s_order_documents od 
	      WHERE userID = (SELECT o.userID FROM s_order o WHERE o.id = ?) 
		   		      AND od.orderID = ? 
				      AND od.type = ?';
    $hash = Shopware ()->Db ()->fetchOne ( 
      $sql, array (	$orderId,$orderId,$documentType)
    );
    $path = Shopware()->DocPath()."files/documents"."/".$hash.".pdf";
    $mpdf = new mPDF (
      "utf-8", "A4-L", "", "", $_document ["left"], $_document ["right"],
      $_document ["top"], $_document ["bottom"] );
    $mpdf->WriteHTML ( $data );
    $mpdf->Output ( $path, "F" );
  }
}

Der Hook auf die “setDocumentId”-Methode ist nur dafür da damit wir in der „replaceRender“-Methode Zugriff auf „DocumentId“ haben. Das müssen wir machen, da das ursprüngliche Attribut in der Klasse „protected“ ist und somit nicht in der Hook-Methode sichtbar. Wir stecken seinen Wert in die „_config“-Variable, die glücklicherweise die Sichtbarkeit „public“ hat:

public function afterSetDocumentId(Enlight_Hook_HookArgs $args) {
  $controller = $args->getSubject ();
  $controller->_config ["DocumentId"] = $args->getArgs ()[0];
}

PDF-Erzeugung mit FPDF anpassen.

Nochmal zur Erinnerung – mit FPDF fasst Shopware mehrere PDF-Dokumente zu einem zusammen. Das geschieht in der Stappelvrarbeitung. Obwohl unsere Dokumente bereits im Querformat vorliegen muss auch FPDF auf Querformat eingestellt werden. Im „Order“-Controller übernimmt die „mergeDocumentsAction“ diese Aufgabe. Auch hier kommen wir nicht an die notwendigen Codezeilen heran, ohne viel Code in einem Hook kopieren und überschreiben zu müssen.

Weiteren Hook in der install-Methode registrieren:

public function install() {
  $this->subscribeEvent (
    'Shopware_Components_Document::render::replace',
    'replaceRender' );
  $this->subscribeEvent (
    'Shopware_Components_Document::setDocumentId::after',
    'afterSetDocumentId' );
  $this->subscribeEvent (
    'Shopware_Controllers_Backend_Order::mergeDocumentsAction::replace',
    'replaceMergeDocumentsAction' );
  return true;
}

Die Methode, die wir hier eigentlich anpassen wollen heißt „mergeDocuments“. Da sie aber als „private“ deklariert ist, können wir Sie nicht mittels einem Hook überschreiben. Stattdessen müssen wir die ganze Action „mergeDocumentsAction“ überschreiben und den Aufruf von „mergeDocuments“ auf unsere lokale „mergeDocuments“-Methode umlenken:

public function replaceMergeDocumentsAction(Enlight_Hook_HookArgs $args) {
  $controller = $args->getSubject ();
  $data = $controller->Request ()->getParam ( 'data', null ); 
  $controller->Front ()->Plugins ()->ViewRenderer ()->setNoRender ();
  if ($data === null) {
    $controller->View ()->assign( array (
      'success' => false,
      'message' => 'No valid data passed.' 
    ) );
    return;
  }
  $data = json_decode ( $data );
  if ($data->orders === null || count ( $data->orders ) === 0) {
    $controller->View ()->assign ( array (
      'success' => false,
      'message' => 'No valid order id passed.' 
    ) );
    return;
  } 
  $files = array ();
  $query = $controller->getOrderDocumentsQuery ( 
    $data->orders, $data->docType );
  $models = $query->getResult ();
  foreach ( $models as $model ) {
    foreach ( $model->getDocuments () as $document ) {
      $files [] = Shopware()->DocPath( 'files/documents' )
        .$document->getHash().".pdf";
    }
  }
  $this->mergeDocuments( $files );
}

private function mergeDocuments($paths) {
  include_once 'engine/Library/Fpdf/fpdf.php';
  include_once 'engine/Library/Fpdf/fpdi.php';    
  $pdf = new FPDI ();   
  foreach ( $paths as $path ) {
    $numPages = $pdf->setSourceFile ( $path );
    for($i = 1; $i <= $numPages; $i ++) {
      $template = $pdf->importPage ( $i );
      $size = $pdf->getTemplateSize ( $template );
      $pdf->AddPage ( 'L', array($size ['w'], $size ['h']) );
      $pdf->useTemplate ( $template );
    }
  }
  $hash = md5 ( uniqid ( rand () ) );   
  $pdf->Output ( $hash . '.pdf', "D" );
}

Damit haben wir alle Bereiche der Dokumentengenerierung auf Querformat umgestellt.