<?php namespace WPForms\Integrations\Square\Api\Webhooks; use RuntimeException; use WPForms\Db\Payments\Queries; /** * Webhook payment.updated class. * Set the status to 'completed' if payment is paid. * * @since 1.9.5 */ class PaymentUpdated extends Base { /** * Invoice object. * * @since 1.9.5 * * @var Invoice|null */ private $invoice; /** * Handle the Webhook's data. * * @since 1.9.5 * * @throws RuntimeException If payment isn't found or not updated. * * @return bool */ public function handle(): bool { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh $order_id = $this->data->object->payment->order_id ?? ''; $this->invoice = $this->api->get_invoice_by_order_id( $order_id ); $subscription_id = $this->invoice ? $this->invoice->getSubscriptionId() : ''; // If a subscription ID exists, process the subscription-specific logic. if ( $subscription_id ) { $this->update_subscription_payment( $subscription_id ); } $this->set_payment(); if ( $this->db_payment === null ) { throw new RuntimeException( 'Payment Update Event: Payment has not been found and set.' ); } // Update payment method details to keep them up to date. if ( isset( $this->data->object->payment ) && $this->data->object->payment !== null ) { $this->update_payment_method_details( $this->db_payment->id, $this->data->object->payment ); } // Update total refunded amount if set. if ( ! empty( $this->data->object->payment->refunded_money ) ) { $this->update_total_refund( $this->db_payment->id, $this->data->object->payment->refunded_money ); } if ( $this->db_payment->status !== 'processed' || $this->data->object->payment->status !== 'COMPLETED' ) { return false; } $currency = strtoupper( $this->data->object->payment->total_money->currency ); $db_amount = wpforms_format_amount( $this->db_payment->total_amount ); $amount = wpforms_format_amount( $this->data->object->payment->total_money->amount / wpforms_get_currency_multiplier( $currency ) ); if ( $amount !== $db_amount ) { return false; } $updated_payment = wpforms()->obj( 'payment' )->update( $this->db_payment->id, [ 'status' => 'completed', 'date_updated_gmt' => gmdate( 'Y-m-d H:i:s' ), ] ); if ( ! $updated_payment ) { throw new RuntimeException( 'Payment not updated' ); } wpforms()->obj( 'payment_meta' )->add_log( $this->db_payment->id, 'Square payment was completed.' ); return true; } /** * Update subscription payment. * * @since 1.9.5 * * @param string $subscription_id Subscription ID. * * @return bool */ private function update_subscription_payment( string $subscription_id ): bool { // If this is the first invoice in the subscription, do not create a renewal. if ( $this->is_initial_invoice_for_subscription( $subscription_id ) ) { return false; } // Retrieve the renewal record from the database. $db_renewal = ( new Queries() )->get_renewal_by_invoice_id( $this->invoice->getId() ); if ( is_null( $db_renewal ) ) { return false; // The newest renewal not found. } // Check if the renewal payment is already completed. if ( $db_renewal->status === 'completed' ) { return true; } // Retrieve the payment requests from the invoice. $payment_requests = $this->invoice->getPaymentRequests(); if ( empty( $payment_requests ) ) { return false; } // Use the first payment request to get the final paid amount. $total_completed = $payment_requests[0]->getTotalCompletedAmountMoney(); $currency = strtoupper( $total_completed->getCurrency() ); $amount = $total_completed->getAmount() / wpforms_get_currency_multiplier( $currency ); // Retrieve the transaction ID using the subscription ID. $transaction_id = $this->get_latest_subscription_transaction_id( $subscription_id ); if ( empty( $transaction_id ) ) { $transaction_id = ''; } // Update the renewal payment with the final amount and transaction ID. wpforms()->obj( 'payment' )->update( $db_renewal->id, [ 'total_amount' => $amount, 'subtotal_amount' => $amount, 'status' => 'completed', 'transaction_id' => $transaction_id, ] ); // Copy additional meta data from the transaction details. $this->copy_meta_from_transaction_details( (int) $db_renewal->id, $transaction_id ); wpforms()->obj( 'payment_meta' )->add_log( $db_renewal->id, sprintf( 'Square renewal was successfully paid. (Payment ID: %1$s)', $transaction_id ) ); return true; } /** * Copy meta from transaction. * * @since 1.9.5 * * @param int $renewal_id Renewal ID. * @param string $transaction_id Transaction ID. */ private function copy_meta_from_transaction_details( int $renewal_id, string $transaction_id ) { $card_details = $this->api->get_card_details_from_transaction_id( $transaction_id ); if ( ! $card_details ) { return; } $this->update_payment_method_details( $renewal_id, $card_details ); } }