PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.19
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.19
1.10.20 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 All 164 releases
← All changes | includes/API/V2/Writers/Order_Writer.php +47 -91 1.10.10 → 1.10.19 View file →
@@ -9,12 +9,12 @@
9 9
10 10 namespace WCPOS\WooCommercePOS\API\V2\Writers;
11 11
12 12 use WCPOS\WooCommercePOS\Services\Order_Notes;
13 +use WCPOS\WooCommercePOS\Services\Order_Write_Intent;
13 14 use WCPOS\WooCommercePOS\Services\Pos_Order_Audit;
14 15 use WCPOS\WooCommercePOS\Services\Settings as SettingsService;
15 16 use WCPOS\WooCommercePOS\Services\Stock_Validator;
16 -use WCPOS\WooCommercePOS\Services\Tax_Id_Writer;
17 17 use WCPOS\WooCommercePOS\Sync\Meta_Entry;
18 18 use WCPOS\WooCommercePOS\Sync\Order_Serializer;
19 19 use WCPOS\WooCommercePOS\Sync\Order_Write_Payload;
20 20 use WCPOS\WooCommercePOS\Sync\Pos_Uuid;
@@ -45,9 +45,9 @@
45 45 }
46 46
47 47 /** Prepare an order create and its create-only hook policy. */
48 48 public function prepare_create( array $meta, array $payload, callable $validate_tax_ids ) {
49 - $created_gmt = $this->validate_client_created_gmt( $payload );
49 + $created_gmt = $this->order_payload->validate_client_created_gmt( $payload );
50 50 if ( is_wp_error( $created_gmt ) ) {
51 51 return $created_gmt;
52 52 }
53 53 $error = $validate_tax_ids( $payload );
@@ -119,9 +119,21 @@
119 119 }
120 120
121 121 /** Forward within the named order hook lifecycle. */
122 122 public function forward( array $prepared, callable $forward ) {
123 - return $this->forward_with_reserved_stock( $prepared, $forward );
123 + $declared = $prepared['context'];
124 + if ( ! in_array( $declared['operation'] ?? '', array( 'create', 'update' ), true ) ) {
125 + return $this->forward_with_reserved_stock( $prepared, $forward );
126 + }
127 + $payload = $prepared['payload'];
128 + $declared['requested_status'] = isset( $payload['status'] ) ? (string) $payload['status'] : '';
129 + $declared['set_paid'] = isset( $payload['set_paid'] ) && rest_sanitize_boolean( $payload['set_paid'] );
130 + return Order_Write_Intent::open(
131 + $declared,
132 + function () use ( $prepared, $forward ) {
133 + return $this->forward_with_reserved_stock( $prepared, $forward );
134 + }
135 + );
124 136 }
125 137
126 138 /**
127 139 * Wrap the create forward in the shared create-pending -> reserve -> complete
@@ -176,32 +188,39 @@
176 188 // right, and it is the same order throughout.
177 189 return $response;
178 190 }
179 191
180 - /** Persist the order behavior assigned to a controller-owned protocol phase. */
181 - public function persist( string $phase, int $id, array $payload, array $current = array(), array $response_data = array(), array $context = array() ): void {
182 - if ( 'create_before_identity' === $phase ) {
183 - $this->persist_tax_ids( $id, $payload, true );
184 - } elseif ( 'create_after_identity' === $phase ) {
185 - $this->stamp_order_audit( $id, $payload, true );
192 + /** Persist tax IDs before the identity proof. */
193 + public function after_create( int $id, array $payload ): void {
194 + $this->order_payload->persist_tax_ids( $id, $payload, true );
195 + }
196 +
197 + /** Stamp audit metadata and add the creation note after the identity proof. */
198 + public function after_identity( int $id, array $payload ): void {
199 + $this->stamp_order_audit( $id, $payload, true );
200 + $order = wc_get_order( $id );
201 + if ( $order ) {
202 + Order_Notes::add_creation_note( $order, get_current_user_id(), $order->get_meta( '_pos_store' ) );
203 + }
204 + }
205 +
206 + /** Restore audit metadata and tax IDs after recovery. */
207 + public function after_recovery( int $id, array $payload ): void {
208 + $this->stamp_order_audit( $id, $payload, false );
209 + $this->order_payload->persist_tax_ids( $id, $payload, true );
210 + }
211 +
212 + /** Persist till metadata, tax IDs, reassignment, and email changes after update. */
213 + public function after_update( int $id, array $payload, array $current, array $response_data, array $context ): void {
214 + $this->stamp_order_till_meta( $id, $payload );
215 + $this->order_payload->persist_tax_ids( $id, $payload, false );
216 + $this->persist_cashier_store_reassignment( $id, $current, $response_data, $context );
217 + if ( ! empty( $context['clear_email'] ) ) {
186 218 $order = wc_get_order( $id );
187 219 if ( $order ) {
188 - Order_Notes::add_creation_note( $order, get_current_user_id(), $order->get_meta( '_pos_store' ) );
220 + $order->set_billing_email( '' );
221 + $order->get_data_store()->update( $order );
189 222 }
190 - } elseif ( 'create_recovery' === $phase ) {
191 - $this->stamp_order_audit( $id, $payload, false );
192 - $this->persist_tax_ids( $id, $payload, true );
193 - } elseif ( 'update' === $phase ) {
194 - $this->stamp_order_till_meta( $id, $payload );
195 - $this->persist_tax_ids( $id, $payload, false );
196 - $this->persist_cashier_store_reassignment( $id, $current, $response_data, $context );
197 - if ( ! empty( $context['clear_email'] ) ) {
198 - $order = wc_get_order( $id );
199 - if ( $order ) {
200 - $order->set_billing_email( '' );
201 - $order->get_data_store()->update( $order );
202 - }
203 - }
204 223 }
205 224 }
206 225
207 226 /** Execute delete with the named stock restore/rollback lifecycle. */
@@ -237,35 +256,15 @@
237 256 }
238 257
239 258 /** Apply create/update hook policies around one exact forwarded order. */
240 259 private function forward_with_order_lifecycle( array $prepared, callable $forward ) {
241 - $context = $prepared['context'];
242 - $forwarded_order = null;
243 - $pre_insert = static function ( $order, $request, $creating ) use ( $context, &$forwarded_order ) {
244 - $is_create = 'create' === $context['operation'];
245 - if ( $is_create && $creating && $order instanceof \WC_Order && null === $forwarded_order ) {
246 - $forwarded_order = $order;
247 - }
248 - $target = $is_create ? ( $creating && $order === $forwarded_order ) : ( $order instanceof \WC_Order && $context['id'] === $order->get_id() );
249 - if ( $target ) {
250 - foreach ( $context['fill_meta'] as $key => $value ) {
251 - $order->update_meta_data( $key, $value );
252 - }
253 - }
254 - if ( $is_create && $creating && null !== $context['created_gmt'] && $order instanceof \WC_Order ) {
255 - $order->set_date_created( $context['created_gmt'] );
256 - }
257 - return $order;
258 - };
259 - $created_via = static function ( $order ) use ( &$forwarded_order ) {
260 - if ( $order instanceof \WC_Order && $order === $forwarded_order && 'woocommerce-pos' !== $order->get_created_via() ) {
260 + $context = $prepared['context'];
261 + $created_via = static function ( $order ) {
262 + $intent = Order_Write_Intent::current();
263 + if ( $order instanceof \WC_Order && null !== $intent && $intent->is_subject( $order ) && 'woocommerce-pos' !== $order->get_created_via() ) {
261 264 $order->set_created_via( 'woocommerce-pos' );
262 265 }
263 266 };
264 - $use_filter = 'create' === $context['operation'] || array() !== $context['fill_meta'];
265 - if ( $use_filter ) {
266 - add_filter( 'woocommerce_rest_pre_insert_shop_order_object', $pre_insert, 10, 3 );
267 - }
268 267 if ( 'create' === $context['operation'] ) {
269 268 add_action( 'woocommerce_before_order_object_save', $created_via );
270 269 }
271 270 try {
@@ -270,11 +269,8 @@
270 269 }
271 270 try {
272 271 return $forward( $prepared['method'], $prepared['route'], $prepared['payload'] );
273 272 } finally {
274 - if ( $use_filter ) {
275 - remove_filter( 'woocommerce_rest_pre_insert_shop_order_object', $pre_insert, 10 );
276 - }
277 273 if ( 'create' === $context['operation'] ) {
278 274 remove_action( 'woocommerce_before_order_object_save', $created_via );
279 275 }
280 276 }
@@ -403,21 +399,8 @@
403 399 Order_Notes::add_pos_customer_change_note( $order, $current['customer_id'], $data['customer_id'] );
404 400 }
405 401 }
406 402
407 - /** Persist order tax IDs or the create-time customer snapshot. */
408 - private function persist_tax_ids( int $id, array $payload, bool $is_create ): void {
409 - $order = wc_get_order( $id );
410 - if ( ! $order ) {
411 - return;
412 - }
413 - if ( is_array( $payload['tax_ids'] ?? null ) ) {
414 - ( new Tax_Id_Writer() )->write_for_order( $order, $payload['tax_ids'] );
415 - } elseif ( $is_create && $order->get_customer_id() > 0 ) {
416 - ( new Tax_Id_Writer() )->snapshot_from_user_to_order( $order, $order->get_customer_id() );
417 - }
418 - }
419 -
420 403 /** Persist server-owned order audit metadata. */
421 404 private function stamp_order_audit( int $id, array $payload, bool $stamp_version ): void {
422 405 $meta = array( '_pos_user' => (string) get_current_user_id() );
423 406 // Create-shaped phases only (create_after_identity, create_recovery, the
@@ -454,35 +437,8 @@
454 437 private function without_pos_audit_meta( array $payload, int $id = 0 ): array {
455 438 $meta = is_array( $payload['meta_data'] ?? null ) ? $payload['meta_data'] : array();
456 439 $protected = $id > 0 ? Pos_Order_Audit::audit_meta_ids( wc_get_order( $id ) ) : array();
457 440 return Pos_Order_Audit::strip_audit_meta( $meta, $protected );
458 - }
459 -
460 - /** Validate and normalize the optional client create timestamp. */
461 - private function validate_client_created_gmt( array $payload ) {
462 - if ( ! isset( $payload['date_created_gmt'] ) ) {
463 - return null;
464 - }
465 - if ( ! is_scalar( $payload['date_created_gmt'] ) ) {
466 - return $this->invalid_created_gmt();
467 - }
468 - $value = wc_clean( wp_unslash( (string) $payload['date_created_gmt'] ) );
469 - if ( '' === $value ) {
470 - return null;
471 - }
472 - $timestamp = 1 === preg_match( '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?$/i', $value )
473 - ? rest_parse_date( 'Z' === strtoupper( substr( $value, -1 ) ) ? $value : $value . 'Z', true ) : false;
474 - if ( false === $timestamp ) {
475 - return $this->invalid_created_gmt();
476 - }
477 - return $timestamp > time() + DAY_IN_SECONDS
478 - ? new WP_Error( 'woocommerce_pos_rest_future_date_created_gmt', __( 'date_created_gmt cannot be more than 24 hours in the future.', 'woocommerce-pos' ), array( 'status' => 400 ) )
479 - : $timestamp;
480 - }
481 -
482 - /** Build the stable invalid create timestamp error. */
483 - private function invalid_created_gmt(): WP_Error {
484 - return new WP_Error( 'woocommerce_pos_rest_invalid_date_created_gmt', __( 'date_created_gmt must be a valid ISO 8601 UTC date.', 'woocommerce-pos' ), array( 'status' => 400 ) );
485 441 }
486 442
487 443 /** Whether order stock was actually reduced before delete. */
488 444 private function order_stock_reduced( int $id ): bool {