PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.18
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.18
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
← All changes | includes/API/V2/Write_Controller.php +61 -15 1.10.191.10.18 View file →
@@ -11,9 +11,8 @@
11 11 use WCPOS\WooCommercePOS\Services\Permission_Rules;
12 12 use WCPOS\WooCommercePOS\Services\Tax_Id_Types;
13 13 use WCPOS\WooCommercePOS\Sync\Api;
14 14 use WCPOS\WooCommercePOS\Sync\Collections;
15 -use WCPOS\WooCommercePOS\Sync\Create_Identity;
16 15 use WCPOS\WooCommercePOS\Sync\Endpoint_Permissions;
17 16 use WCPOS\WooCommercePOS\Sync\Header_Mirror;
18 17 use WCPOS\WooCommercePOS\Sync\Meta_Normalizer;
19 18 use WCPOS\WooCommercePOS\Sync\Mutation_Store;
@@ -53,12 +52,9 @@
53 52
54 53 /** @var mixed Duck-typed mutation store; tests inject an in-memory implementation. */
55 54 private $store;
56 55
57 - /** @var Create_Identity Shared proof for fresh and poisoned creates. */
58 - private Create_Identity $identity;
59 56
60 -
61 57 /**
62 58 * collection => wc/v3 route + how its uuid→id is resolved. ONE table, not
63 59 * per-collection controllers. Only collections whose resolver is correct AND
64 60 * exercised are exposed; the rest stay out until their phase:
@@ -103,9 +99,8 @@
103 99 }
104 100
105 101 public function __construct( $store = null ) {
106 102 $this->store = $store ? $store : new Mutation_Store();
107 - $this->identity = new Create_Identity( $this->store );
108 103 }
109 104
110 105 /** Resolve the collection-specific writer for registry metadata. */
111 106 private function writer( array $meta ) {
@@ -225,14 +220,9 @@
225 220 return $mismatch;
226 221 }
227 222 }
228 223 if ( is_array( $hit ) && 'poison' === ( $hit['status'] ?? '' ) ) {
229 - $writer = $this->writer( $meta );
230 - $recovered = $this->identity->recover( $meta, $m, $hit, $writer );
231 - if ( is_wp_error( $recovered ) ) {
232 - return $recovered;
233 - }
234 - return $this->envelope_document( $this->document_for( $meta, $recovered['id'] ), $m['recordId'], $meta, $recovered['id'], $recovered['status'], $writer );
224 + return $this->retry_identity_stamp( $meta, $m, $hit );
235 225 }
236 226 if ( is_array( $hit ) && in_array( ( $hit['status'] ?? '' ), array( 'done', 'applied' ), true ) ) {
237 227 if ( 'applied' === $hit['status'] && ! $this->store->finalize( $m['mutationId'], (int) $hit['remote_id'] ) ) {
238 228 return $this->finalize_error();
@@ -416,12 +406,33 @@
416 406 $this->store->mark_indeterminate( $m['mutationId'], 0, $response->get_status() );
417 407 return new WP_Error( 'woo_rxdb_sync_create_no_id', 'Create returned no server id.', array( 'status' => 502 ) );
418 408 }
419 409
420 - $stamped = $this->identity->stamp( $meta, $m, $new_id, $response->get_status(), $writer );
421 - if ( is_wp_error( $stamped ) ) {
422 - return $stamped;
410 + // Poison checkpoint, UUID persistence, and finalization remain shared here.
411 + $checkpointed = $this->store->mark_poison( $m['mutationId'], $new_id, $response->get_status() );
412 + $writer->persist( 'create_before_identity', $new_id, $m['payload'] );
413 + $identity_error = null;
414 + if ( ! $this->store->persist_uuid( $meta['id_type'], $new_id, $m['recordId'] ) ) {
415 + $identity_error = new WP_Error( 'woo_rxdb_sync_identity_persistence_failed', 'Unable to persist created record identity.', array( 'status' => 500 ) );
416 + } else {
417 + $resolved = $this->store->resolve_id_by_uuid( $meta['id_type'], $m['recordId'], $meta );
418 + if ( is_wp_error( $resolved ) ) {
419 + $identity_error = $resolved;
420 + } elseif ( $resolved !== $new_id ) {
421 + $identity_error = new WP_Error( 'woo_rxdb_sync_identity_persistence_failed', 'Unable to persist created record identity.', array( 'status' => 500 ) );
422 + }
423 423 }
424 + if ( ! $checkpointed ) {
425 + $this->store->mark_indeterminate( $m['mutationId'], $new_id, $response->get_status() );
426 + return $this->finalize_error();
427 + }
428 + if ( $identity_error ) {
429 + return $identity_error;
430 + }
431 + $writer->persist( 'create_after_identity', $new_id, $m['payload'] );
432 + if ( ! $this->store->finalize_poison( $m['mutationId'], $new_id ) ) {
433 + return $this->finalize_error();
434 + }
424 435 return $this->envelope_document( $this->document_for( $meta, $new_id ), $m['recordId'], $meta, $new_id, $response->get_status(), $writer );
425 436 }
426 437
427 438 /**
@@ -508,9 +519,9 @@
508 519 if ( $response->get_status() >= 400 ) {
509 520 return new WP_REST_Response( $response->get_data(), $response->get_status() );
510 521 }
511 522 $data = $response->get_data();
512 - $writer->after_update( $id, $m['payload'], $current_bare, is_array( $data ) ? $data : array(), $prepared['context'] );
523 + $writer->persist( 'update', $id, $m['payload'], $current_bare, is_array( $data ) ? $data : array(), $prepared['context'] );
513 524
514 525 $this->store->persist_uuid( $meta['id_type'], $id, $m['recordId'] );
515 526 $finalized = $this->checkpoint_and_finalize( $m['mutationId'], $id, $response->get_status() );
516 527 if ( is_wp_error( $finalized ) ) {
@@ -628,8 +639,43 @@
628 639 ? (int) $hit['response_status']
629 640 : ( 'create' === ( $hit['operation'] ?? '' ) ? 201 : null );
630 641 $writer = $this->writer( $meta );
631 642 return $this->envelope_document( $this->document_for( $meta, $remote_id ), $expected, $meta, $remote_id, $status, $writer );
643 + }
644 +
645 + private function retry_identity_stamp( array $meta, array $m, array $hit ) {
646 + $remote_id = (int) ( $hit['remote_id'] ?? 0 );
647 + $record_uuid = (string) ( $hit['record_uuid'] ?? '' );
648 + if ( $record_uuid !== $m['recordId'] ) {
649 + return new WP_Error( 'woo_rxdb_sync_identity_conflict', 'recordId disagrees with the stored mutation identity.', array( 'status' => 422 ) );
650 + }
651 + if ( 'create' !== ( $hit['operation'] ?? '' ) || $remote_id <= 0 ) {
652 + return new WP_Error( 'woo_rxdb_sync_identity_persistence_failed', 'Created record identity cannot be recovered safely.', array( 'status' => 500 ) );
653 + }
654 + $resolved = $this->store->resolve_id_by_uuid( $meta['id_type'], $record_uuid, $meta );
655 + if ( is_wp_error( $resolved ) ) {
656 + return $resolved;
657 + }
658 + if ( $resolved > 0 && $resolved !== $remote_id ) {
659 + return new WP_Error( 'woo_rxdb_sync_identity_persistence_failed', 'Stored create identity points at a different record.', array( 'status' => 500 ) );
660 + }
661 + if ( ! $this->store->persist_uuid( $meta['id_type'], $remote_id, $record_uuid ) ) {
662 + return new WP_Error( 'woo_rxdb_sync_identity_persistence_failed', 'Unable to persist created record identity.', array( 'status' => 500 ) );
663 + }
664 + $verified = $this->store->resolve_id_by_uuid( $meta['id_type'], $record_uuid, $meta );
665 + if ( is_wp_error( $verified ) ) {
666 + return $verified;
667 + }
668 + if ( $verified !== $remote_id ) {
669 + return new WP_Error( 'woo_rxdb_sync_identity_persistence_failed', 'Unable to persist created record identity.', array( 'status' => 500 ) );
670 + }
671 + $writer = $this->writer( $meta );
672 + $writer->persist( 'create_recovery', $remote_id, $m['payload'] );
673 + if ( ! $this->store->finalize_poison( $m['mutationId'], $remote_id ) ) {
674 + return $this->finalize_error();
675 + }
676 + $status = isset( $hit['response_status'] ) ? (int) $hit['response_status'] : 201;
677 + return $this->envelope_document( $this->document_for( $meta, $remote_id ), $record_uuid, $meta, $remote_id, $status, $writer );
632 678 }
633 679
634 680 /**
635 681 * Validate a client-submitted `tax_ids` payload against the v1 schema.