Repository: woocommerce/woocommerce (PHP)

Issue:
HPOS - Refund amount is missing in Woo API order refunds response payload and in data received via Webhooks if HPOS is enabled
### Prerequisites

- [X] I have carried out troubleshooting steps and I believe I have found a bug.
- [X] I have searched for similar bugs in both open and closed issues and cannot find a duplicate.

### Describe the bug

The following info is missing in the response payload from Woo API GET `wp-json/wc/v3 /orders/<orderid>refund` if an order is refunded while HPOS is enabled: 
"amount": "0.00",
"refunded_by": 0,

The same scenario goes for data received via Webhooks.

If HPOS is disabled, everything works - values come correct and on time.


### Expected behavior

Refunds response values  when **HPOS enabled** via woo API GET `wp-json/wc/v3 /orders/<orderid>refund`
 
 "amount": "40.50", (expected amount while according to goods price on test shop)
  "refunded_by": 1,


### Actual behavior

Refunds response values  when **HPOS disabled** via woo API GET `wp-json/wc/v3 /orders/<orderid>refund`

"amount": "0.00",
"refunded_by": 0,

### Steps to reproduce

1. Create completed order;
2. Refund order;
3. Get refund data via Woo API GET `wp-json/wc/v3 /orders/<orderid>refund`
4. "amount" is 0.00
5. "refunded_by" is 0

### WordPress Environment

[SystemStatusReport_woo-e2e-test.omni-woo-test.com_2023-07-13T11-26-58.txt](https://github.com/woocommerce/woocommerce/files/12038819/SystemStatusReport_woo-e2e-test.omni-woo-test.com_2023-07-13T11-26-58.txt)


### Isolating the problem

- [X] I have deactivated other plugins and confirmed this bug occurs when only WooCommerce plugin is active.
- [X] This bug happens with a default WordPress theme active, or [Storefront](https://woocommerce.com/storefront/).
- [X] I can reproduce this bug consistently using the steps above.


Discussion: @m-mikelkevicius I can only partially reproduce this. If I do a partial or refund on an order while HPOS is enabled, I see the same `refunded_by` value that you do, `0` (i.e. no user ID is present). However, I am seeing the correct value for `amount`. If I switch the data storage setting to "WordPress post tables", I still see the correct `amount` and now `refunded_by` is showing the correct user ID.

Can you provide a bit more detail about your settings/environment where you're seeing an empty `amount` as well?
Hi @coreymckrill , I have tried to reproduce once again on another shop, where no additional plugins are activated, and I could reproduce it:
After placing order I have refunded it while HPOS is enabled, and while not. After that, if I try to get refund data via woo API  wp-json/wc/v3/orders/<order_id>/refunds  just after I refunded it I get the different payload as you see below:

With HPOS
{
        "id": 1441,
        "date_created": "2023-07-21T13:40:09",
        "date_created_gmt": "2023-07-21T13:40:09",
        **"amount": "0.00",**
        "reason": "",
        **"refunded_by": 0,**
        "refunded_payment": false,....

Without HPOS:
{
        "id": 1443,
        "date_created": "2023-07-21T13:45:05",
        "date_created_gmt": "2023-07-21T13:45:05",
        **"amount": "55.00",**
        "reason": "",
        **"refunded_by": 1,**
        "refunded_payment": false,

If I try to get data for refunded order with HPOS after a few minutes the data then appears usually, but not always.

The main issue for us is that webhooks send data without mentioned properties because with HPOS there is this delay introduced.
I think this was partially fixed by #39219, which is not yet in a public release. That would explain why the `amount` field was missing data when testing in WC 7.8.2, but I was seeing correct data for it when I tested in trunk. However, the `refunded_by` field is still not working correctly. I've outlined the cause of that in #39444.



Fix (patch):
diff --git a/plugins/woocommerce/changelog/fix-39215-alternative-refund-meta-keys b/plugins/woocommerce/changelog/fix-39215-alternative-refund-meta-keys
new file mode 100644
index 0000000000000..903db8f99811f
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-39215-alternative-refund-meta-keys
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+Ensure refund meta data is saved correctly when HPOS is enabled.
diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
index 41f912bd3fab2..d76c1b8a358c4 100644
--- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
+++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
@@ -2358,10 +2358,10 @@ protected function persist_save( &$order, bool $force_all_fields = false, $backf
 			$order->set_date_modified( current_time( 'mysql' ) );
 		}
 
-		$this->update_order_meta( $order );
-
 		$this->persist_order_to_db( $order, $force_all_fields );
 
+		$this->update_order_meta( $order );
+
 		$order->save_meta_data();
 		$order->apply_changes();
 
diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableRefundDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableRefundDataStore.php
index fab7f3640f782..6d532a93ce3eb 100644
--- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableRefundDataStore.php
+++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableRefundDataStore.php
@@ -6,6 +6,8 @@
 
 namespace Automattic\WooCommerce\Internal\DataStores\Orders;
 
+use WC_Meta_Data;
+
 /**
  * Class OrdersTableRefundDataStore.
  */
@@ -159,8 +161,17 @@ public function update_order_meta( &$refund ) {
 
 		$props_to_update = $this->get_props_to_update( $refund, $meta_key_to_props );
 		foreach ( $props_to_update as $meta_key => $prop ) {
-			$value = $refund->{"get_$prop"}( 'edit' );
-			$refund->update_meta_data( $meta_key, $value );
+			$meta_object        = new WC_Meta_Data();
+			$meta_object->key   = $meta_key;
+			$meta_object->value = $refund->{"get_$prop"}( 'edit' );
+			$existing_meta      = $this->data_store_meta->get_metadata_by_key( $refund, $meta_key );
+			if ( $existing_meta ) {
+				$existing_meta   = $existing_meta[0];
+				$meta_object->id = $existing_meta->id;
+				$this->update_meta( $refund, $meta_object );
+			} else {
+				$this->add_meta( $refund, $meta_object );
+			}
 			$updated_props[] = $prop;
 		}