Source: my-calendar-payment-functions.php

<?php
/**
 * My Calendar Submission Payment Processing
 *
 * @category Payments
 * @package  My Calendar Pro
 * @author   Joe Dolson
 * @license  GPLv2 or later
 * @link     https://www.joedolson.com/my-calendar-pro/
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Get receipt ID and verify
 */
function mcs_verify_receipt() {
	global $wpdb;
	if ( isset( $_GET['mcs_receipt'] ) ) {
		$receipt = ( isset( $_GET['mcs_receipt'] ) ) ? sanitize_text_field( wp_unslash( $_GET['mcs_receipt'] ) ) : false;
		$email   = ( isset( $_POST['mcs_email'] ) ) ? sanitize_text_field( is_email( $_POST['mcs_email'] ) ) : false;
		if ( $receipt && $email ) {
			if ( wp_verify_nonce( $_POST['_wpnonce'], 'mcs_receipt_nonce' ) ) {
				$result = $wpdb->get_var( $wpdb->prepare( 'SELECT id FROM ' . my_calendar_payments_table() . ' WHERE hash = %s AND payer_email = %s', $receipt, $email ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
				if ( $result ) {
					if ( version_compare( PHP_VERSION, '7.3.0', '>' ) ) {
						// Fix syntax.
						$options = array(
							'expires'  => time() + 60 * 60,
							'path'     => COOKIEPATH,
							'domain'   => COOKIE_DOMAIN,
							'secure'   => false,
							'httponly' => true,
							'samesite' => 'Lax',
						);
						setcookie( 'mcs_receipt', 'true', $options );
					} else {
						setcookie( 'mcs_receipt', 'true', time() + 60 * 60, COOKIEPATH, COOKIE_DOMAIN, false, true );
					}
				}
				wp_safe_redirect( add_query_arg( 'mcs_receipt', $receipt, home_url() ) );
			}
		}
	}
}

/**
 * Print receipt header.
 */
function mcs_receipt_header() {
	$url = plugin_dir_url( __FILE__ );
	global $mcs_version;
	?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
	<head>
		<meta charset="<?php bloginfo( 'charset' ); ?>" />
		<meta name="viewport" content="width=device-width" />
		<title><?php bloginfo( 'name' ); ?> - <?php esc_html_e( 'My Calendar Pro: Receipt', 'my-calendar-pro' ); ?></title>
		<meta name="generator" content="My Calendar for WordPress" />
		<meta name="robots" content="noindex,nofollow" />
		<?php
		if ( function_exists( 'mc_file_exists' ) && mc_file_exists( 'mcs-receipt.css' ) ) {
			$stylesheet = mc_get_file( 'mcs-receipt.css', 'url' );
		} else {
			$stylesheet = $url . 'css/mcs-receipt.css';
		}
		?>
		<!-- Copy mcs-receipt.css to your theme directory if you wish to replace the default print styles -->
		<link rel='stylesheet' href='<?php echo esc_url( add_query_arg( 'version', $mcs_version, $stylesheet ) ); ?>' />
	</head>
	<body>
		<div class='mcs-receipt'>
	<?php
	mcs_receipt_logo();
}

/**
 * Print custom receipt logo section.
 */
function mcs_receipt_logo() {
	$logo = get_custom_logo();
	if ( ! $logo ) {
		// translators: 1) link to site home; 2) name of site.
		$logo = sprintf( '<h1><a href="%1$s">%2$s</a></h1>', home_url(), get_bloginfo( 'blogname' ) );
		/**
		 * Filter the site name on receipts.
		 *
		 * @hook mcs_receipt_logo
		 *
		 * @param {string} $logo Site name wrapped in link to home and h1 element. Does not include logo.
		 *
		 * @return {string}
		 */
		$logo = apply_filters( 'mcs_receipt_logo', $logo );
	} else {
		$logo = '<h1>' . $logo . '</h1>';
	}
	?>
			<header class="mcs-receipt-header">
				<?php echo wp_kses_post( $logo ); ?>
			</header>
			<main>
	<?php
}

/**
 * Print receipt footer.
 */
function mcs_receipt_footer() {
	?>
			</main>
			<footer>
				<p><?php esc_html_e( 'Receipt generated by My Calendar Pro', 'my-calendar-pro' ); ?></p>
			</footer>
		</div>
	</body>
</html>
	<?php
}

add_filter( 'mcs_receipt_template', 'wpautop' );
/**
 * Display the receipt for purchase of event submission
 */
function mcs_show_receipt() {
	// verify validity of viewer.
	if ( isset( $_GET['mcs_receipt'] ) && isset( $_COOKIE['mcs_receipt'] ) && 'true' === $_COOKIE['mcs_receipt'] ) {
		global $wpdb;
		$receipt_id = sanitize_text_field( wp_unslash( $_GET['mcs_receipt'] ) );
		$query      = 'SELECT * FROM ' . my_calendar_payments_table() . ' WHERE hash = %s';
		$results    = $wpdb->get_row( $wpdb->prepare( $query, $receipt_id ), ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared

		$template = '
			<h2>' . __( 'Payment Key Purchase Receipt', 'my-calendar-pro' ) . '</h2>

			<strong>Purchased By</strong><span> {first_name} {last_name}</span>
			<strong>Transaction ID</strong><span> {txn_id}</span>
			<strong>Payment Key</strong><span> {hash}</span>
			<strong>Payer Email</strong><span> {payer_email}</span>

			<strong>Amount Paid</strong><span> ${price}</span>
			<strong>Submissions Granted</strong><span> {total}</span>
			<strong>Submissions Remaining</strong><span> {quantity}</span>
			<strong>Transaction Date</strong><span> {transaction_date}</span>';
		$template = apply_filters( 'mcs_receipt_template', $template, $results );
		mcs_receipt_header();
		echo wp_kses( mc_draw_template( $results, $template ), mc_kses_elements() );
		echo '<a href="javascript:window.print()">' . esc_html__( 'Print Receipt', 'my-calendar-pro' ) . '</a>';
		mcs_receipt_footer();
		exit;
	} elseif ( isset( $_GET['mcs_receipt'] ) ) {
		$nonce = wp_create_nonce( 'mcs_receipt_nonce' );
		mcs_receipt_header();
		?>
		<form action='' method='POST'>
			<input type='hidden' name='_wpnonce' value='<?php echo esc_attr( $nonce ); ?>' />
			<div>
				<label for='mcs-email'>Your purchase email</label> 
				<input type='email' name='mcs_email' id='mcs-email' autocomplete='email' /> 
				<input type='submit' name='mcs-verify' value='<?php esc_html_e( 'Verify Email', 'my-calendar-pro' ); ?>' />
			</div>
		</form>
		<?php
		mcs_receipt_footer();
		exit;
	}
}

add_action( 'init', 'mcs_setup_gateway' );
/**
 * Gateway setup function.
 */
function mcs_setup_gateway() {
	$gateway = get_option( 'mcs_gateway' );
	switch ( $gateway ) {
		case 'paypal':
			require_once 'gateways/my-calendar-paypal.php';
			break;
		case 'stripe':
			require_once 'gateways/my-calendar-stripe.php';
			break;
	}
	// Support for custom gatways.
	do_action( 'mcs_enqueue_gateway', $gateway );
}

/**
 * Process IPN data returned from payment gateways
 */
function mcs_receive_ipn() {
	if ( isset( $_GET['mcsipn'] ) && 'true' === $_GET['mcsipn'] ) {
		mcs_check();
		$gateway = get_option( 'mcs_gateway' );
		do_action( 'mcs_process_payment', $gateway );
	}
}

/**
 * Map statuses from Auth.net to match PayPal responses.
 *
 * @param integer $status Auth.net response ID.
 *
 * @return string
 */
function mcs_map_status( $status ) {
	switch ( $status ) {
		case 1:
			$response = 'Completed';
			break;
		case 2:
			$response = 'Declined';
			break;
		case 3:
			$response = 'Error';
			break;
		case 4:
			$response = 'Held for Review';
			break;
		default:
			$response = 'Completed';
	}

	return $response;
}

/**
 * Insert new payment into database and send notifications.
 *
 * @param array  $values Values passed from gateway.
 * @param string $status Status of this payment.
 *
 * @return string status
 */
function mcs_process_payment( $values, $status ) {
	$item_number = $values['item_number'];
	$txn_id      = $values['txn_id'];
	$price       = $values['price'];
	$mc_fee      = $values['mc_fee'];
	$payer_first = $values['payer_first'];
	$payer_last  = $values['payer_last'];
	$payer_email = $values['payer_email'];

	$payment = mcs_get_payment( $item_number, $txn_id );
	if ( $payment ) {
		$post = array(
			'price'       => $price,
			'first_name'  => $payer_first,
			'last_name'   => $payer_last,
			'email'       => $payer_email,
			'fee'         => $mc_fee,
			'txn_id'      => $txn_id,
			'item_number' => $item_number,
			'status'      => $status,
		);
		$args = mcs_update_payment( $post, $payment );

		if ( isset( $args['status'] ) && 'Completed' === $args['status'] ) {
			$status = 'Completed';
		}
	} else {
		$post = array(
			'price'       => $price,
			'first_name'  => $payer_first,
			'last_name'   => $payer_last,
			'email'       => $payer_email,
			'fee'         => $mc_fee,
			'txn_id'      => $txn_id,
			'item_number' => $item_number,
			'status'      => $status,
		);
		$args = mcs_create_payment( $post );
	}

	if ( 'Completed' === $status ) {
		$notifications = mcs_send_notifications( $args );
		setcookie( 'mcs_receipt', 'true', time() + 60 * 60, COOKIEPATH, COOKIE_DOMAIN, false, true );
	}

	return $status;
}

/**
 * Get payment based on item number or txn id.
 *
 * @param int    $item_number Post ID.
 * @param string $txn_id Transaction ID (from payment gateway.).
 *
 * @return array
 */
function mcs_get_payment( $item_number = false, $txn_id = false ) {
	// get payment based on either item number or txnid.
	global $wpdb;

	if ( $item_number || $txn_id ) {
		$result = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . my_calendar_payments_table() . ' WHERE id = %d', $item_number ), 'ARRAY_A' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared

		if ( $result ) {
			return $result;
		} else {
			$result = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . my_calendar_payments_table() . ' WHERE txn_id = %s', $txn_id ), 'ARRAY_A' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
			if ( $result ) {
				return $result;
			}
		}
	}

	return false;
}

/**
 * Delete a payment.
 *
 * @param int $payment_id Payment ID.
 *
 * @return string
 */
function mcs_delete_payment( $payment_id ) {
	// get payment based on either item number or txnid.
	global $wpdb;

	if ( $payment_id ) {
		$result = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . my_calendar_payments_table() . ' WHERE id = %d', $payment_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		if ( $result ) {
			return __( 'Payment record deleted.', 'my-calendar-pro' );
		}
	}

	return false;
}

/**
 * Update a payment.
 *
 * @param array     $post Post data.
 * @param array|int $payment Payment array or payment ID.
 *
 * @return array|false
 */
function mcs_update_payment( $post, $payment ) {
	if ( ! $payment ) {
		return false;
	}

	if ( is_numeric( $payment ) ) {
		$post    = array_merge( $post, array( 'item_number' => $payment ) );
		$payment = mcs_get_payment( $payment );
	}

	if ( ! is_array( $payment ) ) {
		return false;
	}

	global $wpdb;
	// Price & Quantity minimum values available.
	$quantity = ( isset( $post['quantity'] ) ) ? (int) $post['quantity'] : $payment['quantity'];
	$total    = ( isset( $post['total'] ) ) ? (int) $post['total'] : $quantity;
	if ( $total !== $quantity ) {
		// If we change the total purchased, increment up the quantity available to match.
		$quantity = $quantity + ( $total - $quantity );
	}
	$price      = sprintf( '%01.2f', $post['price'] );
	$first_name = ( isset( $post['first_name'] ) ) ? $post['first_name'] : '';
	$last_name  = ( isset( $post['last_name'] ) ) ? $post['last_name'] : '';
	$email      = ( isset( $post['email'] ) ) ? is_email( $post['email'] ) : '';
	$txn_id     = ( isset( $post['txn_id'] ) ) ? $post['txn_id'] : 'Manual Entry';
	$status     = ( isset( $post['status'] ) ) ? $post['status'] : 'Completed';
	$fee        = ( isset( $post['mc_fee'] ) ) ? $post['mc_fee'] : '0.00';
	$metadata   = ( isset( $post['metadata'] ) ) ? $post['metadata'] : array();
	// Commented out keys are in Payment but not updated.
	$update = array(
		// 'item_number'      => $post['item_number'],.
		// 'event_id'         => 0,.
		// 'hash'             => '',
		// 'transaction_date' => '',.
		'quantity'    => $quantity,
		'total'       => $total,
		'txn_id'      => $txn_id,
		'price'       => $price,
		'fee'         => '0.00',
		'status'      => $status,
		'first_name'  => $first_name,
		'last_name'   => $last_name,
		'payer_email' => $email,
		'gateway'     => get_option( 'mcs_gateway' ),
		'metadata'    => serialize( $metadata ),
	);
	if ( isset( $payment['id'] ) ) {
		unset( $payment['id'] );
	}
	$update  = array_merge( $payment, $update );
	$formats = array(
		'%d', // Item Number.
		'%d', // Event ID.
		'%d', // Quantity.
		'%d', // Total count.
		'%s', // Hash.
		'%s', // Txn ID.
		'%f', // Price.
		'%f', // Fee.
		'%s', // Status.
		'%s', // Transaction Date.
		'%s', // First Name.
		'%s', // Last Name.
		'%s', // Payer Email.
		'%s', // Gateway.
		'%s', // Metadata.
	);
	$update  = $wpdb->update( my_calendar_payments_table(), $update, array( 'id' => $post['item_number'] ), $formats );
	$id      = $wpdb->insert_id;
	$args    = array(
		'first'    => $first_name,
		'last'     => $last_name,
		'email'    => $email,
		'price'    => $price,
		'hash'     => $payment['hash'],
		'quantity' => $quantity,
		'id'       => $id,
		'status'   => $status,
	);

	return $args;
}

/**
 * Update a single payment field.
 *
 * @param int              $item_number Payment ID.
 * @param string           $field Field name.
 * @param string|int|float $value Field value.
 *
 * @return bool|int
 */
function mcs_update_payment_field( $item_number, $field, $value ) {
	global $wpdb;
	$update = array(
		$field => $value,
	);
	switch ( $field ) {
		case 'hash':
		case 'transaction_date':
		case 'txn_id':
		case 'status':
		case 'first_name':
		case 'last_name':
		case 'payer_email':
		case 'gateway':
		case 'metadata':
			$format = array( '%s' );
			break;
		case 'quantity':
			$format = array( '%d' );
			break;
		case 'item_number':
		case 'event_id':
		case 'total':
		case 'price':
		case 'fee':
			$format = array( '%f' );
			break;
	}
	$result = $wpdb->update( my_calendar_payments_table(), $update, array( 'id' => $item_number ), $format );

	return $result;
}

/**
 * Get the value of a single payment field.
 *
 * @param int    $item_number Payment ID.
 * @param string $field Field name.
 *
 * @return string|int|float
 */
function mcs_get_payment_field( $item_number, $field ) {
	global $wpdb;
	switch ( $field ) {
		case 'hash':
		case 'transaction_date':
		case 'txn_id':
		case 'status':
		case 'first_name':
		case 'last_name':
		case 'payer_email':
		case 'gateway':
		case 'metadata':
		case 'quantity':
		case 'item_number':
		case 'event_id':
		case 'total':
		case 'price':
		case 'fee':
			$field_name = $field;
			break;
		default:
			$field_name = false;
	}
	if ( ! $field_name ) {
		return $item_number;
	}
	$value = $wpdb->get_var( $wpdb->prepare( 'SELECT ' . $field_name . ' FROM ' . my_calendar_payments_table() . ' WHERE id = %d', $item_number ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared

	return $value;
}

/**
 * Send notifications about completed purchases.
 *
 * @param array $args Array of passed values.
 */
function mcs_send_notifications( $args = array() ) {
	// Define message variables.
	$first    = $args['first'];
	$last     = $args['last'];
	$email    = $args['email'];
	$price    = $args['price'];
	$hash     = $args['hash'];
	$quantity = $args['quantity'];
	$blogname = get_option( 'blogname' );
	$receipt  = add_query_arg( 'mcs_receipt', $hash, home_url() );
	$search   = array(
		'first_name' => $first,
		'last_name'  => $last,
		'blogname'   => $blogname,
		'price'      => $price,
		'key'        => $hash,
		'quantity'   => $quantity,
		'receipt'    => $receipt,
	);

	$mail_from      = "From: $blogname Events <" . get_option( 'mcs_from', get_option( 'admin_email' ) ) . '>';
	$admin_subject  = get_option( 'mcs_payment_subject' );
	$client_subject = get_option( 'mcs_payment_confirmation_subject' );

	// Draw templates.
	$admin_subject  = mc_draw_template( $search, $admin_subject );
	$client_subject = mc_draw_template( $search, $client_subject );
	$admin_body     = mc_draw_template( $search, get_option( 'mcs_payment_response' ) );
	$client_body    = mc_draw_template( $search, get_option( 'mcs_payment_confirmation' ) );

	$send_html = false;
	$warning   = '';

	if ( 'true' === get_option( 'mcs_html_email' ) ) {
		add_filter( 'wp_mail_content_type', 'mcs_html_email' );
		$send_html = true;
	}

	$client = wp_mail( $email, $client_subject, $client_body, $mail_from );
	if ( ! $client ) {
		// Translators: Purchaser email address.
		$warning = ' ' . sprintf( __( 'There was an error sending the purchaser email notification. You will need to contact the purchaser directly at %s', 'my-calendar-pro' ), $email );
		$warning = ( $send_html ) ? wpautop( $warning ) : $warning . "\n\n";
	}
	$admin_email = get_option( 'mcs_to', get_option( 'admin_email' ) );
	wp_mail( $admin_email, $admin_subject, $warning . $admin_body, $mail_from );

	if ( 'true' === get_option( 'mcs_html_email' ) ) {
		remove_filter( 'wp_mail_content_type', 'mcs_html_email' );
	}
}

/**
 * Check Unique ID in the database
 *
 * @param string $hash Saved key.
 * @param int    $i Check number.
 *
 * @return string
 */
function mcs_uniqid( $hash, $i = 1 ) {
	global $wpdb;
	$sql = $wpdb->prepare( 'SELECT hash FROM ' . my_calendar_payments_table() . ' WHERE hash=%s', $hash ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
	if ( $wpdb->get_var( $sql ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		$hash = uniqid( 'E' . $i );
		mcs_uniqid( $hash, $i++ );
	} else {
		return $hash;
	}
}

/**
 * Set cURL to use SSL version supporting TLS 1.2
 *
 * @param object $handle CURL object.
 */
function mcs_http_api_curl( $handle ) {
	curl_setopt( $handle, CURLOPT_SSLVERSION, 6 );
}
add_action( 'http_api_curl', 'mcs_http_api_curl' );


/**
 * Submit payment form
 */
function mcs_payment_form() {
	$ret     = '';
	$form    = '';
	$gateway = get_option( 'mcs_gateway' );
	if ( isset( $_GET['response_code'] ) ) {
		$mcs     = sanitize_text_field( $_GET['response_code'] );
		$item    = isset( $_GET['item_number'] ) ? absint( $_GET['item_number'] ) : '';
		$payment = mcs_get_payment( $item );
		$ret     = apply_filters( 'mcs_gateway_response', '', $mcs, $payment, $gateway );
	}
	if ( mcs_payment_required() ) {
		$price     = mcs_get_price();
		$currency  = get_option( 'mcs_currency' );
		$discounts = mcs_check_discount();
		if ( is_array( $discounts ) ) {
			$discount_rate = (int) $discounts['rate'];
			$discount      = ( 0 !== $discount_rate ) ? true : false;
			$begins        = $discounts['begins'];
			$ends          = $discounts['ends'];
		} else {
			$discount_rate = 0;
			$discount      = false;
			$begins        = '';
			$ends          = '';
		}

		if ( isset( $_GET['response_code'] ) ) {
			$message = '';
		} else {
			$message = wpautop(
				mc_draw_template(
					array(
						'price'    => $price,
						'currency' => $currency,
						'discount' => $discount_rate,
						'begins'   => $begins,
						'ends'     => $ends,
					),
					get_option( 'mcs_payment_message' )
				)
			);
		}
		$nonce = wp_create_nonce( 'mcs-payments-nonce' );
		$args  = array(
			'nonce'         => $nonce,
			'price'         => $price,
			'discount'      => $discount,
			'discount_rate' => $discount_rate,
			'discounts'     => $discounts,
			'currency'      => $currency,
		);
		$form  = "<div class='mc-payments-form " . esc_attr( $gateway ) . "'>$ret$message";
		$form .= '<div class="mc-create-purchase">';
		$form .= mcs_set_quantity_form( $price );
		$form .= "</div><div class='mc-payment-form'>";
		$form .= apply_filters( 'mcs_payment_gateway', '', $gateway, $args );
		$form .= '</div></div>';
	}

	return $form;
}
add_shortcode( 'submit_payment', 'mcs_payment_form' );

/**
 * Get information about purchase.
 */
function mcs_purchase_request() {
	if ( isset( $_REQUEST['action'] ) && 'mcs_purchase_request' === $_REQUEST['action'] ) {
		$quantity   = ( isset( $_REQUEST['quantity'] ) ) ? absint( $_REQUEST['quantity'] ) : 1;
		$security   = $_REQUEST['security'];
		$payment_id = ( is_numeric( $_REQUEST['payment_id'] ) ) ? absint( $_REQUEST['payment_id'] ) : false;

		if ( ! wp_verify_nonce( $security, 'mc-query-purchase' ) ) {
			wp_send_json(
				array(
					'success'    => 0,
					'response'   => '',
					'payment_id' => $payment_id,
				)
			);
		}
		if ( isset( $_REQUEST['payer_name'] ) && isset( $_REQUEST['payer_email'] ) ) {
			// We're updating data in an existing payment.
			$name  = sanitize_text_field( wp_unslash( $_REQUEST['payer_name'] ) );
			$email = sanitize_email( wp_unslash( $_REQUEST['payer_email'] ) );
			$names = explode( ' ', $name );
			$first = array_shift( $names );
			$last  = implode( ' ', $names );
			mcs_update_payment_field( $payment_id, 'payer_email', $email );
			mcs_update_payment_field( $payment_id, 'first_name', $first );
			mcs_update_payment_field( $payment_id, 'last_name', $last );
			wp_send_json(
				array(
					'success'    => 1,
					'response'   => 'Saved',
					'payment_id' => $payment_id,
				)
			);
		}
		$price = mcs_get_price();
		$total = ( $price * $quantity );
		$post  = array(
			'quantity'    => $quantity,
			'price'       => $total,
			'txn_id'      => '--',
			'status'      => 'Pending',
			'item_number' => $payment_id,
		);

		if ( ! is_numeric( $payment_id ) ) {
			$insert = mcs_create_payment( $post );
		} else {
			$insert = mcs_update_payment( $post, $payment_id );
		}
		$gateway = get_option( 'mcs_gateway' );
		if ( 'stripe' === $gateway ) {
			$total            = ( mcs_zerodecimal_currency() ) ? $total : $total * 100;
			$intent           = mcs_generate_intent( $total, $insert['id'] );
			$post['metadata'] = serialize( array( 'intent_id' => $intent->id ) );
			mcs_update_payment( $post, $insert['id'] );
		}
		$insert_id = $insert['id'];
		$response  = array(
			'success'    => 1,
			'response'   => $price,
			'payment_id' => $insert_id,
		);
		if ( 'stripe' === $gateway && is_object( $intent ) ) {
			$response['client_secret'] = $intent->client_secret;
		}
		wp_send_json( $response );
	}
}
add_action( 'wp_ajax_mcs_purchase_request', 'mcs_purchase_request' );
add_action( 'wp_ajax_nopriv_mcs_purchase_request', 'mcs_purchase_request' );

/**
 * Check whether payment is required to submit.
 *
 * @return boolean
 */
function mcs_payment_required() {
	$enabled = ( 'true' === get_option( 'mcs_payments' ) ) ? true : false;
	if ( current_user_can( 'manage_options' ) || ! $enabled ) {
		$return = false;
	} else {
		if ( ( ! is_user_logged_in() ) || ( is_user_logged_in() && get_option( 'mcs_members_discount' ) < 100 ) ) {
			$return = true;
		} else {
			$return = false;
		}
	}

	return apply_filters( 'mcs_payment_required', $return );
}

add_action( 'admin_notices', 'mcs_stripe_requires_ssl' );
/**
 * Stripe only functions under SSL. Notify user that this is required.
 */
function mcs_stripe_requires_ssl() {
	global $current_screen;
	if ( stripos( $current_screen->id, 'my-calendar-pro' ) ) {
		if ( 0 === stripos( home_url(), 'https' ) || 'true' !== get_option( 'mcs_payments' ) ) {
			return;
		} else {
			wp_admin_notice(
				__( 'Payment processing requires an SSL Certificate. Please switch your site to HTTPS. <a href="https://wordpress.org/support/article/https-for-wordpress/">How to switch WordPress to HTTPS</a>', 'my-calendar-pro' ),
				array(
					'type'               => 'error',
					'additional_classes' => array( 'my-calendar-pro' ),
				)
			);
		}
	}
}

/**
 * Check for a user discount.
 *
 * @param string $role Filtered variable for user roles.
 *
 * @return mixed float/boolean Value of discount.
 */
function mcs_check_discount( $role = 'auto' ) {
	$discounts = get_option( 'mcs_discount' );
	$discounts = apply_filters( 'mcs_alter_discount', $discounts, $role );
	if ( $discounts ) {
		$on_sale = mcs_on_sale( $discounts );
		if ( $on_sale ) {
			return $discounts;
		} else {
			return false;
		}
	}

	return false;
}

/**
 * Calculate the price to add an event.
 *
 * @param int     $quantity How many event keys to buy.
 * @param float   $price Price per event.
 * @param boolean $discount User has discount.
 * @param float   $discount_rate Percentage discount.
 *
 * @return float.
 */
function mcs_calculate_price( $quantity, $price, $discount, $discount_rate ) {
	$total = $price * $quantity;
	if ( $discount ) {
		$total = $price * $discount_rate;
	}

	return $total;
}

/**
 * Show quantity form to select a number of keys to buy.
 *
 * @param float $price Price per event.
 *
 * @return string
 */
function mcs_set_quantity_form( $price ) {
	$currency = get_option( 'mcs_currency' );
	$form     = "<form action='' method='POST'>
			<input type='hidden' name='mcs_payment_id' id='mcs_payment_id' value='' />
			<div>
				<label for='mcs_quantity'>" . __( 'Number of events?', 'my-calendar-pro' ) . "</label>
				<input type='number' name='mcs_quantity' value='1' min='1' id='mcs_quantity' /> 
			</div>
			<div>
			<button type='button' class='mc-purchase-key' name='mcs_set_quantity'>" . __( 'Go to Payment', 'my-calendar-pro' ) . "</button>
			</div>
		</form>
		<div class='mcs-payment-total' role='alert'>
			<strong>" . __( 'Total:', 'my-calendar-pro' ) . '</strong> ' .
			// Translators: Count, Price per, Total price.
			sprintf( __( '%1$s at %2$s: %3$s', 'my-calendar-pro' ), '<span class="mcs-event-count">1</span>', '<span class="mcs-event-currency">' . mcs_symbols( $currency ) . '</span><span class="mcs-event-price">' . $price . '</span>', '<span class="mcs-event-currency">' . mcs_symbols( $currency ) . '</span><strong class="mcs-event-total">' . $price . '</strong>' ) . '
		</div>';

	return $form;
}

/**
 * Is there a sale on?
 *
 * @param array $discounts Discount information.
 *
 * @return boolean
 */
function mcs_on_sale( $discounts ) {
	if ( ! isset( $discounts['begins'] ) || ! isset( $discounts['ends'] ) || ! isset( $discounts['rate'] ) ) {
		$return = false;
	}
	if ( '' === $discounts['begins'] ) {
		$return = false;
	}
	$end = ( '' === $discounts['ends'] ) ? mcs_date( 'Y-m-d', time() + 60 * 60 * 24 * 7 ) : $discounts['ends'];
	if ( function_exists( 'my_calendar_date_xcomp' ) ) {
		if ( my_calendar_date_xcomp( $discounts['begins'], mcs_date( 'Y-m-d', time() ) ) && my_calendar_date_xcomp( mcs_date( 'Y-m-d', time() ), $end ) && (int) $discounts['rate'] > 0 ) {
			$return = true;
		}
	} else {
		$return = false;
	}

	return $return;
}

/**
 * Get event submission price.
 *
 * @return float.
 */
function mcs_get_price() {
	$logged_in = ( is_admin() ) ? true : is_user_logged_in();
	$price     = apply_filters( 'mcs_get_price', get_option( 'mcs_submission_fee' ) );
	if ( $logged_in ) {
		$discounts = mcs_check_discount();
		if ( is_array( $discounts ) ) {
			$discount   = $discounts['rate'];
			$discounted = ( 0 !== $discount ) ? $price - ( $price * ( $discount / 100 ) ) : $price;
			$price      = $discounted;
		}
	}

	return (float) sprintf( '%01.2f', $price );
}

add_action( 'wp_enqueue_scripts', 'mcs_payments_enqueue_scripts' );
/**
 * Enqueue payment gateway scripts.
 */
function mcs_payments_enqueue_scripts() {
	if ( ! mcs_user_can_submit_events() ) {
		return;
	}
	global $mcs_version;
	if ( SCRIPT_DEBUG && true === SCRIPT_DEBUG ) {
		$mcs_version = $mcs_version . uniqid();
	}
	$stripe_options = get_option( 'mcs_stripe' );
	$gateway        = get_option( 'mcs_gateway' );
	wp_enqueue_script( 'mcs-payments', plugins_url( 'js/mcs-payments.js', __FILE__ ), array( 'jquery' ), $mcs_version, true );
	if ( ! empty( $stripe_options ) && 'stripe' === $gateway ) {
		// check if we are using test mode.
		if ( 'true' === get_option( 'mcs_use_sandbox' ) ) {
			$publishable = trim( $stripe_options['test_public'] );
		} else {
			$publishable = trim( $stripe_options['prod_public'] );
		}
		wp_enqueue_style( 'mcs.stripe.css', plugins_url( 'css/stripe.css', __FILE__ ) );
		wp_enqueue_script( 'stripe', 'https://js.stripe.com/v3/' );
		wp_enqueue_script( 'mcs.stripe', plugins_url( 'js/stripe.js', __FILE__ ), array( 'jquery', 'mcs-payments' ), $mcs_version, true );
		$url        = ( is_numeric( get_option( 'mcs_submit_id' ) ) ) ? get_permalink( get_option( 'mcs_submit_id' ) ) : home_url();
		$return_url = add_query_arg(
			array(
				'response_code' => 'thanks',
				'gateway'       => 'stripe',
				'item_number'   => '%d',
			),
			$url
		);
		wp_localize_script(
			'mcs.stripe',
			'mcs_stripe',
			array(
				'publishable_key'     => $publishable,
				'currency'            => get_option( 'mcs_currency', 'USD' ),
				'purchase_descriptor' => __( 'Calendar Submissions Order', 'my-calendar-pro' ),
				'return_url'          => $return_url,
				'selected'            => __( 'Selected', 'my-calendar-pro' ),
				'processing'          => __( 'Processing...', 'my-calendar-pro' ),
				'pay'                 => __( 'Pay Now', 'my-calendar-pro' ),
				'success'             => __( 'Successful Payment', 'my-calendar-pro' ),
			)
		);
	}
}

/**
 * Is the current currency a zerodecimal type.
 *
 * @return bool
 */
function mcs_zerodecimal_currency() {
	$currency   = get_option( 'mcs_currency', 'USD' );
	$currencies = mcs_currency();
	$data       = $currencies[ $currency ];

	if ( isset( $data['zerodecimal'] ) && true === $data['zerodecimal'] ) {
		return true;
	}

	return false;
}


/**
 * UPdate the available quantity on this key.
 *
 * @param string $key Purchase key.
 * @param int    $quantity How many events to adjust.
 *
 * @return integer update result
 */
function mcs_update_key_quantity( $key, $quantity ) {
	global $wpdb;
	$data    = array(
		'quantity' => $quantity - 1,
	);
	$formats = array( '%d' );
	$result  = $wpdb->update(
		my_calendar_payments_table(),
		$data,
		array(
			'hash' => $key,
		),
		$formats,
		'%s'
	);

	return $result;
}

/**
 * Verify validity of a key.
 *
 * @param string $key Purchase key.
 *
 * @return int|false
 */
function mcs_check_key( $key ) {
	if ( ! $key ) {
		return false;
	}
	global $wpdb;
	$sql      = 'SELECT quantity FROM ' . my_calendar_payments_table() . " WHERE hash = %s AND status = 'Completed'";
	$quantity = $wpdb->get_var( $wpdb->prepare( $sql, $key ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
	if ( ! $quantity || 0 === $quantity ) {

		$return = false;
	} else {

		$return = $quantity;
	}

	/**
	 * Filter payment key response. Can add checks against other posted data, e.g. email, etc.
	 *
	 * @hook mcs_check_key
	 *
	 * @param {int|false} $return Number of events available or false.
	 * @param {string}    $key Key to check.
	 *
	 * @return {int|false}
	 */
	return apply_filters( 'mcs_check_key', $return, $key );
}

/**
 * Get the status of a purchase key.
 *
 * @param string $key Purchase key.
 *
 * @return boolean
 */
function mcs_key_status( $key ) {
	if ( ! $key ) {
		return false;
	}
	global $wpdb;
	$sql = 'SELECT quantity,status FROM ' . my_calendar_payments_table() . ' WHERE hash = %s';
	$key = $wpdb->get_row( $wpdb->prepare( $sql, $key ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
	if ( ! $key ) {
		$return = __( 'That payment key does not exist', 'my-calendar-pro' );
	} elseif ( 0 === (int) $key->quantity ) {
		$return = __( 'Your payment key has been used up!', 'my-calendar-pro' );
	} elseif ( 'Completed' !== $key->status ) {
		// Translators: Payment key status.
		$return = sprintf( __( 'Your payment key status is "%s".', 'my-calendar-pro' ), $key->status );
	}

	return $return;
}