PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.16
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.16
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
woocommerce-pos / includes / Services / Providers / Printnode_Adapter.php

Printnode_Adapter.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.16, at includes/Services/Providers/Printnode_Adapter.php

186 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * PrintNode provider adapter.
4 *
5 * @package WCPOS\WooCommercePOS\Services\Providers
6 */
7
8 namespace WCPOS\WooCommercePOS\Services\Providers;
9
10 use WCPOS\WooCommercePOS\Interfaces\Push_Provider_Adapter_Interface;
11 use WCPOS\WooCommercePOS\Services\Pdf_Renderer;
12 use WCPOS\WooCommercePOS\Services\Print_Job_Service;
13 use WCPOS\WooCommercePOS\Services\PrintNode_Client;
14
15 /**
16 * Printnode_Adapter class.
17 */
18 class Printnode_Adapter implements Push_Provider_Adapter_Interface {
19 /**
20 * Return the PrintNode default PDF content type.
21 *
22 * @return string
23 */
24 public function content_type(): string {
25 return 'application/pdf';
26 }
27
28 /**
29 * Resolve PrintNode PDF or raw ESC/POS format data.
30 *
31 * @param array $printer Printer configuration.
32 * @param array $template Template configuration.
33 *
34 * @return array{kind:string, content_type:string}
35 */
36 public function format( array $printer, array $template ): array {
37 if ( 'thermal' !== (string) ( $template['engine'] ?? '' ) || 'raw' !== (string) ( $printer['printnode_format'] ?? 'pdf' ) ) {
38 return array(
39 'kind' => 'pdf',
40 'content_type' => $this->content_type(),
41 );
42 }
43
44 return array(
45 'kind' => 'escpos',
46 'content_type' => 'application/octet-stream',
47 );
48 }
49
50 /**
51 * Build a printer-friendly diagnostic PDF.
52 *
53 * @param string $printer_name Printer display name.
54 *
55 * @return array{content_type:string, payload:string}
56 */
57 public function diagnostic( string $printer_name ): array {
58 $html = '<!DOCTYPE html><html><head><meta charset="utf-8"><style>';
59 $html .= 'body{font-family:"dejavu sans",sans-serif;color:#000;background:#fff;margin:24px;}'
60 . 'h1{font-size:18px;margin:0 0 12px;}.row{font-size:13px;margin:4px 0;}'
61 . '.label{font-weight:bold;}hr{border:none;border-top:1px solid #000;margin:16px 0;}'
62 . '.ok{font-size:14px;font-weight:bold;margin-top:16px;}</style></head><body>';
63 $html .= '<h1>WCPOS &mdash; Cloud Print Test</h1>';
64 $html .= '<div class="row"><span class="label">Printer:</span> ' . esc_html( $printer_name ) . '</div>';
65 $html .= '<div class="row"><span class="label">Date (UTC):</span> ' . esc_html( gmdate( 'Y-m-d H:i' ) ) . '</div>';
66 $html .= '<hr><div class="ok">If you can read this, printing works!</div></body></html>';
67
68 return array(
69 'content_type' => $this->content_type(),
70 'payload' => base64_encode( ( new Pdf_Renderer() )->render_html( $html ) ),
71 );
72 }
73
74 /**
75 * Resolve PrintNode live status with the existing transient cache contract.
76 *
77 * @param array $printer Printer configuration.
78 * @param array $context Runtime status context.
79 *
80 * @return string
81 */
82 public function status( array $printer, array $context ): string {
83 $key = 'wcpos_cloud_print_pn_status_' . md5( (string) $printer['id'] );
84 $cached = get_transient( $key );
85 if ( false !== $cached ) {
86 return (string) $cached;
87 }
88
89 $api_key = (string) ( $printer['printnode_api_key'] ?? '' );
90 $printer_id = (int) ( $printer['printnode_printer_id'] ?? 0 );
91 $status = '' === $api_key || 0 === $printer_id
92 ? 'unknown'
93 : ( new PrintNode_Client( $api_key ) )->printer_state( $printer_id );
94 set_transient( $key, $status, (int) $context['cache_ttl'] );
95
96 return $status;
97 }
98
99 /**
100 * Submit a rendered PrintNode job and optional drawer kick.
101 *
102 * @param array $printer Printer configuration.
103 * @param array $job Print job data.
104 * @param string $payload Rendered payload bytes.
105 * @param string $title Provider job title.
106 *
107 * @return array{success:bool, retryable:bool, error:string, external_job_id:string, drawer_error:string}
108 */
109 public function submit( array $printer, array $job, string $payload, string $title ): array {
110 $api_key = (string) ( $printer['printnode_api_key'] ?? '' );
111 $printer_id = (int) ( $printer['printnode_printer_id'] ?? 0 );
112 if ( '' === $api_key || 0 === $printer_id ) {
113 return $this->failure( 'Cloud print: PrintNode printer is missing an API key or printer id.', false );
114 }
115 if ( '' === $payload ) {
116 return $this->failure( 'Cloud print: PrintNode job produced no printable content.', false );
117 }
118
119 $content_type = 'pdf_base64';
120 if ( 'escpos' === ( $job['pn_kind'] ?? '' ) ) {
121 $content_type = 'raw_base64';
122 }
123
124 $client = new PrintNode_Client( $api_key );
125 $result = $client->submit_job(
126 $printer_id,
127 $title,
128 $content_type,
129 base64_encode( $payload )
130 );
131 if ( is_wp_error( $result ) ) {
132 return $this->failure( $result->get_error_message(), true );
133 }
134
135 $drawer_error = '';
136 if ( 'pdf' === ( $job['pn_kind'] ?? '' ) && ! empty( $job['auto_open_drawer'] ) ) {
137 $drawer = $client->submit_job(
138 $printer_id,
139 $title . ' Cash Drawer',
140 'raw_base64',
141 base64_encode( $this->drawer_kick_bytes( (string) ( $job['drawer_connector'] ?? 'pin2' ) ) )
142 );
143 $drawer_error = is_wp_error( $drawer ) ? $drawer->get_error_message() : '';
144 }
145
146 return array(
147 'success' => true,
148 'retryable' => false,
149 'error' => '',
150 'external_job_id' => (string) $result['id'],
151 'drawer_error' => $drawer_error,
152 );
153 }
154
155 /**
156 * Build the stable submit failure shape.
157 *
158 * @param string $error Provider error message.
159 * @param bool $retryable Whether the service should retry.
160 *
161 * @return array{success:bool, retryable:bool, error:string, external_job_id:string, drawer_error:string}
162 */
163 private function failure( string $error, bool $retryable ): array {
164 return array(
165 'success' => false,
166 'retryable' => $retryable,
167 'error' => $error,
168 'external_job_id' => '',
169 'drawer_error' => '',
170 );
171 }
172
173 /**
174 * Build ESC/POS drawer kick bytes.
175 *
176 * @param string $connector pin2 or pin5.
177 *
178 * @return string
179 */
180 private function drawer_kick_bytes( string $connector ): string {
181 $pin = 'pin5' === Print_Job_Service::normalize_drawer_connector( $connector ) ? "\x01" : "\x00";
182
183 return "\x1B\x70" . $pin . "\x19\xFA";
184 }
185 }
186