PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.17
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.17
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 1.9.13 All 162 releases
woocommerce-pos / includes / API / V1 / Receipts_Controller.php

Receipts_Controller.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.17, at includes/API/V1/Receipts_Controller.php

243 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Receipts REST controller.
4 *
5 * @package WCPOS\WooCommercePOS\API\V1
6 */
7
8 namespace WCPOS\WooCommercePOS\API\V1;
9
10 use WCPOS\WooCommercePOS\Logger;
11 use WCPOS\WooCommercePOS\Services\Print_Job_Service;
12 use WCPOS\WooCommercePOS\Services\Receipt_Data_Builder;
13 use WCPOS\WooCommercePOS\Services\Receipt_Snapshot_Store;
14 use WCPOS\WooCommercePOS\Services\Fiscal_Receipt_Service;
15 use WCPOS\WooCommercePOS\Services\Template_Pdf_Service;
16 use WP_Error;
17 use WP_REST_Controller;
18 use WP_REST_Request;
19 use WP_REST_Server;
20
21 use const WCPOS\WooCommercePOS\SHORT_NAME;
22
23 /**
24 * Receipts_Controller class.
25 */
26 class Receipts_Controller extends WP_REST_Controller {
27 /**
28 * Endpoint namespace.
29 *
30 * @var string
31 */
32 protected $namespace = SHORT_NAME . '/v1';
33
34 /**
35 * Route base.
36 *
37 * @var string
38 */
39 protected $rest_base = 'receipts';
40
41 /**
42 * Declare routes with special permission-gate handling.
43 *
44 * @return array<string, string[]> Route classifications.
45 */
46 public function wcpos_route_classifications(): array {
47 return array(
48 'permission_error_passthrough' => array( "/{$this->namespace}/{$this->rest_base}/" ),
49 );
50 }
51
52 /**
53 * Register routes.
54 */
55 public function register_routes(): void {
56 register_rest_route(
57 $this->namespace,
58 '/' . $this->rest_base . '/(?P<order_id>[\\d]+)',
59 array(
60 'methods' => WP_REST_Server::READABLE,
61 'callback' => array( $this, 'get_item' ),
62 'permission_callback' => array( $this, 'get_item_permissions_check' ),
63 'args' => array(
64 'order_id' => array(
65 'type' => 'integer',
66 'required' => true,
67 'sanitize_callback' => 'absint',
68 ),
69 'mode' => array(
70 'type' => 'string',
71 'required' => false,
72 'enum' => array( 'fiscal', 'live' ),
73 'sanitize_callback' => 'sanitize_text_field',
74 ),
75 ),
76 )
77 );
78
79 register_rest_route(
80 $this->namespace,
81 '/' . $this->rest_base . '/(?P<order_id>[\\d]+)/pdf',
82 array(
83 'methods' => WP_REST_Server::READABLE,
84 'callback' => array( $this, 'get_pdf' ),
85 'permission_callback' => array( $this, 'get_item_permissions_check' ),
86 'args' => array(
87 'order_id' => array(
88 'type' => 'integer',
89 'required' => true,
90 'sanitize_callback' => 'absint',
91 ),
92 'template_id' => array(
93 'type' => 'string',
94 'required' => true,
95 'sanitize_callback' => 'sanitize_text_field',
96 ),
97 ),
98 )
99 );
100 }
101
102 /**
103 * Get receipt payload for an order.
104 *
105 * @param WP_REST_Request $request Request object.
106 *
107 * @return array|WP_Error
108 */
109 public function get_item( $request ) {
110 $order_id = (int) $request->get_param( 'order_id' );
111 $order = wc_get_order( $order_id );
112
113 if ( ! $order ) {
114 return new WP_Error(
115 'wcpos_receipt_invalid_order',
116 /* translators: REST API schema field label or error message. */
117 __( 'Invalid order.', 'woocommerce-pos' ),
118 array( 'status' => 404 )
119 );
120 }
121
122 $snapshot_store = Receipt_Snapshot_Store::instance();
123 $requested_mode = $request->get_param( 'mode' );
124 if ( null !== $requested_mode && ! \in_array( $requested_mode, array( 'fiscal', 'live' ), true ) ) {
125 return new WP_Error(
126 'wcpos_receipt_invalid_mode',
127 /* translators: REST API schema field label or error message. */
128 __( 'Invalid receipt mode.', 'woocommerce-pos' ),
129 array( 'status' => 400 )
130 );
131 }
132
133 $mode = $snapshot_store->resolve_mode( $requested_mode );
134 $payload = null;
135
136 if ( 'fiscal' === $mode ) {
137 $payload = $snapshot_store->get_snapshot( $order_id );
138 if ( ! $payload ) {
139 return new WP_Error(
140 'wcpos_receipt_snapshot_missing',
141 __( 'No fiscal snapshot found for this order.', 'woocommerce-pos' ),
142 array( 'status' => 404 )
143 );
144 }
145 } else {
146 $payload = ( new Receipt_Data_Builder() )->build( $order, 'live' );
147 }
148
149 return array(
150 'order_id' => $order_id,
151 'mode' => $mode,
152 'has_snapshot' => $snapshot_store->has_snapshot( $order_id ),
153 'submission_status' => ( new Fiscal_Receipt_Service() )->get_submission_status( $order_id ),
154 'data' => $payload,
155 );
156 }
157
158 /**
159 * Get receipt PDF bytes for an order.
160 *
161 * @param WP_REST_Request $request Request object.
162 *
163 * @return Raw_Response|WP_Error
164 */
165 public function get_pdf( $request ) {
166 $order = wc_get_order( (int) $request['order_id'] );
167 if ( ! $order ) {
168 return new WP_Error(
169 'wcpos_receipt_order_not_found',
170 __( 'Order not found.', 'woocommerce-pos' ),
171 array( 'status' => 404 )
172 );
173 }
174
175 $template_id = trim( (string) $request->get_param( 'template_id' ) );
176 if ( '' === $template_id ) {
177 return new WP_Error(
178 'wcpos_receipt_missing_template',
179 __( 'A template_id is required.', 'woocommerce-pos' ),
180 array( 'status' => 400 )
181 );
182 }
183
184 $template = Print_Job_Service::load_template( $template_id );
185 if ( null === $template ) {
186 return new WP_Error(
187 'wcpos_receipt_template_not_found',
188 __( 'Template not found.', 'woocommerce-pos' ),
189 array( 'status' => 404 )
190 );
191 }
192
193 try {
194 $pdf = ( new Template_Pdf_Service() )->render( $template, $order );
195 } catch ( \Throwable $e ) {
196 Logger::log( sprintf( 'Receipt PDF render failed for order %d: %s', $order->get_id(), $e->getMessage() ) );
197
198 return new WP_Error(
199 'wcpos_receipt_pdf_failed',
200 __( 'Could not generate the receipt PDF.', 'woocommerce-pos' ),
201 array( 'status' => 500 )
202 );
203 }
204
205 if ( '' === $pdf ) {
206 return new WP_Error(
207 'wcpos_receipt_pdf_empty',
208 __( 'Could not generate the receipt PDF.', 'woocommerce-pos' ),
209 array( 'status' => 500 )
210 );
211 }
212
213 return Raw_Response::serve(
214 $pdf,
215 'application/pdf',
216 array(
217 'Content-Disposition' => sprintf( 'attachment; filename="receipt-%d.pdf"', $order->get_id() ),
218 'Content-Length' => (string) \strlen( $pdf ),
219 'Cache-Control' => 'no-store',
220 )
221 );
222 }
223
224 /**
225 * Permissions check.
226 *
227 * @param WP_REST_Request $request Request object.
228 *
229 * @return bool|WP_Error
230 */
231 public function get_item_permissions_check( $request ) {
232 if ( ! current_user_can( 'access_woocommerce_pos' ) ) {
233 return new WP_Error(
234 'wcpos_rest_insufficient_permissions',
235 __( 'Sorry, you cannot view receipts.', 'woocommerce-pos' ),
236 array( 'status' => 403 )
237 );
238 }
239
240 return true;
241 }
242 }
243