builder = $builder; $this->repository = $repository; $this->activityLog = $activityLog; } public function registerRoutes(): void { register_rest_route( self::NAMESPACE, '/stock-sync', [ 'methods' => 'POST', 'callback' => [ $this, 'create' ], 'permission_callback' => [ $this, 'authorize' ], ] ); register_rest_route( self::NAMESPACE, '/stock-sync', [ 'methods' => 'GET', 'callback' => [ $this, 'lookup' ], 'permission_callback' => [ $this, 'authorize' ], 'args' => [ 'pos_order_id' => [ 'required' => true ], ], ] ); } public function authorize(): bool { return current_user_can( 'manage_woocommerce' ); } /** * GET /stock-sync?pos_order_id=X — lets akantio_pos check whether this * POS order's stock delta was already applied before attempting to push * it again, so a broken local sync record doesn't double-decrement * WooCommerce's stock (POST is idempotent by itself too, see * StockSyncBuilder::build(), but this lets the caller skip the push * entirely and just reconcile its own state). */ public function lookup( WP_REST_Request $request ) { $posOrderId = (string) $request->get_param( 'pos_order_id' ); if ( '' === $posOrderId ) { return new WP_Error( 'akantio_woo_missing_pos_order_id', 'pos_order_id is required.', [ 'status' => 400 ] ); } $existing = $this->repository->findByPosOrderId( $posOrderId ); if ( null === $existing ) { return new WP_Error( 'akantio_woo_stock_sync_not_found', 'No stock sync found for this pos_order_id.', [ 'status' => 404 ] ); } return new WP_REST_Response( [ 'pos_order_id' => $posOrderId, 'synced_at' => $existing['synced_at'], ], 200 ); } public function create( WP_REST_Request $request ) { $data = $request->get_json_params(); if ( ! is_array( $data ) ) { return new WP_Error( 'akantio_woo_invalid_body', 'Request body must be a JSON object.', [ 'status' => 400 ] ); } try { $payload = StockSyncPayload::fromArray( $data ); } catch ( InvalidArgumentException $e ) { return new WP_Error( 'akantio_woo_invalid_payload', $e->getMessage(), [ 'status' => 400 ] ); } try { $result = $this->builder->build( $payload ); } catch ( RuntimeException $e ) { return new WP_Error( 'akantio_woo_stock_sync_failed', $e->getMessage(), [ 'status' => 500 ] ); } if ( $result['applied'] ) { $this->activityLog->record( 'stock_synced', [ 'pos_order_id' => $payload->posOrderId(), 'product_ids' => array_column( $payload->productUpdates(), 'product_id' ), ] ); } return new WP_REST_Response( $result, $result['applied'] ? 201 : 200 ); } }