Files
formipay-public/includes/Order.php
2025-08-21 20:39:34 +07:00

1259 lines
49 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Formipay;
use Formipay\Traits\SingletonTrait;
if ( ! defined( 'ABSPATH' ) ) exit;
class Order {
use SingletonTrait;
private $form_id;
private $form_data;
private $order_data;
private $order_details;
/**
* Initializes the plugin by setting filters and administration functions.
*/
protected function __construct() {
add_action( 'init', [$this, 'create_db'] );
add_action( 'wp_ajax_formipay_submission', [$this, 'retrieve_form_data'] );
add_action( 'wp_ajax_nopriv_formipay_submission', [$this, 'retrieve_form_data'] );
add_action( 'admin_menu', [$this, 'add_menu'] );
add_action( 'admin_enqueue_scripts', [$this, 'enqueue'] );
add_action( 'wp_ajax_formipay_get_all_forms', [$this, 'formipay_get_all_forms'] );
add_action( 'wp_ajax_formipay_orders_get_choices', [$this, 'formipay_orders_get_choices'] );
add_action( 'wp_ajax_formipay-tabledata-orders', [$this, 'formipay_tabledata_orders'] );
add_action( 'wp_ajax_formipay-delete-order', [$this, 'formipay_delete_order'] );
add_action( 'wp_ajax_formipay-bulk-delete-order', [$this, 'formipay_bulk_delete_order'] );
add_action( 'wp_ajax_formipay_load_order_data', [$this, 'formipay_load_order_data'] );
add_action( 'wp_ajax_formipay_change_order_status', [$this, 'formipay_change_order_status'] );
add_action( 'wp_ajax_formipay_check_editable_field', [$this, 'formipay_check_editable_field'] );
add_action( 'wp_ajax_formipay_update_editable_field_data', [$this, 'formipay_update_editable_field_data'] );
add_action( 'wp_ajax_formipay_update_digital_access', [$this, 'formipay_update_digital_access'] );
add_filter( 'formipay/order/thankyou-screen-content', [$this, 'process_response_message'], 999, 5 );
add_filter( 'formipay/order/get', [$this, 'get_order_by_id'], 10, 2 );
}
public function create_db() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$create[] = "CREATE TABLE `{$wpdb->base_prefix}formipay_orders` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`created_date` datetime DEFAULT CURRENT_TIMESTAMP,
`updated_date` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`form_id` int,
`user_id` int,
`customer_id` int,
`items` text,
`total` float(10, 2) DEFAULT 0,
`status` varchar(20) DEFAULT 'on-hold',
`form_data` text,
`payment_gateway` text,
`meta_data` text,
PRIMARY KEY (`id`)
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($create);
}
public function retrieve_form_data() {
// Verify nonce
if ( empty($_POST['nonce']) || ! wp_verify_nonce( sanitize_text_field(wp_unslash($_POST['nonce'])), 'formipay_order_submit' ) ) {
wp_send_json_error([
'message' => 'Nonce verification failed'
]);
// wp_send_json_error() dies internally, no need for exit
}
// Sanitize and unslash inputs explicitly
$form_id = isset($_REQUEST['form_id']) ? intval(wp_unslash($_REQUEST['form_id'])) : 0;
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$raw_data = isset($_REQUEST['data']) ? wp_unslash($_REQUEST['data']) : [];
$form_data = is_array($raw_data) ? formipay_sanitize_array($raw_data) : sanitize_text_field($raw_data);
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$order_meta_data = isset($_REQUEST['meta_data']) ? wp_unslash($_REQUEST['meta_data']) : [];
$purpose = isset($_REQUEST['purpose']) ? sanitize_text_field(wp_unslash($_REQUEST['purpose'])) : '';
$this->form_id = $form_id;
// Let everyone modify this data (sanitize inside filters if needed)
$order_data = apply_filters('formipay/order/process-data', $form_data, $form_id);
$this->order_data = $order_data;
$order_details = $this->process_order_details();
$this->order_details = $order_details;
$total = $this->process_order_total();
if ($purpose === 'calculate') {
$order_data['total'] = $total;
$order_data['items'] = $order_details;
wp_send_json($order_data);
}
$status = ($total == 0) ? 'completed' : 'on-hold';
$submit_args = [
'form_id' => $form_id,
'items' => $order_details,
'total' => $total,
'status' => $status,
'form_data' => $order_data,
'payment_gateway' => isset($order_data['payment_gateway']) ? sanitize_text_field($order_data['payment_gateway']) : '',
'meta_data' => $order_meta_data,
];
$submit = $this->submit($submit_args);
$order_date = formipay_date('Y-m-d H:i:s');
$form_settings = formipay_get_post_meta($form_id, 'formipay_settings');
$global_settings = get_option('formipay_settings');
$thankyou_link = (!empty($global_settings['thankyou_link'])) ? $global_settings['thankyou_link'] : 'thankyou';
if ($submit !== false) {
$order_data = formipay_get_order($submit);
$this->order_data = apply_filters('formipay/order/result', $order_data);
do_action('formipay/order/new', $this->order_data);
do_action('formipay/order/on-hold', $this->order_data);
do_action('formipay/notification/order', $this->order_data);
$submit_action_type = formipay_get_post_meta($form_id, 'submit_action_type');
$success_message = formipay_get_post_meta($form_id, 'success_response_content');
$success_message = $this->process_response_content($success_message, 'thankyou');
$unique_id = isset($order_meta_data['session_id']) ? sanitize_text_field($order_meta_data['session_id']) : '';
$thankyou_url = site_url('/' . $thankyou_link . '/' . base64_encode($form_id . ':::' . $order_data['id'] . ':::' . $unique_id));
setcookie('fp_access', maybe_serialize([$order_data['id'] => $unique_id]), time() + 86400, '/');
if (
!empty($this->order_data['redirect_url']) &&
$submit_action_type !== 'whatsapp'
) {
$redirect_url = esc_url_raw($this->order_data['redirect_url']);
} else {
switch ($submit_action_type) {
case 'redirect':
$redirect_url = esc_url_raw(formipay_get_post_meta($form_id, 'redirect_url'));
break;
case 'whatsapp':
$admin_number = sanitize_text_field(formipay_get_post_meta($form_id, 'whatsapp_admin'));
$whatsapp_message_format = formipay_get_post_meta($form_id, 'whatsapp_message');
$redirect_url = 'https://wa.me/' . $admin_number . '?text=' . rawurlencode($this->process_response_content($whatsapp_message_format, $submit_action_type));
break;
default:
$redirect_url = esc_url_raw($thankyou_url);
break;
}
}
wp_send_json_success([
'message' => wp_kses_post($success_message),
'response_type' => formipay_get_post_meta($form_id, 'response_type'),
'action_type' => $submit_action_type,
'url' => $redirect_url,
]);
}
$message = formipay_get_post_meta($form_id, 'failed_response_content');
$message = str_replace('{{error_message}}', $submit->error_message(), $message);
wp_send_json_error(['message' => wp_kses_post($message)]);
}
public function process_order_shortcodes($submit_action_type) {
$buyer_name = '';
if(!empty(formipay_get_post_meta($this->form_id, 'buyer_name'))){
$buyer_name_field = formipay_get_post_meta($this->form_id, 'buyer_name');
$buyer_name = $this->order_data['form_data'][$buyer_name_field];
}
$shortcodes = [
'buyer_name' => $buyer_name,
'product_name' => html_entity_decode(get_the_title($this->form_id)),
'order_id' => $this->order_data['id'],
'order_date' => $this->order_data['created_date'],
'order_total' => formipay_price_format($this->order_data['total'], $this->form_id),
'order_status' => $this->order_data['status'],
'order_details' => $this->render_order_details($submit_action_type),
'form_submission' => $this->render_form_submit($submit_action_type)
];
$shortcodes = apply_filters( 'formipay/order/shortcodes', $shortcodes, $this->form_id, $this->order_data, $submit_action_type );
return $shortcodes;
}
public function process_order_details() {
$details = [];
$product_price = floatval(formipay_get_post_meta($this->form_id, 'product_price'));
$details[] = [
'item' => html_entity_decode(get_the_title($this->form_id)),
'amount' => $product_price,
'qty' => $this->order_data['qty'],
'subtotal' => floatval($product_price) * intval($this->order_data['qty']),
'context' => 'main'
];
$check_fields = formipay_get_post_meta($this->form_id, 'formipay_settings');
if(!empty($check_fields['fields'])){
foreach($check_fields['fields'] as $field){
// if($field['field_type'] == 'select'){
if(in_array($field['field_type'], ['select','checkbox', 'radio'])) {
$options = $field['field_options'];
if(!empty($options)){
foreach($options as $option){
$option_value = ($field['show_toggle']['value'] && '' !== $option['value']) ? $option['value'] : $option['label'];
if(!empty($this->order_data[$field['field_id']])) {
$field_value = $this->order_data[$field['field_id']];
if($field['field_type'] == 'select'){
$field_value = ($field['show_toggle']['value']) ?
$this->order_data[$field['field_id']]['value'] :
$this->order_data[$field['field_id']]['label'];
}
$field_value = explode(',', $field_value);
$context = 'no-context';
if(floatval($option['amount']) < 0){
$context = 'sub';
}elseif(floatval($option['amount']) > 0){
$context = 'add';
}
if(!empty($field_value) && $field['show_toggle']['amount'] == 'yes'){
foreach($field_value as $f_value){
if($option_value == $f_value){
$qty = ($option['qty'] == 'yes') ? $this->order_data['qty'] : 1;
$details[] = [
'item' => $field['label'] .' - '. $option['label'],
'amount' => floatval($option['amount']),
'qty' => $qty,
'subtotal' => floatval($option['amount']) * intval($qty),
'context' => $context
];
}
}
}
}
}
}
}
}
}
$details = apply_filters('formipay/order/order-details', $details, $this->form_id, $this->order_data );
return $details;
}
public function process_order_total() {
$detail_total = 0.00;
if(!empty($this->order_details)){
foreach ($this->order_details as $detail) {
$detail_total += $detail['subtotal'];
}
}
$order_total = apply_filters('formipay/order/set-total', $detail_total, $this->form_id, $this->order_data);
if($order_total <= 0){
$order_total = 0;
}
return $order_total;
}
public function process_response_content($content, $submit_action_type){
$shortcodes = $this->process_order_shortcodes($submit_action_type);
// $target = [];
// $replace_to_be = [];
$replacements = [];
if(!empty($shortcodes)){
foreach($shortcodes as $key => $value){
// $target[] = '{{'.$key.'}}';
// $replace_to_be[] = $value;
$replacements['{{'.$key.'}}'] = $value;
}
}
// $content = str_replace($target, $replace_to_be, $content);
$content = strtr($content, $replacements);
if($submit_action_type == 'whatsapp'){
$content = str_replace(
[
PHP_EOL, "\n", ' '
],
[
'%0A', '%0A', '%20'
],
$content
);
}
return $content;
}
public function render_order_details($submit_action_type) {
if($submit_action_type == 'thankyou'){
ob_start();
if(!empty($this->order_details)){
?>
<table id="order-details">
<tbody>
<?php
foreach($this->order_details as $detail){
$qty = '';
if(isset($detail['qty'])){
$qty = ' <i class="bi bi-x"></i> '.$detail['qty'];
}
?>
<tr>
<th><?php echo esc_html($detail['item'] . $qty); ?></th>
<td><?php echo esc_html(formipay_price_format($detail['subtotal'], $this->form_id)); ?></td>
</tr>
<?php
}
?>
<tr>
<th><?php echo esc_html__( 'Total', 'formipay' ); ?></th>
<td><b><?php echo esc_html(formipay_price_format($this->order_data['total'], $this->form_id)); ?></b></td>
</tr>
</tbody>
</table>
<?php
}
$content = ob_get_contents();
ob_get_clean();
}elseif($submit_action_type == 'whatsapp'){
$target_length = 24;
$message_format = formipay_get_post_meta($this->form_id, 'whatsapp_message');
$order_details_message = '';
if(!empty($this->order_details)){
foreach($this->order_details as $detail){
$qty = '';
if(isset($detail['qty']) && !empty($detail['qty'])){
$qty = $detail['qty'].'×';
}
$subtotal = formipay_price_format($detail['subtotal'], $this->form_id);
$qty_length = strlen($qty);
$subtotal_length = strlen($subtotal);
if(floatval($detail['subtotal']) < 0){
$subtotal_length = $subtotal_length + 1;
}
$dot_length = $target_length - ($qty_length + $subtotal_length);
$dots = str_repeat('.', intval($dot_length));
$order_details_message .= "%0A".$detail['item'];
$order_details_message .= "%0A".$qty.$dots.$subtotal;
}
$total = formipay_price_format($this->order_data['total'], $this->form_id);
$total_length = strlen($total);
$dot_length = $target_length - ($total_length + 6);
$dots = str_repeat('.', intval($dot_length));
$divider = str_repeat('_', intval($target_length));
$order_details_message .= "%0A".$divider."%0A%0A".'Total'.$dots.$total;
}
$order_details_message .= '';
$content = '%60%60%60'.$order_details_message.'%60%60%60';
}else{
$content = apply_filters( 'formipay/order/order-details/shortcode-render', '', $this->form_id, $this->order_details, $submit_action_type );
}
return $content;
}
public function render_form_submit($submit_action_type) {
ob_start();
if(!empty($this->order_data)){
$field_config = formipay_get_post_meta($this->order_data['form_id'], 'formipay_settings');
$skip_row = array(
'form_id', 'payment', 'id', 'status', 'total', 'created_date', 'redirect_url', 'items', 'form_data', 'meta_data'
);
$rows = [];
foreach($this->order_data['form_data'] as $field_name => $field_value){
$field_value = $field_value['value'];
// $field_label = $field_config['fields'][$field_name.'_config']['label'];
if(in_array($field_name, $skip_row)){
continue;
}
switch ($field_name) {
case 'form_id':
$field_label = __( 'Form ID', 'formipay' );
break;
case 'qty':
$field_label = __( 'Quantity', 'formipay' );
break;
case 'coupon_code':
$field_label = __( 'Coupon Code', 'formipay' );
break;
case 'payment':
$field_label = __( 'Payment', 'formipay' );
break;
case 'payment_gateway':
$field_label = __( 'Payment Gateway', 'formipay' );
$field_value = ucwords(str_replace('_', ' ', $field_value));
break;
case 'id':
$field_label = __( 'Order ID', 'formipay' );
break;
case 'total':
$field_label = __( 'Grand Total', 'formipay' );
$field_value = formipay_price_format($field_value, $this->form_id);
break;
case 'status':
$field_label = __( 'Order Status', 'formipay' );
break;
case 'created_date':
$field_label = __( 'Order Date', 'formipay' );
break;
default:
$field_label = $field_config['fields'][$field_name.'_config']['label'];
if(is_array($field_value)){
$field_value = $field_value['value'];
}
if(filter_var($field_value, FILTER_VALIDATE_EMAIL)){
$field_value = $field_value;
}elseif(strpos($field_value, ',') !== false){
$values = explode(',', $field_value);
$field_value = '';
foreach($values as $value){
$field_value .= '<span class="checkbox-span">'.$value.'</span> ';
}
}else{
$field_value = ucwords(str_replace(['-','_'], ' ', $field_value));
}
break;
}
$rows[] = [
'label' => $field_label,
'value' => $field_value
];
}
if($submit_action_type == 'thankyou') {
?>
<table id="order-submission-details">
<tbody>
<tr>
<th><?php echo esc_html__('Product', 'formipay'); ?></th>
<td><?php echo esc_html(get_the_title($this->form_id)); ?></td>
</tr>
<?php
foreach($rows as $row) {
?>
<tr>
<th><?php echo esc_html($row['label']); ?></th>
<td><?php echo esc_html($row['value']); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
<?php
ob_get_clean();
$content = ob_get_contents();
}elseif($submit_action_type == 'whatsapp') {
$content = '';
foreach($rows as $row){
$content .= "%0A".rawurlencode($row['label'].': *'.$row['value'].'*');
}
}
}
return $content;
}
public function submit($args) {
$args = wp_parse_args( $args, [
'form_id' => 0,
'items' => [],
'total' => 0,
'status' => 'on-hold',
'form_data' => [],
'payment_gateway' => '',
'meta_data' => []
] );
global $wpdb;
$table = $wpdb->prefix . 'formipay_orders';
$insert_data = [
'created_date' => formipay_date('Y-m-d H:i:s'),
'form_id' => intval($args['form_id']),
'items' => maybe_serialize($args['items']),
'total' => floatval($args['total']),
'status' => sanitize_text_field( $args['status'] ),
'form_data' => maybe_serialize($args['form_data']),
'payment_gateway' => sanitize_text_field($args['payment_gateway']),
'meta_data' => maybe_serialize($args['meta_data'])
];
if($args['form_id'] > 0){
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
$wpdb->insert($table, $insert_data);
return $wpdb->insert_id;
}
return false;
}
public function get($order_id = 0) {
global $wpdb;
$table = $wpdb->prefix .'formipay_orders';
if($order_id == 0){
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM %i", $table
)
);
}else{
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM %i WHERE `id` = %d", $table, $order_id
)
);
}
return $get;
}
public function get_order_by_id($data, $order_id){
global $wpdb;
$table = $wpdb->prefix .'formipay_orders';
if($order_id == 0){
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$data = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM %i", $table),
ARRAY_A
);
}else{
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$data = $wpdb->get_row(
$wpdb->prepare("SELECT * FROM %i WHERE `id` = %d", $table, $order_id),
ARRAY_A);
}
return $data;
}
public function get_by_form_id($form_id, $search='', $limit=false, $offset=false) {
global $wpdb;
$table = $wpdb->prefix .'formipay_orders';
if(false == $limit && false == $offset){
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM %i WHERE `form_id` = %d", $table, $form_id
)
);
}else{
if('' == $search){
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM %i WHERE `form_id` = %d ORDER BY `id` DESC LIMIT %d, %d",
$table, $form_id, $offset, $limit
)
);
}else{
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM %i WHERE `form_id` = %d AND `form_data` LIKE %s ORDER BY `id` DESC LIMIT %d, %d",
$table, $form_id, '%'.$search.'%',$offset, $limit)
);
}
}
return $get;
}
public function add_menu() {
add_submenu_page(
'formipay',
__( 'Orders', 'formipay' ),
__( 'Orders', 'formipay' ),
'manage_options',
'formipay-orders',
[$this, 'orders_page']
);
}
public function orders_page() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$order_id = isset($_GET['order_id']) ? intval($_GET['order_id']) : 0;
if(empty($order_id)){
include FORMIPAY_PATH . 'admin/page-orders.php';
}else{
$order = formipay_get_order( $order_id );
include FORMIPAY_PATH . 'admin/page-order-details.php';
}
}
public function enqueue() {
global $current_screen;
if($current_screen->id == 'formipay_page_formipay-orders') {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$order_id = isset($_GET['order_id']) ? intval($_GET['order_id']) : 0;
if(empty($order_id)){
wp_enqueue_style( 'page-orders', FORMIPAY_URL . 'admin/assets/css/admin-orders.css', [], FORMIPAY_VERSION, 'all' );
wp_enqueue_script( 'page-orders', FORMIPAY_URL . 'admin/assets/js/admin-orders.js', ['jquery', 'gridjs'], FORMIPAY_VERSION, true );
wp_localize_script( 'page-orders', 'formipay_orders_page', [
'ajax_url' => admin_url('admin-ajax.php'),
'site_url' => site_url(),
'columns' => [
'id' => esc_html__( 'ID', 'formipay' ),
'form' => esc_html__( 'Form', 'formipay' ),
'total' => esc_html__( 'Total', 'formipay' ),
'date' => esc_html__( 'Date', 'formipay' ),
'payment_gateway' => esc_html__( 'Payment Gateway', 'formipay' ),
'status' => esc_html__( 'Status', 'formipay' ),
],
'filter_form' => [
'products' => [
'placeholder' => esc_html__( 'Filter by Product', 'formipay' ),
'noresult_text' => esc_html__( 'No results found', 'formipay' )
],
'currencies' => [
'placeholder' => esc_html__( 'Filter by Currency', 'formipay' ),
'noresult_text' => esc_html__( 'No results found', 'formipay' )
]
],
'nonce' => wp_create_nonce( 'formipay-order-details' )
] );
}else{
wp_enqueue_style( 'bootstrap-icon', FORMIPAY_URL . 'vendor/Bootstrap/bootstrap-icons.css', [], '1.11.1', 'all');
wp_enqueue_style( 'bootstrap', FORMIPAY_URL . 'vendor/Bootstrap/bootstrap.min.css', [], '5.3.2' );
wp_enqueue_style( 'page-orders', FORMIPAY_URL . 'admin/assets/css/admin-order-details.css', [], FORMIPAY_VERSION, 'all' );
wp_enqueue_script( 'handlebars', FORMIPAY_URL . 'vendor/HandleBars/handlebars.min.js', [], '4.7.7', true);
wp_enqueue_script( 'bootstrap', FORMIPAY_URL . 'vendor/Bootstrap/bootstrap.bundle.min.js', ['jquery'], '5.3.2', true );
wp_enqueue_script( 'page-orders', FORMIPAY_URL . 'admin/assets/js/admin-order-details.js', ['jquery'], FORMIPAY_VERSION, true );
wp_localize_script( 'page-orders', 'formipay_order_details_page', [
'ajax_url' => admin_url('admin-ajax.php'),
'site_url' => site_url(),
'order_id' => $order_id,
'order_detail' => [
'change_order_status_confirmation' => esc_html__( 'Are you sure to change status?', 'formipay' ),
'change_order_status_button_confirm' => esc_html__( 'Change', 'formipay' ),
'change_order_status_button_cancel' => esc_html__( 'Cancel', 'formipay' ),
'edit_button_loading_text' => esc_html__( 'Preparing...', 'formipay' ),
'update_button_loading_text' => esc_html__( 'Updating...', 'formipay' ),
'pass_method' => [
'magic_link' => esc_html__( 'Magic Link', 'formipay' ),
'static_password' => esc_html__( 'Static Password', 'formipay' )
]
],
'modal' => [
'delete' => [
'question' => esc_html__( 'Do you want to delete the order?', 'formipay' ),
'cancelButton' => esc_html__( 'Cancel', 'formipay' ),
'confirmButton' => esc_html__( 'Delete Permanently', 'formipay' )
],
'bulk_delete' => [
'question' => esc_html__( 'Do you want to delete the selected the order(s)?', 'formipay' ),
'cancelButton' => esc_html__( 'Cancel', 'formipay' ),
'confirmButton' => esc_html__( 'Confirm', 'formipay' )
],
],
'nonce' => wp_create_nonce( 'formipay-order-details' )
] );
}
}
}
public function formipay_get_all_forms() {
$all_forms = get_posts([
'post_type' => 'formipay-form',
'posts_per_page' => -1
]);
$forms = [];
if(!empty($all_forms)){
foreach($all_forms as $form){
$forms[$form->ID] = get_the_title($form->ID);
}
}
wp_send_json( $forms );
}
public function get_all_field_name($formid) {
$meta = get_post_meta($formid, 'formipay_settings', true);
$headers = $meta['fields'];
$table_header = [];
if(!empty($headers)){
foreach($headers as $config => $header){
$header_id = $header['field_id'];
$table_header[$header_id] = $header['label'];
}
}
return $table_header;
}
public function formipay_orders_get_choices() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
$type = isset($_REQUEST['type']) ? sanitize_text_field( wp_unslash($_REQUEST['type']) ) : '';
$search = isset($_REQUEST['search']) ? sanitize_text_field( wp_unslash($_REQUEST['search']) ) : '';
$results = [];
if($type == 'form'){
$args = [
'post_type' => 'formipay-form',
'posts_per_page' => -1,
];
if('' !== $search) {
$args['s'] = $search;
}
$get = get_posts($args);
if(!empty($get)){
foreach($get as $post){
$results[] = [
'value' => $post->ID,
'label' => $post->post_title
];
}
}
}elseif($type == 'currency'){
$countries = formipay_currency_array();
foreach($countries as $country){
$country_name = strtolower($country['name']);
$country_search = strtolower($search);
if(strpos($country_name, $country_search) !== false || $country_search == strtolower($country['code'])){
$results[] = [
'value' => $country['code'],
// phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage
'label' => '<img src="'.formipay_get_flag_by_currency($country['code']).'" height="18" style="margin-bottom: -3px;"> '.$country['name']
];
}
}
}
wp_send_json($results);
}
public function update($order_id, $args) {
global $wpdb;
$table_name = $wpdb->prefix . 'formipay_orders';
// Get current data safely
$recent_data = $this->get($order_id);
if (!$recent_data) {
return new WP_Error('invalid_order', __('Order not found', 'formipay'));
}
// Parse args with type safety
$args = wp_parse_args($args, [
'form_id' => (int)$recent_data->form_id,
'items' => maybe_unserialize($recent_data->items) ?: [],
'total' => (float)$recent_data->total,
'status' => sanitize_text_field($recent_data->status),
'form_data' => maybe_unserialize($recent_data->form_data) ?: [],
'payment_gateway' => sanitize_text_field($recent_data->payment_gateway),
'meta_data' => maybe_unserialize($recent_data->meta_data) ?: []
]);
// Prepare update log
$update_time = current_time('mysql');
$user_id = get_current_user_id();
$changes = [];
$status_changed = false;
// Compare values properly (unserialized)
$compare_fields = [
'items' => ['before' => maybe_unserialize($recent_data->items), 'after' => $args['items']],
'total' => ['before' => (float)$recent_data->total, 'after' => (float)$args['total']],
'status' => ['before' => $recent_data->status, 'after' => $args['status']],
'form_data' => ['before' => maybe_unserialize($recent_data->form_data), 'after' => $args['form_data']],
'payment_gateway' => ['before' => $recent_data->payment_gateway, 'after' => $args['payment_gateway']]
];
foreach ($compare_fields as $field => $values) {
if ($values['before'] !== $values['after']) {
$changes[$field] = [
'before' => $this->sanitize_log_value($values['before']),
'after' => $this->sanitize_log_value($values['after'])
];
if ($field === 'status') {
$status_changed = true;
}
}
}
// Update meta_data with log
if (!empty($changes)) {
$args['meta_data']['update_log'][] = [
'timestamp' => $update_time,
'user_id' => $user_id,
'changes' => $changes
];
}
// Prepare database update
$new_args = [
'form_id' => (int)$args['form_id'],
'items' => maybe_serialize($args['items']),
'total' => (float)$args['total'],
'status' => sanitize_text_field($args['status']),
'form_data' => maybe_serialize($args['form_data']),
'payment_gateway' => sanitize_text_field($args['payment_gateway']),
'meta_data' => maybe_serialize($args['meta_data'])
];
$formats = [
'%d', // form_id
'%s', // items
'%f', // total
'%s', // status
'%s', // form_data
'%s', // payment_gateway
'%s' // meta_data
];
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
$updated = $wpdb->update(
$table_name,
$new_args,
['id' => (int)$order_id],
$formats,
['%d']
);
// Trigger actions if status changed
if ($status_changed && $updated) {
$order_data = $this->get($order_id);
do_action("formipay/order/{$args['status']}", $order_data);
do_action('formipay/notification/order', $order_data);
}
return $updated;
}
public function delete($order_id) {
global $wpdb;
return $wpdb->delete(
$wpdb->prefix . 'formipay_orders',
['id' => $id],
['%d'],
);
}
private function sanitize_log_value($value) {
if (is_array($value)) {
return array_map([$this, 'sanitize_log_value'], $value);
}
return sanitize_text_field(wp_unslash($value));
}
public function formipay_tabledata_orders() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
$all_orders = $this->get();
$order_status = [
'all' => 0,
'completed' => 0,
'on-hold' => 0,
'payment-confirm' => 0
];
// Count order statuses
if (!empty($all_orders)) {
foreach ($all_orders as $order) {
$order_status['all']++;
$order_status[$order->status]++;
}
}
global $wpdb;
$table = $wpdb->prefix . 'formipay_orders';
$where = [];
$params = [];
// ID filter
if (!empty(intval($_REQUEST['order_id']))) {
$where[] = "`id` = %d";
$params[] = intval($_REQUEST['order_id']);
} else {
$where[] = "`id` > %d";
$params[] = 0;
}
// Status filter
if (isset($_REQUEST['order_status']) && 'all' !== $_REQUEST['order_status']) {
$where[] = "`status` = %s";
$params[] = sanitize_text_field(wp_unslash($_REQUEST['order_status']));
}
// Product filter
if (isset($_REQUEST['product']) && 0 < intval($_REQUEST['product'])) {
$where[] = "`form_id` = %d";
$params[] = intval($_REQUEST['product']);
}
// Combine WHERE clause
$where_sql = implode(' AND ', $where);
$sql = "SELECT * FROM {$table} WHERE $where_sql ORDER BY `id` DESC";
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get_all_orders = $wpdb->get_results($wpdb->prepare($sql, ...$params));
// For paginated query:
$limit = intval($_REQUEST['limit'] ?? 10);
$offset = intval($_REQUEST['offset'] ?? 0);
$sql_paginated = $sql . " LIMIT %d OFFSET %d";
$params_paginated = array_merge($params, [$limit, $offset]);
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get_filtered_orders = $wpdb->get_results($wpdb->prepare($sql_paginated, ...$params_paginated));
$orders = [];
// Process filtered orders
if (!empty($get_filtered_orders)) {
foreach ($get_filtered_orders as $key => $order) {
$currency = explode(':::', formipay_get_post_meta($order->form_id, 'product_currency'));
$code = !empty($currency[0]) ? $currency[0] : '';
// Prepare order data
$orders[] = [
'ID' => $order->id,
'form' => get_the_title($order->form_id),
'date' => $order->created_date,
'payment_gateway' => ucwords(str_replace('_', ' ', $order->payment_gateway)),
'status' => ucwords(str_replace('-', ' ', $order->status)),
'total' => [
'flag' => formipay_get_flag_by_currency($code),
'name' => $code,
'value' => formipay_price_format($order->total, $order->form_id),
]
];
}
}
// Prepare response data
$response = [
'results' => $orders,
'total' => count($get_all_orders),
'posts_report' => $order_status
];
wp_send_json($response);
}
public function formipay_delete_order() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
$order_id = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
$delete = $this->delete($order_id);
if(is_wp_error( $delete )){
wp_send_json_error( [
'title' => esc_html__( 'Failed', 'formipay' ),
'message' => esc_html__( 'Failed to delete ortder. Please try again.', 'formipay' ),
'icon' => 'error'
] );
}
wp_send_json_success( [
'title' => esc_html__( 'Deleted', 'formipay' ),
'message' => esc_html__( 'Order is deleted permanently.', 'formipay' ),
'icon' => 'success'
] );
}
public function formipay_bulk_delete_order() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
if( empty($_REQUEST['ids']) ){
wp_send_json_error( [
'title' => esc_html__( 'Failed', 'formipay' ),
'message' => esc_html__( 'There is no coupon selected. Please try again.', 'formipay' ),
'icon' => 'error'
] );
}
$ids = isset($_REQUEST['ids']) ? $_REQUEST['ids'] : [];
$success = 0;
$failed = 0;
$report = __( 'Done.', 'formipay' );
if(!empty($ids)){
foreach($ids as $id){
$delete = $this->delete($order_id);
if(is_wp_error( $delete )){
$failed++;
}else{
$success++;
}
}
}
if($success > 0){
$report .= sprintf( __( ' Deleted %d coupon(s).', 'formipay' ), $success);
}
if($failed > 0){
$report .= sprintf( __( ' Failed %d coupon(s).', 'formipay' ), $failed);
}
wp_send_json_success( [
'title' => esc_html__( 'Done!', 'formipay' ),
'message' => $report,
'icon' => 'info'
] );
}
public function formipay_load_order_data() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
$order_id = isset($_REQUEST['order']) ? intval($_REQUEST['order']) : 0;
wp_send_json(formipay_get_order($order_id));
}
public function formipay_change_order_status() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
$order_id = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
$status = isset($_REQUEST['status']) ? sanitize_text_field( wp_unslash($_REQUEST['status']) ) : '';
if ($order_id > 0 && $status !== '') {
$update = $this->update($order_id, ['status' => $status]);
if (is_wp_error($update)) {
wp_send_json_error([
'message' => $update->get_error_message(),
'code' => $update->get_error_code(),
]);
}
wp_send_json_success([
'message' => sprintf(
esc_html__('Change status order of #%d is success', 'formipay'),
$order_id
),
]);
}
wp_send_json_error([
'message' => sprintf(
esc_html__('Change status order of #%d is failed', 'formipay'),
$order_id
),
]);
}
public function formipay_check_editable_field() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
$editable_field = [];
$order_id = isset($_REQUEST['order_id']) ? intval($_REQUEST['order_id']) : 0;
$get_order_data = formipay_get_order($order_id);
$form_id = $get_order_data['form_id'];
$field_types = formipay_field_type_collection();
$form_field = formipay_get_post_meta($form_id, 'formipay_settings');
$form_field = $form_field['fields'];
unset($field_types['divider']);
unset($field_types['page_break']);
unset($field_types['country_list']);
foreach($form_field as $key => $field){
if(array_key_exists($field['field_type'], $field_types)){
$skip = false;
if(in_array($field['field_type'], ['select', 'checkbox', 'radio'])){
$options = $field['field_options'];
if(!empty($options)){
foreach($options as $option){
if('' !== $option['amount']){
if(isset($get_order_data['status']) && $get_order_data['status'] == 'completed'){
$skip = true;
}
}
}
}
}
if(false == $skip){
$editable_field[$key] = $field;
}
}
}
wp_send_json($editable_field);
}
public function formipay_update_editable_field_data() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
$order_id = isset($_REQUEST['order_id']) ? intval($_REQUEST['order_id']) : 0;
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$raw_data = isset($_REQUEST['new_values']) ? wp_unslash( $_REQUEST['new_values'] ) : [];
$data = is_array($raw_data) ? formipay_sanitize_array($raw_data) : sanitize_text_field($raw_data);
$new_values = [];
if(!empty($data)){
foreach($data as $_data){
$name = $_data['name'];
$new_values[$name] = $_data['value'];
}
}
$get_order_data = formipay_get_order($order_id);
if(!empty($get_order_data)){
$current_form_data = $get_order_data['form_data'];
$new_form_data = [];
foreach($current_form_data as $current_data){
$field_name = $current_data['name'];
$field_value = $current_data['value'];
if(isset($new_values[$field_name])) {
$field_value = $new_values[$field_name];
}
$new_form_data[$field_name] = $field_value;
}
$update_form_data = $this->update($order_id, ['form_data' => $new_form_data]);
if (is_wp_error($update_form_data)) {
wp_send_json_error([
'message' => $update_form_data->get_error_message(),
'code' => $update_form_data->get_error_code(),
]);
}
wp_send_json_success( [
'message' => esc_html__( 'Succesfully change transaction data', 'formipay' )
] );
}
wp_send_json_error( [
'message' => esc_html__( 'Error. Data is not available or not able to be changed. Try again.', 'formipay' )
] );
}
public function formipay_update_digital_access() {
check_ajax_referer( 'formipay-order-details', '_wpnonce' );
$order_id = isset($_REQUEST['order_id']) ? intval($_REQUEST['order_id']) : 0;
$method = isset($_REQUEST['method']) ? sanitize_text_field( wp_unslash($_REQUEST['method']) ) : '';
$password = isset($_REQUEST['password']) ? sanitize_text_field( wp_unslash($_REQUEST['password']) ) : '';
$get_order_data = $this->get($order_id);
$meta_data = maybe_unserialize($get_order_data->meta_data);
$meta_data['access_method'] = $method;
if($method == 'static_password'){
$meta_data['access_password'] = $password;
}
$update_meta_data = $this->update($order_id, ['meta_data' => $meta_data]);
if(is_wp_error($update_meta_data)){
wp_send_json_error([
'message' => $update_meta_data->get_error_message(),
'code' => $update_meta_data->get_error_code(),
]);
}
wp_send_json_success( [
'message' => esc_html__( 'Succesfully set access data', 'formipay' )
] );
}
}