PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.21
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.21
1.10.22 1.10.21 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 All 166 releases
← All changes | includes/API/V1/Orders_Controller.php +32 -157 1.10.18 → 1.10.21 View file →
@@ -21,9 +21,8 @@
21 21 use WC_Email_Customer_Invoice;
22 22 use WC_Order;
23 23 use WC_Order_Item;
24 24 use WC_Order_Item_Fee;
25 -use WC_Order_Item_Product;
26 25 use WC_REST_Orders_Controller;
27 26 use WC_Tax;
28 27 use WCPOS\WooCommercePOS\Logger;
29 28 use WCPOS\WooCommercePOS\Services\Order_Write_Intent;
@@ -308,8 +307,10 @@
308 307 }
309 308
310 309 /**
311 310 * Add custom fields to the order schema.
311 + *
312 + * Email, nullable parent_name, and decimal quantity relaxations let raw POS documents pass validation before payload shaping.
312 313 */
313 314 public function get_item_schema() {
314 315 $schema = parent::get_item_schema();
315 316
@@ -413,8 +414,10 @@
413 414 if ( isset( $request['meta_data'] ) && \is_array( $request['meta_data'] ) ) {
414 415 $request->set_param( 'meta_data', Pos_Order_Audit::sanitize_create_meta( $request['meta_data'] ) );
415 416 }
416 417
418 + $this->wcpos_shape_request_payload( $request, $this->order_payload->for_create( $request->get_params() ) );
419 +
417 420 $response = Order_Write_Intent::open(
418 421 array(
419 422 'operation' => 'create',
420 423 'requested_status' => (string) $request->get_param( 'status' ),
@@ -488,10 +491,21 @@
488 491 )
489 492 );
490 493 }
491 494
492 - // Proceed with the parent method to handle the update.
493 - $response = parent::update_item( $request );
495 + $this->wcpos_shape_request_payload( $request, $this->order_payload->for_partial_update( (int) $request['id'], $request->get_params() ) );
496 +
497 + $response = Order_Write_Intent::open(
498 + array(
499 + 'operation' => 'update',
500 + 'id' => (int) $request['id'],
501 + 'requested_status' => (string) $request->get_param( 'status' ),
502 + 'set_paid' => $request->has_param( 'set_paid' ) && rest_sanitize_boolean( $request->get_param( 'set_paid' ) ),
503 + ),
504 + function () use ( $request ) {
505 + return parent::update_item( $request );
506 + }
507 + );
494 508 $this->wcpos_refresh_tax_ids_response( $response, $request, false );
495 509
496 510 return $response;
497 511 }
@@ -496,8 +510,23 @@
496 510 return $response;
497 511 }
498 512
499 513 /**
514 + * Replace the request fields touched by the shared payload shaper.
515 + *
516 + * @param WP_REST_Request $request Validated request.
517 + * @param array $shaped Shaped create or partial-update payload.
518 + */
519 + private function wcpos_shape_request_payload( WP_REST_Request $request, array $shaped ): void {
520 + // Neither for_create nor for_partial_update removes a top-level key; present-key replacement is sufficient.
521 + foreach ( array( 'billing', 'line_items', 'shipping_lines', 'fee_lines', 'coupon_lines', 'meta_data' ) as $key ) {
522 + if ( array_key_exists( $key, $shaped ) ) {
523 + $request->set_param( $key, $shaped[ $key ] );
524 + }
525 + }
526 + }
527 +
528 + /**
500 529 * Adapt the parent response to the shared snapshot and refresh its tax_ids.
501 530 *
502 531 * @param mixed $response Response from parent controller.
503 532 * @param WP_REST_Request $request Original request.
@@ -520,139 +549,8 @@
520 549 }
521 550 }
522 551
523 552 /**
524 - * Create or update a line item.
525 - *
526 - * @param array $posted Line item data.
527 - * @param string $action 'create' to add line item or 'update' to update it.
528 - * @param object $item Passed when updating an item. Null during creation.
529 - *
530 - * @throws \WC_REST_Exception Invalid data, server error.
531 - *
532 - * @return WC_Order_Item_Product
533 - */
534 - public function prepare_line_items( $posted, $action = 'create', $item = null ) {
535 - $item = parent::prepare_line_items( $posted, $action, $item );
536 -
537 - /**
538 - * If you send a variation with meta_data, the meta_data will be duplicated
539 - * WooCommerce attempts to delete the duped meta_data in $item->set_product( $variation )
540 - * but later it gets added right back in $this->maybe_set_item_meta_data.
541 - *
542 - * To fix this we check for a variation_id and remove the meta_data before setting the product
543 - */
544 - if ( 'create' !== $action && $item->get_variation_id() ) {
545 - $attributes = wc_get_product_variation_attributes( $item->get_variation_id() );
546 -
547 - // Loop through attributes and remove any duplicates.
548 - foreach ( $attributes as $key => $value ) {
549 - $attribute = str_replace( 'attribute_', '', $key );
550 - $meta_data = $item->get_meta( $attribute, false );
551 -
552 - if ( \is_array( $meta_data ) && \count( $meta_data ) > 1 ) {
553 - $meta_to_keep = null;
554 -
555 - // Check each meta to find one with an ID to keep.
556 - foreach ( $meta_data as $meta ) {
557 - if ( isset( $meta->id ) ) {
558 - $meta_to_keep = $meta;
559 -
560 - break;
561 - }
562 - }
563 -
564 - // If no meta with an ID is found, keep the first one.
565 - if ( ! $meta_to_keep ) {
566 - $meta_to_keep = $meta_data[0];
567 - }
568 -
569 - // Remove all other meta data for this attribute.
570 - foreach ( $meta_data as $meta ) {
571 - if ( $meta !== $meta_to_keep ) {
572 - if ( $meta->id ) {
573 - $item->delete_meta_data_by_mid( $meta->id );
574 - } else {
575 - $meta->value = null;
576 - }
577 - }
578 - }
579 - }
580 - }
581 - }
582 -
583 - return $item;
584 - }
585 -
586 - /**
587 - * Maybe set item meta if posted.
588 - *
589 - * @param WC_Order_Item $item Order item data.
590 - * @param array $posted Request data.
591 - */
592 - public function maybe_set_item_meta_data( $item, $posted ): void {
593 - /*
594 - * Call the parent method first to handle standard meta data
595 - * This will populate the attribute key, eg: 'pa_color' or 'logo'
596 - * BUT: if the attribute can be 'any' then we need to handle that
597 - */
598 - parent::maybe_set_item_meta_data( $item, $posted );
599 -
600 - // Ensure this is a product line item, not a fee or shipping.
601 - if ( ! \is_object( $item ) || 'WC_Order_Item_Product' !== \get_class( $item ) ) {
602 - return;
603 - }
604 -
605 - // SKU meta is not stored by default, we will add it for 'miscellaneous' products.
606 - if ( isset( $posted['sku'] ) && 0 === $item->get_product_id() ) {
607 - $item->add_meta_data( '_sku', $posted['sku'], true );
608 - }
609 -
610 - // Only proceed if there's a variation ID and we have posted meta.
611 - if ( ! $item->get_variation_id() || empty( $posted['meta_data'] ) || ! \is_array( $posted['meta_data'] ) ) {
612 - return;
613 - }
614 -
615 - $attributes = wc_get_product_variation_attributes( $item->get_variation_id() );
616 - $product_id = $item->get_product_id();
617 - $product = wc_get_product( $product_id );
618 - $parent_attributes = $product->get_attributes();
619 -
620 - foreach ( $attributes as $key => $value ) {
621 - if ( '' === $value ) {
622 - $slug = str_replace( 'attribute_', '', $key );
623 -
624 - if ( ! isset( $parent_attributes[ $slug ] ) ) {
625 - continue;
626 - }
627 -
628 - $name = $parent_attributes[ $slug ]['name'] ?? $slug;
629 - if ( $name === $slug ) {
630 - $name = wc_attribute_label( $slug );
631 - }
632 -
633 - // find the value from $posted['meta_data'].
634 - foreach ( $posted['meta_data'] as $meta ) {
635 - // Match posted attribute label to the $name we just determined.
636 - if ( isset( $meta['display_key'], $meta['display_value'] ) && $meta['display_key'] === $name ) {
637 - $posted_value = $meta['display_value'];
638 - // Only update if the posted value is non-empty.
639 - if ( $posted_value ) {
640 - $item->update_meta_data(
641 - $slug,
642 - $posted_value,
643 - $meta['id'] ?? ''
644 - );
645 -
646 - break; // Stop searching once found.
647 - }
648 - }
649 - }
650 - }
651 - }
652 - }
653 -
654 - /**
655 553 * The way WooCommerce handles negative fees is ... weird.
656 554 * They by-pass the normal tax calculation, disregard the tax_status and tax_class, and apply the taxes to the fee line.
657 555 * This is a problem because if people want to apply a negative fee to an order, and set tax_status to 'none', it will give
658 556 * the wrong result.
@@ -665,31 +563,8 @@
665 563 * @param array $calculate_tax_for The tax calculation data.
666 564 */
667 565 public function wcpos_order_item_fee_after_calculate_taxes( $fee_item, $calculate_tax_for ): void {
668 566 \WCPOS\WooCommercePOS\Orders::fee_after_calculate_taxes( $fee_item, $calculate_tax_for );
669 - }
670 -
671 - /**
672 - * Gets the product ID from posted ID.
673 - *
674 - * @param array $posted Request data.
675 - * @param string $action 'create' to add line item or 'update' to update it.
676 - *
677 - * @throws WC_REST_Exception When SKU or ID is not valid.
678 - *
679 - * @return int
680 - */
681 - public function get_product_id( $posted, $action = 'create' ) {
682 - // If id = 0, ie: miscellaneaous product, just return 0.
683 - if ( isset( $posted['product_id'] ) && 0 == $posted['product_id'] ) {
684 - return 0;
685 - }
686 -
687 - // Bypass the sku check. Some users have products with duplicated SKUs, esp. variable/variations.
688 - $data = $posted;
689 - unset( $data['sku'] );
690 -
691 - return parent::get_product_id( $data, $action );
692 567 }
693 568
694 569 /**
695 570 * Validate billing email.