| Server IP : 186.64.123.29 / Your IP : 216.73.217.94 Web Server : LiteSpeed System : Linux house.hostinglat.cl 5.15.0-185-generic #195-Ubuntu SMP Fri Jun 19 17:11:50 UTC 2026 x86_64 User : tuemp9827 ( 1016) PHP Version : 8.1.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/tuempresavirtual.cl/public_html/wp-content/plugins/flowpaymentfl/ |
Upload File : |
<?php
/**
* Prohibits the execution of this file directly from the browser.
*/
defined('ABSPATH') or die ('Nope!');
/**
* Plugin Name: Flow Payment (flow)
* Plugin URI: http://flow.cl
* Version: 2.0.1
* Author: Flow
* Author URI: http://flow.cl
* Description: Flow Payment Gateway for flow
*/
define('PLUGIN_DIR_flow', dirname(__FILE__).'/');
include PLUGIN_DIR_flow."lib/FlowApifl.class.php";
add_action('plugins_loaded', 'woocommerce_flow_flow_init', 0);
function woocommerce_flow_flow_init(){
class WC_Gateway_Flow_flow extends WC_Payment_Gateway {
const ERROR_CODE_CURRENCY_NOT_ALLOWED = 1000;
protected $medio_pago;
public function __construct(){
$this->medio_pago = 'flow';
$this->id = 'flow_'.$this->medio_pago;
if (file_exists(PLUGIN_DIR_flow."images/logo-small.png")) {
if (!file_exists(PLUGIN_DIR_flow."images/custom-logo-small.png")) {
copy(PLUGIN_DIR_flow."images/logo-small.png", PLUGIN_DIR_flow."images/custom-logo-small.png");
}
}
$this->icon = plugins_url('images/custom-logo-small.png', __FILE__);
$this->method_title = __(utf8_encode('Flow'), 'flow');
$this->method_description = __('Pago con Flow', 'flow');
$this->has_fields = false;
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option('title');
$this->description = $this->get_option('description');
add_action('woocommerce_api_confirm_' .$this->id, array($this, 'callback_confirm' ));
add_action('woocommerce_api_return_'.$this->id, array($this, 'callback_return'));
add_action('woocommerce_api_custom_error_'.$this->id, array($this, 'callback_custom_error'));
add_action('woocommerce_api_coupon_generated_'.$this->id, array($this, 'callback_coupon_generated'));
add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'flow_process_admin_options'));
}
/**
* Displays a page with a generic error in case any exception is thrown in the payment process.
*
* @return void
*/
public function callback_custom_error(){
global $woocommerce;
$checkout_page_id = wc_get_page_id('checkout');
//In case the url for the checkout is not found, we redirect to the home page.
$url_return = ($checkout_page_id) !== -1 ? get_permalink($checkout_page_id) : get_home_url();
wp_die(wc_get_template( 'error.php', array('url_return' => $url_return), 'flowpaymentfl/', plugin_dir_path( __FILE__ ) .'templates/'));
}
/**
* Displays a page with a message for the user when they generate a coupon in multicaja or servipag.
*
* @return void
*/
public function callback_coupon_generated(){
$url_return = get_home_url();
wp_die(wc_get_template( 'coupon-generated.php', array('url_return' => $url_return), 'flowpaymentfl/', plugin_dir_path( __FILE__ ) .'templates/'));
}
public function init_form_fields(){
$this->form_fields = array(
'enabled' => array(
'title' => __('Activar/Desactivar', 'woocommerce'),
'type' => 'checkbox',
'label' => __('Activar o Desactivar el plugin', 'woocommerce'),
'default' => 'yes'
),
'mode' => array(
'title' => __( 'Selector de plataforma de Flow', 'woocommerce' ),
'desc' => __( 'Selector de plataforma de Flow', 'woocommerce' ),
'id' => 'platform_select',
'default' => 'all',
'type' => 'select',
'class' => 'wc-enhanced-select',
'css' => 'min-width: 350px;',
'desc_tip' => true,
'options' => array(
'TEST' => __( 'Plataforma sandbox Flow', 'woocommerce' ),
'PROD' => __( 'Plataforma de producción Flow', 'woocommerce' )
),
),
'title' => array(
'title' => __('Título', 'woocommerce'),
'type' => 'text',
'desc_tip' => true,
'description' => __('Medio de pago utilizado', 'woocommerce'),
'placeholder' => __('Pago vía flow', 'woocommerce'),
'default' => __('Flow', 'woocommerce')
),
'description' => array(
'title' => __('Descripción', 'woocommerce'),
'type' => 'textarea',
'description' => __('Descripción Medio de Pago.', 'woocommerce'),
'placeholder' => __('Pago con Flow'),
'desc_tip' => true,
),
'api_key' => array(
'title' => __('Api Key', 'woocommerce'),
'type' => 'text',
'desc_tip' => true,
'description' => __('El Api Key corresponde al identificador único de seguridad para ser usado en la integración de tu comercio con Flow.', 'woocommerce'),
'placeholder' => __('Api Key'),
),
'secret_key' => array(
'title' => 'Secret Key',
'type' => 'text',
'desc_tip' => true,
'description' => __('El Secret Key corresponde a una clave de seguridad para asegurar que la información que se está trasmitiendo viene de una fuente confiable', 'woocommerce'),
'placeholder' => __('Clave de Seguridad'),
),
'logo-small' => array(
'title' => __('Logo a mostrar', 'woocommerce'),
'type' => 'file',
'description' => __('Corresponde al logo a mostrar al momento de pagar para este método de pago', 'woocommerce'),
'placeholder' => __('Logo'),
'desc_tip' => true
)
);
//If the current plugin is not the webpay one, we add a url return field.
if ($this->hasReturnUrl()) {
$this->form_fields['return_url'] = array(
'title' => __('Return Url', 'woocommerce'),
'type' => 'text',
'description' => __('Ingrese su url de retorno', 'woocommerce'),
'desc_tip' => true
);
}
}
/**
* Called after checkout. Creates the payment and redirects to Flow
*
* @param int $order_id
* @return void
*/
public function process_payment($order_id) {
$this->log('Entering process_payment', 'info');
global $woocommerce;
$order = $this->getOrder($order_id);
$customer = new WC_Customer();
$concept = 'Orden: '.$order_id." - ". urldecode(get_bloginfo('name'));
$amount = round(number_format($order->get_total(), 0, ',', ''));
$service = 'payment/create';
$method = 'POST';
$email = $this->getCustomerEmail($order);
$confirm_url = add_query_arg('wc-api', 'confirm_'.$this->id, home_url('/'));
$return_url = add_query_arg('wc-api', 'return_'.$this->id, home_url('/'));
$currency = $this->getCurrency($order);
$allowedCurrencies = array(
"CLP"
);
if (!in_array($currency, $allowedCurrencies)) {
throw new \Exception("Flow does not accept the $currency currency", self::ERROR_CODE_CURRENCY_NOT_ALLOWED);
}
$params = array(
"currency" => $currency,
"commerceOrder" => $order_id,
"subject" => $concept,
"amount" => $amount,
"email" => $email,
"urlConfirmation" => $confirm_url,
"urlReturn" => $return_url,
"paymentMethod"=>$this->getPaymentMethod()
);
try {
$this->log('Calling Flow service: '.$service." with params: ".json_encode($params));
$flowApi = $this->getFlowApi();
$result = $flowApi->send($service, $params, $method);
if (!isset($result["url"]) || !isset($result["token"])) {
if (isset($result["message"]) && $result["code"]) {
throw new \Exception($result["message"], $result["code"]);
} else {
throw new \Exception("Ha ocurrido un error inesperado creando el pago en Flow");
}
}
$this->log('Flow response: '.json_encode($result));
$url_to_redirect = $result['url']."?token=".$result['token'];
return array(
'result' => 'success',
'redirect' => $url_to_redirect,
);
} catch(Exception $e){
error_log($e->getMessage());
wc_add_notice(
__('Ha ocurrido un error inesperado. Por favor, intentelo de nuevo. ', 'woocommerce'). '<br>'. $e->getMessage(),
'error'
);
$this->log('Unexpected error: '.$e->getCode(). ' - '.$e->getMessage(), 'error');
}
}
/**
* Called by flow asynchronously in order to confirm the payment.
*
* @return void
*/
public function callback_confirm(){
$this->log('Entering the confirm callback', 'info');
try{
$flowApi = $this->getFlowApi();
$service = 'payment/getStatus';
$method = 'GET';
$token = filter_input(INPUT_POST, 'token');
$params = array(
"token" => $token
);
$this->log('Calling the flow service: '.$service);
$this->log('With params: '.json_encode($params));
$result = $flowApi->send($service, $params, $method);
$this->log('Flow response: '.json_encode($result));
if (isset($result["message"])) {
throw new \Exception($result["message"]);
}
$order_id = $result['commerceOrder'];
$order = $this->getOrder($order_id);
$status = $result['status'];
$amountInStore = round(number_format($order->get_total(), 0, ',', ''));
$amountPaidInFlow = $result["amount"];
$this->log('Amount in store: '.$amountInStore);
if ($amountPaidInFlow != $amountInStore) {
throw new Exception('The amount has been altered. Aborting...');
}
/*if($this->isTesting($result)){
$this->setProductionEnvSimulation($status, $result);
}*/
if($this->isPendingInFlow($status)){
$this->setOrderAsPending($order);
}
elseif($this->isPaidInFlow($status)){
$this->payOrder($order);
}
elseif($this->isCancelledInFlow($status)){
$this->cancelOrder($order);
}
else{
$this->rejectOrder($order);
}
} catch(Exception $e) {
error_log($e->getMessage());
$this->log('Unexpected error: '.$e->getCode(). ' - '.$e->getMessage(), 'error');
}
}
/**
* Redirect by Flow after the payment process is complete.
*
* @return void
*/
public function callback_return(){
$this->log('Entering callback_return', 'info');
$flowApi = $this->getFlowApi();
$service = 'payment/getStatus';
$method = 'GET';
$token = filter_input(INPUT_POST, 'token');
$params = array(
"token" => $token
);
try {
$this->log('Calling the flow service: '.$service);
$this->log('With params: '.json_encode($params));
$result = $flowApi->send($service, $params, $method);
$this->log('Flow result: '.json_encode($result));
if (isset($result["message"])) {
throw new \Exception($result["message"]);
}
$order_id = $result['commerceOrder'];
$status = $result['status'];
$order = $this->getOrder($order_id);
$order_status = $order->get_status();
if ($this->userCanceledPayment($status, $result)) {
$this->log('User canceled the payment. Redirecting to checkout...', 'info');
$this->redirectToCheckout();
}
$amountInStore = round(number_format($order->get_total(), 0, ',', ''));
$amountPaidInFlow = $result["amount"];
$this->log('Amount in store: '.$amountInStore);
if ($amountPaidInFlow != $amountInStore) {
throw new Exception('The amount has been altered. Aborting...');
}
/*if($this->isTesting($result)){
$this->log('Setting up the production simulation...');
$this->setProductionEnvSimulation($status, $result);
}*/
if ($this->isPendingInFlow($status)) {
$this->clearCart();
if($this->userGeneratedCoupon($status, $result)){
if(!empty( $this->get_option('return_url'))){
$this->redirectTo($this->get_option('return_url'));
}
}
$this->redirectToCouponGenerated($order);
} elseif($this->isPaidInFlow($status)) {
if($this->isPendingInStore($order_status)){
$this->payOrder($order);
}
$this->redirectToSuccess($order);
} else {
if($this->isRejectedInFlow($status)){
if($this->isPendingInStore($order_status)){
$this->rejectOrder($order);
}
}
if($this->isCancelledInFlow($status)){
if($this->isPendingInStore($order_status)){
$this->cancelOrder($order);
}
}
$this->redirectToFailure($order);
}
} catch(Exception $e) {
$this->log('Unexpected error: '.$e->getCode(). ' - '.$e->getMessage(), 'error');
$this->redirectToError();
}
wp_die();
}
/**
* Renders the options for the admin and any errors in case there are any.
*
* @return void
*/
public function admin_options(){
if(!get_option('woocommerce_flow_api_key_valid'))
$this->add_error('La llave de api es obligatoria.');
if(!get_option('woocommerce_flow_secret_key_valid')){
$this->add_error('La llave secreta es obligatoria.');
}
if($this->is_valid_for_use()){
$this->display_errors();
parent::admin_options();
}
else{
?>
<div class="inline error">
<p>
<strong><?php esc_html_e( 'Gateway disabled', 'woocommerce' ); ?></strong>: <?php esc_html_e( 'Flow no soporta el tipo de moneda (' .get_woocommerce_currency() .').', 'woocommerce' ); ?>
</p>
</div>
<?php
}
}
/**
* Processes and validates the admin options
*
* @return void
*/
public function flow_process_admin_options() {
$hasFile = false;
$nombrePlugin = basename(__DIR__);
$idFileInput = "woocommerce_" . $this->id . "_logo-small";
if (isset($_FILES[$idFileInput])) {
$file = $_FILES[$idFileInput];
$hasFile = $file['size']>0;
if ($hasFile) {
move_uploaded_file($file['tmp_name'], PLUGIN_DIR_flow."images/custom-logo-small.png");
}
}
$post_data = $this->get_post_data();
$anyErrors = false;
if(empty($post_data['woocommerce_'.$this->id.'_api_key'])){
update_option('woocommerce_flow_api_key_valid', false);
$anyErrors = true;
}
else{
update_option('woocommerce_flow_api_key_valid', true);
}
if(empty($post_data['woocommerce_'.$this->id.'_secret_key'])){
update_option('woocommerce_flow_secret_key_valid', false);
$anyErrors = true;
}
else{
update_option('woocommerce_flow_secret_key_valid', true);
}
if(!$anyErrors)
$this->process_admin_options();
return ;
}
private function redirectToSuccess($order){
$this->log('Redirecting to the success page...', 'info');
$this->redirectTo($this->get_return_url($order));
}
private function redirectToFailure($order){
$this->log('Redirecting to the failure page...', 'info');
$failUrl = $order->get_cancel_order_url();
$error_message = 'Su pedido ha fallado debido a un error en el pago. Intente nuevamente.';
wc_add_notice( __($error_message, 'woocommerce'), 'error' );
$this->redirectTo($failUrl);
}
private function redirectToCouponGenerated(){
$url = add_query_arg('wc-api', 'coupon_generated_'.$this->id, home_url('/'));
$this->redirectTo($url);
}
private function redirectToError(){
$url = add_query_arg('wc-api', 'custom_error_'.$this->id, home_url('/'));
$this->redirectTo($url);
}
private function redirectToCheckout(){
global $woocommerce;
$checkout_page_id = wc_get_page_id('checkout');
//In case the url for the checkout is not found, we redirect to the home page.
$url = ($checkout_page_id) !== -1 ? get_permalink($checkout_page_id) : get_home_url();
$this->redirectTo($url);
}
private function hasReturnUrl()
{
return !$this->isWebpay() && !$this->isOnepay() && !$this->isMach();
}
private function redirectTo($url){
wp_redirect($url);
die();
}
/**
* Checks if the user canceled the payment (webpay or onepay)
*
* @param int $status
* @param array $flowData
* @return boolean
*/
private function userCanceledPayment($status, $flowData){
return $this->isPendingInFlow($status)
&& empty($flowData['paymentData']['media'])
&& empty($flowData['pending_info']['media']);
}
/**
* Checks if the user generated a coupon
*
* @param int $status
* @param array $flowData
* @return boolean
*/
private function userGeneratedCoupon($status, $flowData){
return $this->isPendingInFlow($status)
&& !empty($flowData['pending_info']['media']
&& empty($flowData['paymentData']['media']));
}
/**
* Returns the numeric representation of the payment method
*
* @return void
*/
private function getPaymentMethod(){
$paymentMethod = 1;
switch($this->medio_pago){
case 'webpay': {
$paymentMethod = 1;
break;
}
case 'servipag': {
$paymentMethod = 2;
break;
}
case 'multicaja': {
$paymentMethod = 3;
break;
}
case 'onepay': {
$paymentMethod = 5;
break;
}
case 'flow': {
$paymentMethod = 9;
break;
}
case 'webpay3c': {
$paymentMethod = 13;
break;
}
case 'mach': {
$paymentMethod = 15;
break;
}
default : {
$paymentMethod = 1;
break;
}
}
return $paymentMethod;
}
/**
* Checks if the current plugin is webpay
*
* @param array $flowData
* @return boolean
*/
private function isWebpay(){
return $this->getPaymentMethod() == 1 || $this->getPaymentMethod() == 13;
}
/**
* Checks if the current plugin is onepay
*
* @return boolean
*/
private function isOnepay(){
return $this->getPaymentMethod() == 5;
}
/**
* Checks if the current payment method is multicaja
*
* @return boolean
*/
private function isMulticaja(){
return $this->getPaymentMethod() == 3;
}
/**
* Checks if the current payment method is Servipag
*
* @return boolean
*/
private function isServipag(){
return $this->getPaymentMethod() == 2;
}
/**
* Checks if the current payment method is Flow.
*
* @return boolean
*/
private function isFlow(){
return $this->getPaymentMethod() == 9;
}
/**
* Checkfs if the current payment methos is Mach
*
* @return boolean
*/
private function isMach()
{
return $this->getPaymentMethod() == 15;
}
/**
* Checks if the order is paid in Flow
*
* @param int $status
* @return boolean
*/
private function isPaidInFlow($status){
return $status == 2;
}
/**
* Checks if the order is rejected in Flow.
*
* @param int $status
* @return boolean
*/
private function isRejectedInFlow($status){
return $status == 3;
}
/**
* Checks if the order is canceled in Flow.
*
* @param int $status
* @return boolean
*/
private function isCancelledInFlow($status){
return $status == 4;
}
/**
* Checks if the order is pending in Flow.
*
* @param int $status
* @return boolean
*/
private function isPendingInFlow($status){
return $status == 1;
}
/**
* Checks if the order in the store has a pending status
*
* @param int $orderStatus
* @return boolean
*/
private function isPendingInStore($orderStatus){
return $orderStatus == 'pending';
}
/**
* Checks if the order in the store has a paid status.
*
* @param int $orderStatus
* @return boolean
*/
private function isPaidInStore($orderStatus){
return $orderStatus == 'completed';
}
/**
* Checks if the order in the store has a processing status.
*
* @param int $orderStatus
* @return boolean
*/
private function isProcessingInStore($orderStatus){
return $orderStatus == 'processing';
}
private function clearCart(){
global $woocommerce;
$woocommerce->cart->empty_cart();
}
/**
* Checks if the current plugin is in testing mode (sandbox)
*
* @param array $flowData
* @return boolean
*/
private function isTesting($flowData){
return ($this->get_option('mode') === 'TEST'
&& (strtolower($flowData['paymentData']['media']) === 'servipag'
|| strtolower($flowData['paymentData']['media']) === 'multicaja')
);
}
/**
* Sets some variables in order to the emulate the production environment (since both environment return different results)
*
* @param int $status
* @param array $flowData
* @return void
*/
private function setProductionEnvSimulation(&$status, &$flowData){
$status = 1;
$flowData['pending_info']['media'] = $flowData['paymentData']['media'];
$flowData['paymentData']['media'] = '';
}
/**
* Pays the order in the store
*
* @param WC_Order $order
* @return void
*/
private function payOrder($order){
$this->log('Paying order #'.$order->get_order_number());
$this->addOrderNote($order, 'Pagado con flow');
$order->payment_complete();
}
/**
* Rejects the order in the store.
*
* @param WC_Order $order
* @return void
*/
private function rejectOrder($order){
$this->log('Rejecting order #'.$order->get_order_number());
$this->addOrderNote($order, 'La orden fue rechazada por Flow');
$order->update_status('failed');
}
/**
* Cancels the order in the store
*
* @param WC_Order $order
* @return boolean
*/
private function cancelOrder($order){
$this->log('Cancelling order #'.$order->get_order_number());
$this->addOrderNote($order, 'La orden fue cancelada por Flow');
$order->update_status('cancelled');
}
/**
* Adds a pending note to the order, since the pending status is the default
*
* @param WC_Order $order
* @return void
*/
private function setOrderAsPending($order){
$this->log('Setting as pending order #'.$order->get_order_number());
//Since the default status of the order is pending, we only add a note here.
$this->addOrderNote($order, 'La orden se encuentra pendiente.');
}
private function addOrderNote($order, $note){
$order->add_order_note(__($note, 'woocommerce'));
}
private function is_valid_for_use()
{
if (!in_array(get_woocommerce_currency(), apply_filters('woocommerce_' . $this->id . '_supported_currencies', array('CLP')))) {
return false;
}
return true;
}
/**
* Returns an order object. Depending on the version of woocommerce, it will use one method or another.
*
* @param int $order_id
* @return void
*/
private function getOrder($order_id){
if($this->flow_woocommerce_version_check()){
return new WC_Order($order_id);
}
else{
return wc_get_order($order_id);
}
}
/**
* Checks if the woocommerce's version is at least 3.0 or more
*
* @param string $version
* @return void
*/
private function flow_woocommerce_version_check($version = '3.0.0') {
if (class_exists('WooCommerce')) {
global $woocommerce;
if (version_compare($woocommerce->version, $version, ">=")) {
return true;
}
return false;
}
return false;
}
private function getCustomerEmail($order){
if($this->flow_woocommerce_version_check()){
$email = $order->get_billing_email();
}
else{
$orderData = get_post_meta($order->id);
$email = $orderData['_billing_email'][0];
}
return $email;
}
private function getFlowApi(){
$apiKey = $this->get_option('api_key');
$secretKey = $this->get_option('secret_key');
$mode = $this->get_option('mode');
$endpoint = $mode == 'PROD' ? 'https://www.flow.cl/api' : 'https://sandbox.flow.cl/api';
$flowApi = new FlowApifl($apiKey, $secretKey, $endpoint);
return $flowApi;
}
private function log($message, $type = 'info'){
//if the version of wocommerce >= 3
if($this->flow_woocommerce_version_check())
{
$logger = wc_get_logger();
$logger->{$type}($message, array('source' => 'flow_flow'));
}
else{
$logger = new WC_Logger('flow_flow');
$logger->add('flow_flow', $message);
}
}
private function getCurrency($order)
{
if ($this->flow_woocommerce_version_check()) {
return $order->get_currency();
}
return $order->get_order_currency();
}
}
function woocommerce_add_flow_flow_class($methods){
$methods[] = 'WC_Gateway_Flow_flow';
return $methods;
}
function woocommerce_add_flow_flow_clp_currency($currencies)
{
$currencies["CLP"] = __('Pesos Chilenos');
return $currencies;
}
function woocommerce_add_flow_flow_clp_currency_symbol($currency_symbol, $currency)
{
switch ($currency) {
case 'CLP':
$currency_symbol = '$';
break;
}
return $currency_symbol;
}
add_filter('woocommerce_currencies', 'woocommerce_add_flow_flow_clp_currency', 10, 1);
add_filter('woocommerce_currency_symbol', 'woocommerce_add_flow_flow_clp_currency_symbol', 10, 2);
add_filter('woocommerce_payment_gateways', 'woocommerce_add_flow_flow_class');
}