get_charset_collate(); $create[] = "CREATE TABLE `{$wpdb->base_prefix}formipay_bank_transfer_trx` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `created_date` datetime DEFAULT CURRENT_TIMESTAMP, `form_id` int DEFAULT 0, `order_id` int DEFAULT 0, `channel` text NOT NULL, `total` float(10, 2) DEFAULT 0, `unique_code` int DEFAULT 0, `meta_data` text, PRIMARY KEY (`id`) ) $charset_collate;"; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; dbDelta($create); } public function add_transaction($order_data) { global $wpdb; $formipay_settings = get_option('formipay_settings'); $timeout = isset($formipay_settings['bank_transfer_timeout']) ? (int) $formipay_settings['bank_transfer_timeout'] : 1440; $table = $wpdb->prefix . 'formipay_bank_transfer_trx'; if ($order_data['payment_gateway'] == 'bank_transfer') { $submit_args = [ 'created_date' => formipay_date('Y-m-d H:i:s', strtotime($order_data['created_date'])), 'form_id' => intval($order_data['form_id']), 'order_id' => intval($order_data['id']), 'channel' => sanitize_text_field(str_replace($order_data['payment_gateway'].':::', '', $order_data['form_data']['payment'])), 'total' => floatval($order_data['total']), 'unique_code' => sanitize_text_field($this->check_unique_code()), 'meta_data' => maybe_serialize(array()) ]; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $inserted = $wpdb->insert($table, $submit_args); wp_schedule_single_event( (int) formipay_date('timestamp') + $timeout, 'formipay/order/payment-timeout', [ 'order_id' => $order_data['id'], 'payment_gateway' => 'bank_transfer' ] ); } } public function auto_cancel_order_on_timeout($order_id, $payment_gateway) { if($payment_gateway == 'bank_transfer'){ global $wpdb; $order = formipay_get_order($order_id); if($order['status'] !== 'completed'){ Order::update($order_id, [ 'status' => 'cancelled' ]); } $this->cancel_payment($order); } } public function cancel_payment($order_data){ do_action('formipay/notification/order', $order_data); } public function check_unique_code() { global $wpdb; $table = $wpdb->prefix . 'formipay_bank_transfer_trx'; // Get the highest existing ID efficiently // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching $max_id = $wpdb->get_var("SELECT MAX(id) FROM $table"); $unique_code = !is_null($max_id) ? ($max_id + 1) : 1; $operation = get_option('bank_transfer_unique_code_operation'); return ($operation == 'add') ? $unique_code : "-{$unique_code}"; } public function add_unique_code_details($details, $form_id, $order_data){ if( floatval(formipay_get_post_meta($form_id, 'product_price')) > 0 && $order_data['payment_gateway'] == 'bank_transfer' ){ $details[] = [ 'item' => __( 'Unique Code', 'formipay' ), 'amount' => $this->check_unique_code(), 'subtotal' => floatval($this->check_unique_code()), 'context' => floatval($this->check_unique_code()) < 0 ? 'sub' : 'add' ]; } return $details; } public function add_gateway($gateways){ $formipay_settings = get_option('formipay_settings'); if(isset($formipay_settings[$this->gateway.'_toggle']) && false !== $formipay_settings[$this->gateway.'_toggle']){ if(isset($formipay_settings[ $this->gateway.'_channels' ]) && !empty($formipay_settings[ $this->gateway.'_channels' ])){ $channels = $formipay_settings[ $this->gateway.'_channels' ]; $channel_options = []; if(!empty($channels)){ foreach($channels as $index => $channel){ $id = $this->gateway.':::'.$channel[$this->gateway.'_name'].'-'.$index; $gateways[] = [ 'id' => $id, 'gateway' => __( 'Bank', 'formipay' ), 'channel' => $channel[$this->gateway.'_name'] ]; } } } } return $gateways; } public function add_bank_transfer_settings($fields){ $banktransfer_field = array( $this->gateway.'_group' => array( 'type' => 'group_title', 'label' => __( 'Settings', 'formipay' ), 'description' => __( 'This will be shown in thank-you page and implemented when buyer uses one of Bank Transfer\'s channels', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'group' => 'started' ), $this->gateway.'_text_section_intro' => array( 'type' => 'text', 'label' => __( 'Payment Details Intro', 'formipay' ), 'value' => __( 'Please complete payment to:', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ) ), $this->gateway.'_confirmation_submit_button' => array( 'type' => 'text', 'label' => __( 'Payment Confirmation Submit Button Text', 'formipay' ), 'value' => __( 'Upload', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'group' => 'ended' ), $this->gateway.'_confirmation_notice_message_group' => array( 'type' => 'group_title', 'label' => __( 'Confirmation Notice Messages', 'formipay' ), 'description' => __( 'Set notice message on every condition about attempting to confirm the payment', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'group' => 'started' ), $this->gateway.'_confirmation_update_to_status' => array( 'type' => 'select', 'label' => __( 'Change status order to', 'formipay' ), 'options' => formipay_order_status_list(), 'value' => 'payment-confirm', 'submenu' => __( 'Bank Transfer', 'formipay' ), ), $this->gateway.'_confirmation_message_success' => array( 'type' => 'hint_textarea', 'label' => __( 'Successfully Confirmed Message', 'formipay' ), 'hints' => array( 'order_id' => __('Order ID', 'formipay') ), 'value' => __('Successfully confirmed payment for #{{order_id}}', 'formipay'), 'description' => __('When successfully change the order status to the preferred one', 'formipay'), 'submenu' => __( 'Bank Transfer', 'formipay' ), ), $this->gateway.'_confirmation_message_already_confirmed' => array( 'type' => 'hint_textarea', 'label' => __( 'Has Been Confirmed Message', 'formipay' ), 'hints' => array( 'order_id' => __('Order ID', 'formipay') ), 'value' => __('#{{order_id}} has been confirmed', 'formipay'), 'description' => __('When the order status has been the preferred one', 'formipay'), 'submenu' => __( 'Bank Transfer', 'formipay' ), ), $this->gateway.'_confirmation_message_error' => array( 'type' => 'hint_textarea', 'label' => __( 'Failed to Confirm Message', 'formipay' ), 'hints' => array( 'order_id' => __('Order ID', 'formipay'), 'system_error_message' => __('System Error Message', 'formipay') ), 'value' => __('Failed to proceed. Error: {{system_error_message}}', 'formipay'), 'description' => __('When error to change the order status to the preferred one', 'formipay'), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'group' => 'ended' ) ); foreach($banktransfer_field as $key => $value){ $fields[$key] = $value; } return $fields; } public function add_settings($settings) { $bank_transfer = array( 'my_code_field' => [ 'type' => 'ace_editor', 'label' => __('Custom Code', 'formipay'), 'lang' => 'javascript', // or 'css', 'html', etc. 'theme' => 'chrome', 'value' => '', // default value 'required' => true, ], $this->gateway.'_toggle' => array( 'type' => 'checkbox', 'label' => __('Activate Bank Transfer', 'formipay'), 'submenu' => __( 'Bank Transfer', 'formipay' ) ), $this->gateway.'_general_group' => array( 'type' => 'group_title', 'label' => __( 'General', 'formipay' ), 'group' => 'started', 'dependency' => array( 'key' => $this->gateway.'_toggle', 'value' => 'not_empty' ), 'submenu' => __( 'Bank Transfer', 'formipay' ) ), $this->gateway.'_timeout' => array( 'type' => 'number', 'label' => __( 'Payment Timeout (minute)', 'formipay' ), 'description' => __( 'Set a timeout to wait for payment. After this timeout is up, the order status automatically changes to cancelled.', 'formipay' ), 'value' => 120, 'group' => 'ended', 'dependency' => array( 'key' => $this->gateway.'_toggle', 'value' => 'not_empty' ), 'submenu' => __( 'Bank Transfer', 'formipay' ) ), $this->gateway.'_unique_codes' => array( 'type' => 'repeater', 'label' => esc_html__( 'Unique Codes', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'description' => __( 'Get unique total amount by adding unique code.', 'formipay' ), 'fields' => array( 'unique_code_currency' => array( 'type' => 'select', 'label' => __( 'Currency', 'formipay' ), 'description' => __( 'This setting is only applied when the selected currency matches the form currency.', 'formipay' ), 'options' => formipay_currency_as_options(), 'is_group_title' => true, 'searchable' => true, 'required' => true ), 'unique_code_toggle' => array( 'type' => 'checkbox', 'label' => __( 'Activate', 'formipay' ), 'description' => __( 'Generate unique code for this currency.', 'formipay' ), 'dependency' => array( 'key' => $this->gateway.'_toggle', 'value' => 'not_empty' ), ), 'unique_code_increment_step' => array( 'type' => 'number', 'label' => esc_html__( 'Increment Step', 'formipay' ), 'value' => 0.01, 'step' => 0.001, 'required' => true ), 'unique_code_max' => array( 'type' => 'number', 'label' => esc_html__( 'Max Amount', 'formipay' ), 'value' => 0.01, 'step' => 0.001, 'required' => true ), 'unique_code_operation' => array( 'type' => 'select', 'label' => __('Operation', 'formipay'), 'options' => array( 'sub' => __( '(-) Decrease Total Amount by Unique Code', 'formipay' ), 'add' => __( '(+) Increase Total Amount by Unique Code', 'formipay' ), ), 'value' => 'add', 'dependency'=> array( array( 'key' => $this->gateway.'_toggle', 'value' => 'not_empty' ), array( 'key' => $this->gateway.'_unique_code_toggle', 'value' => 'not_empty' ), ), 'dependencies' => '&&', 'required' => true, ), ) ), $this->gateway.'_confirmation_group' => array( 'type' => 'group_title', 'label' => __( 'Confirmation Form', 'formipay' ), 'description' => __( 'for order that use Bank Transfer gateway only.', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'dependency' => array( 'key' => 'bank_transfer_toggle', 'value' => 'not_empty', ), 'group' => 'started' ), $this->gateway.'_confirmation_dropzone_color' => array( 'type' => 'color', 'label' => __( 'Dropzone Box Background color', 'formipay' ), 'value' => '#cccccc', 'submenu' => __( 'Bank Transfer', 'formipay' ), 'dependency' => array( 'key' => 'bank_transfer_toggle', 'value' => 'not_empty', ), ), $this->gateway.'_confirmation_dropzone_text_color' => array( 'type' => 'color', 'label' => __( 'Dropzone Box Text Color', 'formipay' ), 'value' => '#808080', 'submenu' => __( 'Bank Transfer', 'formipay' ), 'dependency' => array( 'key' => 'bank_transfer_toggle', 'value' => 'not_empty', ), ), $this->gateway.'_confirmation_dropzone_instruction' => array( 'type' => 'text', 'label' => __( 'Dropzone Instruction', 'formipay' ), 'value' => __( 'Drag & drop a file here or click to select one', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'dependency' => array( 'key' => 'bank_transfer_toggle', 'value' => 'not_empty', ), ), $this->gateway.'_confirmation_submit_button' => array( 'type' => 'text', 'label' => __( 'Submit Button', 'formipay' ), 'value' => __( 'Upload', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'dependency' => array( 'key' => 'bank_transfer_toggle', 'value' => 'not_empty', ), 'group' => 'ended' ), $this->gateway.'_settings_group' => array( 'type' => 'group_title', 'label' => __( 'Account List', 'formipay' ), 'description' => __( 'Add all of your preferred bank accounts to receive the payment', 'formipay' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'dependency' => array( 'key' => $this->gateway.'_toggle', 'value' => 'not_empty' ), 'group' => 'started' ), $this->gateway.'_channels' => array( 'type' => 'repeater', 'label' => __('Bank Accounts', 'formipay'), 'fields' => array( $this->gateway.'_name' => array( 'type' => 'text', 'label' => __( 'Bank Name', 'formipay' ), 'required' => true, 'is_group_title' => true ), $this->gateway.'_account' => array( 'type' => 'text', 'label' => __( 'Bank Account', 'formipay' ), 'required' => true ), $this->gateway.'_account_holder' => array( 'type' => 'text', 'label' => __( 'Bank Account Holder', 'formipay' ), 'required' => true ), $this->gateway.'_logo' => array( 'type' => 'image', 'label' => __( 'Bank Logo', 'formipay' ), 'required' => true ), ), 'dependency' => array( 'key' => $this->gateway.'_toggle', 'value' => 'not_empty' ), 'submenu' => __( 'Bank Transfer', 'formipay' ), 'group' => 'ended' ) ); foreach($bank_transfer as $key => $value){ $settings[$key] = $value; } return $settings; } public function render_payment_details($render, $form_id, $order_data, $submit_action_type) { if(in_array($order_data['status'], ['completed', 'payment-confirm'])){ return $render; } $get_order = formipay_get_order($order_data['id']); $selected_payment = ''; // bank_transfer:::BNI-0 $payment_gateway = ''; if(!empty($get_order['form_data'])){ foreach($get_order['form_data'] as $_form_data){ if($_form_data['name'] == 'payment') { $selected_payment = $_form_data['value']; } if($_form_data['name'] == 'payment_gateway') { $payment_gateway = $_form_data['value']; } } } if('' !== $selected_payment){ $formipay_settings = get_option('formipay_settings'); if($formipay_settings[$payment_gateway.'_toggle'] !== false){ $gateway_channel = []; if(!empty($formipay_settings[$payment_gateway.'_channels'])){ foreach($formipay_settings[$payment_gateway.'_channels'] as $channel){ if(strpos($selected_payment, $channel[$payment_gateway.'_name']) !== false){ $gateway_channel = $channel; break; } } } if(!empty($gateway_channel)){ if($submit_action_type == 'thankyou'){ ob_start(); ?> '.wp_get_attachment_image( $gateway_channel['bank_transfer_logo'], 'thumbnail', false ); } ?>

".sprintf( esc_html__( 'Upload your transfer receipt to confirm the payment to %s', 'formipay' ), site_url('/'.$slug.'/'.base64_encode($form_id.':::'.$order_data['id'].':::'.$order_data['meta_data']['session_id']))); $render = $message; } } } } return $render; } public function handle_formipay_bank_transfer_confirmation() { // Capability check // if (!current_user_can('edit_posts')) { // wp_send_json_error(['message' => __('Permission denied', 'formipay')]); // exit; // } // Nonce verification if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'formipay_bank_transfer_confirmation')) { wp_send_json_error(['message' => __('Nonce verification failed', 'formipay')]); exit; } // Parameter sanitization $form_id = isset($_POST['form_id']) ? sanitize_text_field(wp_unslash($_POST['form_id'])) : ''; $order_id = isset($_POST['order_id']) ? sanitize_text_field(wp_unslash($_POST['order_id'])) : ''; // File validation if (empty($_FILES['file']['tmp_name']) || !is_uploaded_file(sanitize_text_field($_FILES['file']['tmp_name']))) { wp_send_json_error(['message' => __('Invalid file upload', 'formipay')]); exit; } // Check for errors if (isset($_FILES['file']['error']) && $_FILES['file']['error'] !== UPLOAD_ERR_OK) { wp_send_json_error(array('message' => __('File upload error', 'formipay'))); exit; } // Require the WordPress file system require_once(ABSPATH . 'wp-admin/includes/file.php'); // Use wp_handle_upload() to save the file $movefile = wp_handle_upload($_FILES['file'], array('test_form' => false)); if ($movefile && !isset($movefile['error'])) { // File is uploaded successfully; now save it to media library $file_path = $movefile['file']; $file_type = wp_check_filetype(basename($file_path), null); $attachment = array( 'post_mime_type' => $file_type['type'], 'post_title' => 'receipt-order-'.$order_id.'-'.sanitize_file_name(basename($file_path)), 'post_content' => '', 'post_status' => 'inherit' ); // Insert the attachment in the media library $attach_id = wp_insert_attachment($attachment, $file_path); require_once(ABSPATH . 'wp-admin/includes/image.php'); $attach_data = wp_generate_attachment_metadata($attach_id, $file_path); wp_update_attachment_metadata($attach_id, $attach_data); $update = formipay_update_order_status([ 'form_id' => $form_id, 'order_id' => $order_id, 'status' => 'payment-confirm', 'payment_gateway' => 'bank_transfer' ]); if($update['valid']){ // Edit TRX DB $meta_data = [ 'transfer_receipt' => [ 'time' => time(), 'attachment_id' => $attach_id, 'attachment_url' => $movefile['url'] ] ]; global $wpdb; $trx_db = $wpdb->prefix.'formipay_bank_transfer_trx'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->update( $trx_db, ['meta_data' => maybe_serialize($meta_data)], ['order_id' => $order_id] ); }else{ wp_delete_attachment( $attach_id, true ); } wp_send_json( [ 'success' => boolval($update['valid']), 'data' => [ 'message' => $update['message'], 'icon' => (boolval($update['valid']) == true) ? 'success' : 'info' ] ] ); } // Send an error response back wp_send_json_error([ 'message' => 'File could not be saved. Error: ' . $movefile['error'] ]); } public function render_email_action_button($button, $recipient, $order_data){ if( $order_data['payment_gateway'] == $this->gateway && $order_data['status'] == 'on-hold' && $recipient !== 'admin' ){ $formipay_settings = get_option('formipay_settings'); $slug = 'thankyou'; if(!empty($formipay_settings['thankyou_link'])){ $slug = $formipay_settings['thankyou_link']; } $button = [ 'url' => site_url('/'.$slug.'/'.base64_encode($order_data['form_id'].':::'.$order_data['id'])), 'label' => formipay_get_post_meta($order_data['form_id'], 'bank_transfer_confirmation_submit_button') ]; } return $button; } public function process_payment($order_data) { return $order_data; } }