PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.9.16
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.9.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 / Cloud_Print_Trigger_Service.php

Cloud_Print_Trigger_Service.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.9.16, at includes/Services/Cloud_Print_Trigger_Service.php

261 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Creates cloud print jobs from WooCommerce order events.
4 *
5 * @package WCPOS\WooCommercePOS\Services
6 */
7
8 namespace WCPOS\WooCommercePOS\Services;
9
10 use WCPOS\WooCommercePOS\Logger;
11
12 /**
13 * Cloud_Print_Trigger_Service class.
14 */
15 class Cloud_Print_Trigger_Service {
16 const OPTION = 'woocommerce_pos_settings_cloud_print';
17
18 /**
19 * Cron hook used to submit a PrintNode job out-of-band (never on checkout).
20 */
21 const CRON_SUBMIT = 'wcpos_cloud_print_submit';
22
23 /**
24 * Job store.
25 *
26 * @var Print_Job_Service
27 */
28 private $jobs;
29
30 /**
31 * Printer registry.
32 *
33 * @var Cloud_Print_Registry
34 */
35 private $registry;
36
37 /**
38 * Constructor — hook order events.
39 */
40 public function __construct() {
41 $this->jobs = new Print_Job_Service();
42 $this->registry = new Cloud_Print_Registry();
43 add_action( 'woocommerce_new_order', array( $this, 'handle_order' ), 20, 1 );
44 add_action( 'woocommerce_order_status_changed', array( $this, 'handle_order' ), 20, 1 );
45 }
46
47 /**
48 * Create jobs for an order according to the configured assignments.
49 *
50 * @param int $order_id Order ID.
51 */
52 public function handle_order( $order_id ): void {
53 $order = wc_get_order( (int) $order_id );
54 if ( ! $order ) {
55 return;
56 }
57
58 $settings = get_option( self::OPTION, array() );
59 $assignments = isset( $settings['assignments'] ) && \is_array( $settings['assignments'] ) ? $settings['assignments'] : array();
60
61 /**
62 * Filter the cloud-print assignments for an order. Pro uses this to
63 * substitute per-outlet assignments based on the order's store.
64 *
65 * @param array $assignments Global assignments.
66 * @param \WC_Order $order The order being processed.
67 */
68 $assignments = apply_filters( 'woocommerce_pos_cloud_print_assignments', $assignments, $order );
69 if ( ! \is_array( $assignments ) ) {
70 $assignments = array();
71 }
72
73 if ( empty( $assignments ) ) {
74 return;
75 }
76
77 $is_pos = 'woocommerce-pos' === $order->get_created_via();
78
79 foreach ( $assignments as $assignment ) {
80 if ( empty( $assignment['printer_id'] ) || empty( $assignment['template_id'] ) ) {
81 continue;
82 }
83 $scope = isset( $assignment['scope'] ) ? (string) $assignment['scope'] : 'every';
84 if ( ! $this->scope_matches( $scope, $is_pos ) ) {
85 continue;
86 }
87 if ( $this->already_queued( $order->get_id(), (string) $assignment['printer_id'], (string) $assignment['template_id'] ) ) {
88 continue;
89 }
90
91 $printer = $this->registry->get_printer( (string) $assignment['printer_id'] );
92 if ( empty( $printer ) ) {
93 continue;
94 }
95 $provider = (string) ( $printer['provider'] ?? '' );
96
97 $template_id = (string) $assignment['template_id'];
98 $template = Print_Job_Service::load_template( $template_id );
99 if ( null === $template ) {
100 continue;
101 }
102
103 $job_id = self::enqueue_order_job(
104 $this->jobs,
105 (string) $assignment['printer_id'],
106 $printer,
107 $order->get_id(),
108 $template_id,
109 $template
110 );
111 if ( 0 === $job_id ) {
112 Logger::log(
113 sprintf(
114 'Cloud print: skipping assignment for printer "%s" — template "%s" is not printable on provider "%s".',
115 (string) $assignment['printer_id'],
116 $template_id,
117 $provider
118 )
119 );
120 }
121 }
122 }
123
124 /**
125 * Enqueue a print job for an order + template, deriving the wire format from
126 * the printer's provider. Shared by the order-event trigger and the manual
127 * print-jobs endpoint so the two cannot drift.
128 *
129 * For PrintNode the job's submit event is scheduled out-of-band (PrintNode
130 * does not poll). For polling providers (Star/Epson) the printer fetches the
131 * job on its next poll, so no submit is scheduled.
132 *
133 * @param Print_Job_Service $jobs Job store.
134 * @param string $printer_id Registered printer id.
135 * @param array $printer Registered printer config.
136 * @param int $order_id Order id to render.
137 * @param string $template_id Template id (numeric) or virtual slug.
138 * @param array $template Loaded template array.
139 * @param array $drawer_options Drawer options.
140 *
141 * @return int Created job id, or 0 when the template is not printable on the provider.
142 */
143 public static function enqueue_order_job( Print_Job_Service $jobs, string $printer_id, array $printer, int $order_id, string $template_id, array $template, array $drawer_options = array() ): int {
144 $provider = (string) ( $printer['provider'] ?? '' );
145 $drawer_options = self::drawer_options_for_provider( $provider, $drawer_options );
146
147 if ( 'printnode' === $provider ) {
148 $fmt = ( new Print_Format_Resolver() )->resolve( $printer, $template );
149 if ( '' === $fmt['kind'] ) {
150 return 0;
151 }
152
153 $job_id = $jobs->create(
154 array(
155 'printer_id' => $printer_id,
156 'order_id' => $order_id,
157 'template_id' => $template_id,
158 'content_type' => $fmt['content_type'],
159 'pn_kind' => $fmt['kind'],
160 'auto_open_drawer' => ! empty( $drawer_options['auto_open_drawer'] ),
161 'drawer_connector' => $drawer_options['drawer_connector'],
162 )
163 );
164 if ( $job_id > 0 ) {
165 wp_schedule_single_event( time(), self::CRON_SUBMIT, array( $job_id ) );
166 }
167
168 return $job_id;
169 }
170
171 $engine = (string) ( $template['engine'] ?? '' );
172 $wire = Provider::wire_format( $provider, $engine );
173 if ( null === $wire ) {
174 return 0;
175 }
176
177 $job_id = $jobs->create(
178 array(
179 'printer_id' => $printer_id,
180 'content_type' => Provider::content_type( $provider ),
181 'order_id' => $order_id,
182 'template_id' => $template_id,
183 'auto_open_drawer' => ! empty( $drawer_options['auto_open_drawer'] ),
184 'drawer_connector' => $drawer_options['drawer_connector'],
185 )
186 );
187
188 // Push providers (e.g. Star Online) don't poll us; submit out-of-band.
189 if ( $job_id > 0 && Provider::requires_submit( $provider ) ) {
190 wp_schedule_single_event( time(), self::CRON_SUBMIT, array( $job_id ) );
191 }
192
193 return $job_id;
194 }
195
196 /**
197 * Keep drawer metadata scoped to providers implemented by this server change.
198 *
199 * Star providers use Star-specific drawer commands and are intentionally not
200 * changed by the Epson/PrintNode implementation.
201 *
202 * @param string $provider Provider key.
203 * @param array $drawer_options Drawer options.
204 *
205 * @return array{auto_open_drawer:bool, drawer_connector:string}
206 */
207 private static function drawer_options_for_provider( string $provider, array $drawer_options ): array {
208 if ( ! in_array( $provider, array( 'epson-sdp', 'printnode' ), true ) ) {
209 return array(
210 'auto_open_drawer' => false,
211 'drawer_connector' => 'pin2',
212 );
213 }
214
215 return array(
216 'auto_open_drawer' => ! empty( $drawer_options['auto_open_drawer'] ),
217 'drawer_connector' => Print_Job_Service::normalize_drawer_connector( (string) ( $drawer_options['drawer_connector'] ?? 'pin2' ) ),
218 );
219 }
220
221 /**
222 * Whether an assignment scope applies to this order origin.
223 *
224 * @param string $scope every|pos|online.
225 * @param bool $is_pos Whether the order was created via the POS.
226 */
227 private function scope_matches( string $scope, bool $is_pos ): bool {
228 if ( 'every' === $scope ) {
229 return true;
230 }
231 if ( 'pos' === $scope ) {
232 return $is_pos;
233 }
234 if ( 'online' === $scope ) {
235 return ! $is_pos;
236 }
237
238 return false;
239 }
240
241 /**
242 * Guard against duplicate jobs for the same order+printer+template.
243 *
244 * @param int $order_id Order ID.
245 * @param string $printer_id Printer ID.
246 * @param string $template_id Template ID.
247 */
248 private function already_queued( int $order_id, string $printer_id, string $template_id ): bool {
249 $existing = $this->jobs->query(
250 array(
251 'printer_id' => $printer_id,
252 'order_id' => $order_id,
253 'template_id' => $template_id,
254 'limit' => 1,
255 )
256 );
257
258 return ! empty( $existing );
259 }
260 }
261