/home/nbcgowuy/kdosheleads.com/wp-content/plugins/dokan-lite/includes/ReverseWithdrawal/Manager.php
<?php
namespace WeDevs\Dokan\ReverseWithdrawal;
use WeDevs\Dokan\Cache;
use WP_Error;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Database Manager Class
*
* @since 3.5.1
*
* @class Manager
*
* @package WeDevs\Dokan\ReverseWithdrawal
*/
class Manager {
/**
* Table name for dokan_reverse_withdrawal table
*
* @var string
*
* @since 3.5.1
*/
private $table;
/**
* Manager constructor.
*
* @since 3.5.1
*/
public function __construct() {
global $wpdb;
$this->table = "{$wpdb->prefix}dokan_reverse_withdrawal";
}
/**
* This method will return data from dokan_reverse_withdrawal table
*
* @since 3.5.1
*
* @param array $args
*
* @return array|int|WP_Error
*/
public function all( $args = [] ) {
$default = [
'id' => [],
'vendor_id' => [], // array of integers
'trn_id' => [], // array of integers
'trn_type' => [], // array of strings, possible values are:
'trn_date' => [
'from' => '',
'to' => '',
],
'orderby' => 'added',
'order' => 'DESC',
'return' => 'balance', // possible values are vendor_transaction, vendor_transaction_count, balance, balance_count
'per_page' => 20,
'page' => 1,
];
$args = wp_parse_args( $args, $default );
global $wpdb;
$fields = '';
$join = '';
$where = '';
$groupby = '';
$orderby = '';
$limits = '';
$query_args = [ 1, 1 ];
// determine which fields to return
if ( in_array( $args['return'], [ 'vendor_transaction' ], true ) ) {
$fields = 'trn.*';
} elseif ( in_array( $args['return'], [ 'count' ], true ) ) {
$fields = 'COUNT(trn.id) AS count';
} elseif ( in_array( $args['return'], [ 'balance_count', 'vendor_transaction_count' ], true ) ) {
$fields = 'COUNT(trn.id) AS total_transactions, SUM(trn.debit) AS debit, SUM(trn.credit) AS credit';
$fields .= 'balance_count' === $args['return'] ? ', COUNT( distinct vendor_id) AS total_vendors' : '';
} elseif ( 'balance' === $args['return'] ) {
$fields = 'trn.vendor_id, SUM(trn.debit) AS debit, SUM(trn.credit) AS credit';
$fields .= ", (SELECT MAX(trn2.trn_date) AS last_transaction_date FROM {$this->table} As trn2 WHERE trn.vendor_id = trn2.vendor_id AND trn2.trn_type='vendor_payment') AS last_payment_date";
$fields .= ', u_meta.meta_value as store_name';
// join user meta table
$join .= " LEFT JOIN {$wpdb->usermeta} AS u_meta ON trn.vendor_id = u_meta.user_id";
// include dokan_store_name under where param
$where .= ' AND u_meta.meta_key=%s';
$query_args[] = 'dokan_store_name';
$groupby = 'GROUP BY trn.vendor_id';
// reset trn_date from
if ( isset( $args['trn_date']['from'] ) ) {
$args['trn_date']['from'] = '';
}
}
// check if id filter is applied
if ( ! $this->is_empty( $args['id'] ) ) {
$transaction_ids = implode( "','", array_map( 'absint', (array) $args['id'] ) );
$where .= " AND trn.id IN ('$transaction_ids')";
}
// check if vendor id filter is applied
if ( ! $this->is_empty( $args['trn_id'] ) ) {
$trn_id = implode( "','", array_map( 'absint', (array) $args['trn_id'] ) );
$where .= " AND trn.trn_id IN ('$trn_id')";
}
// check if vendor id filter is applied
if ( ! $this->is_empty( $args['vendor_id'] ) ) {
$vendor_id = implode( "','", array_map( 'absint', (array) $args['vendor_id'] ) );
$where .= " AND trn.vendor_id IN ('$vendor_id')";
}
// transaction type validation
if ( ! empty( $args['trn_type'] ) && array_key_exists( $args['trn_type'], Helper::get_transaction_types() ) ) {
$where .= ' AND trn.trn_type = %s';
$query_args[] = $args['trn_type'];
}
// check if trn_date filter is applied
// convert into timestamp
$now = dokan_current_datetime();
if ( ! empty( $args['trn_date']['from'] ) ) {
// fix date format
if ( is_numeric( $args['trn_date']['from'] ) ) {
$now = $now->setTimestamp( $args['trn_date']['from'] );
$args['trn_date']['from'] = $now ? $now->getTimestamp() : 0;
} else {
$now = $now->modify( $args['trn_date']['from'] );
$args['trn_date']['from'] = $now ? $now->setTime( 0, 0, 0 )->getTimestamp() : 0;
}
}
// convert into timestamp
if ( ! empty( $args['trn_date']['to'] ) ) {
if ( is_numeric( $args['trn_date']['to'] ) ) {
$now = $now->setTimestamp( $args['trn_date']['to'] );
$args['trn_date']['to'] = $now ? $now->getTimestamp() : 0;
} else {
$now = $now->modify( $args['trn_date']['to'] );
$args['trn_date']['to'] = $now ? $now->setTime( 23, 59, 59 )->getTimestamp() : 0;
}
}
// check if min and max both values are set, search in between
if ( ! empty( $args['trn_date']['from'] ) && ! empty( $args['trn_date']['to'] ) ) {
// fix min max value
if ( $args['trn_date']['from'] > $args['trn_date']['to'] ) {
$temp = $args['trn_date']['from'];
$args['trn_date']['from'] = $args['trn_date']['to'];
$args['trn_date']['to'] = $temp;
}
$where .= ' AND trn.trn_date BETWEEN %d AND %d';
$query_args[] = $args['trn_date']['from'];
$query_args[] = $args['trn_date']['to'];
} elseif ( ! empty( $args['trn_date']['to'] ) ) {
$where .= ' AND trn.trn_date <= %d';
$query_args[] = $args['trn_date']['to'];
} elseif ( ! empty( $args['trn_date']['from'] ) ) {
$where .= ' AND trn.trn_date >= %d';
$query_args[] = $args['trn_date']['from'];
}
// order and order by param
// supported order by param
$supported_order_by = [
'id' => 'trn.id',
'trn_date' => 'trn.trn_date',
'debit' => 'trn.debit',
'credit' => 'trn.credit',
];
if ( ! empty( $args['orderby'] ) && array_key_exists( $args['orderby'], $supported_order_by ) ) {
$order = in_array( strtolower( $args['order'] ), [ 'asc', 'desc' ], true ) ? strtoupper( $args['order'] ) : 'ASC';
$orderby = "ORDER BY {$supported_order_by[ $args['orderby'] ]} {$order}"; //no need for prepare, we've already whitelisted the parameters
//second order by in case of similar value on first order by field
if ( 'id' !== $args['orderby'] ) {
$orderby .= ", trn.id {$order}";
}
}
// pagination param
if ( ! empty( $args['per_page'] ) && -1 !== intval( $args['per_page'] ) && ! in_array( $args['return'], [ 'count', 'balance_count', 'vendor_transaction_count' ], true ) ) {
$limit = absint( $args['per_page'] );
$page = absint( $args['page'] );
$page = $page > 0 ? $page : 1;
$offset = ( $page - 1 ) * $limit;
$limits = 'LIMIT %d, %d';
$query_args[] = $offset;
$query_args[] = $limit;
}
$cache_group = 'reverse_withdrawal';
$cache_key = 'get_transactions_' . md5( wp_json_encode( $args ) );
if ( is_numeric( $args['vendor_id'] ) ) {
$cache_group = "reverse_withdrawal_{$args['vendor_id']}";
} elseif ( ! $this->is_empty( $args['vendor_id'] ) && 1 === count( $args['vendor_id'] ) ) {
$cache_group = "reverse_withdrawal_{$args['vendor_id'][0]}";
}
$data = Cache::get( $cache_key, $cache_group );
if ( in_array( $args['return'], [ 'vendor_transaction' ], true ) && false === $data ) {
// get all transactions of vendor(s)
// @codingStandardsIgnoreStart
$data = $wpdb->get_results(
$wpdb->prepare(
"SELECT $fields FROM {$this->table} AS trn $join WHERE %d=%d $where $orderby $limits",
$query_args
),
ARRAY_A
);
// @codingStandardsIgnoreEnd
// check for query error
if ( ! empty( $wpdb->last_error ) ) {
return new WP_Error( 'db_query_error', $wpdb->last_error, $wpdb->last_query );
}
// if per_page is 1, send single item
if ( 1 === $args['per_page'] ) {
$data = is_array( $data ) && ! empty( $data ) ? $data[0] : [];
}
// store on cache
Cache::set( $cache_key, $data, $cache_group );
} elseif ( 'count' === $args['return'] && false === $data ) {
// get count of entries
// @codingStandardsIgnoreStart
$data = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT $fields FROM {$this->table} AS trn $join WHERE %d=%d $where",
$query_args
)
);
// @codingStandardsIgnoreEnd
Cache::set( $cache_key, $data, $cache_group );
} elseif ( in_array( $args['return'], [ 'balance_count', 'vendor_transaction_count' ], true ) && false === $data ) {
// @codingStandardsIgnoreStart
$row = $wpdb->get_row(
$wpdb->prepare(
"SELECT $fields FROM {$this->table} AS trn $join WHERE %d=%d $where",
$query_args
)
);
$refund_amount = (float) $wpdb->get_var(
$wpdb->prepare(
"SELECT SUM(trn.credit) FROM {$this->table} AS trn $join WHERE %d=%d $where AND trn.trn_type='order_refund'",
$query_args
)
);
// check for query error
if ( ! empty( $wpdb->last_error ) ) {
return new WP_Error( 'db_query_error', $wpdb->last_error, $wpdb->last_query );
}
$data = [
'total_transactions' => (int) $row->total_transactions,
'debit' => (float) $row->debit,
'credit' => (float) $row->credit - $refund_amount,
];
if ( 'balance_count' === $args['return'] ) {
$data['total_vendors'] = (int) $row->total_vendors;
$data['balance'] = (float) $row->debit - (float) $row->credit;
}
// @codingStandardsIgnoreEnd
Cache::set( $cache_key, $data, $cache_group );
} elseif ( 'balance' === $args['return'] && false === $data ) {
// @codingStandardsIgnoreStart
$data = $wpdb->get_results(
$wpdb->prepare(
"SELECT $fields FROM {$this->table} AS trn $join WHERE %d=%d $where $groupby $orderby $limits",
$query_args
),
ARRAY_A
);
// @codingStandardsIgnoreEnd
// check for query error
if ( ! empty( $wpdb->last_error ) ) {
return new WP_Error( 'db_query_error', $wpdb->last_error, $wpdb->last_query );
}
// if per_page is 1, send single item
if ( 1 === (int) $args['per_page'] ) {
$data = is_array( $data ) && ! empty( $data ) ? $data[0] : [];
}
// store on cache
Cache::set( $cache_key, $data, $cache_group );
}
return $data;
}
/**
* This method will get all/selected vendors balance
*
* @since 3.5.1
*
* @param array $args
*
* @return array|WP_Error
*/
public function get_stores_balance( $args = [] ) {
$query_params = [
'vendor_id' => isset( $args['vendor_id'] ) ? $args['vendor_id'] : 0,
'trn_date' => isset( $args['trn_date'] ) ? $args['trn_date'] : '',
'per_page' => isset( $args['per_page'] ) ? $args['per_page'] : -1,
'page' => isset( $args['page'] ) ? $args['page'] : 1,
'orderby' => isset( $args['orderby'] ) ? $args['orderby'] : 'id',
'order' => isset( $args['order'] ) ? $args['order'] : 'DESC',
];
$items = [];
// get item count
$query_params['return'] = 'balance_count';
$count = $this->all( $query_params );
// check for errors
if ( is_wp_error( $count ) ) {
return $count;
}
// only run query if count value is greater than 0
if ( $count['total_transactions'] > 0 ) {
$query_params['return'] = 'balance';
$items = $this->all( $query_params );
// check for errors
if ( is_wp_error( $items ) ) {
return $items;
}
}
return [
'count' => $count,
'items' => $items,
];
}
/**
* This method will return current balance of a vendor
*
* @since 3.5.1
*
* @param array $args
*
* @return float|WP_Error
*/
public function get_store_balance( $args = [] ) {
$query_params = [
'vendor_id' => isset( $args['vendor_id'] ) ? $args['vendor_id'] : 0,
'trn_date' => isset( $args['trn_date'] ) && ! $this->is_empty( $args['trn_date'] ) ? $args['trn_date'] : '',
'per_page' => 1,
'return' => 'balance',
];
if ( empty( $query_params['vendor_id'] ) || ! is_numeric( $query_params['vendor_id'] ) ) {
return new WP_Error( 'invalid_vendor_id', esc_html__( 'No vendor id provided', 'dokan-lite' ) );
}
$balance = $this->all( $query_params );
if ( is_wp_error( $balance ) ) {
return $balance;
}
return isset( $balance['debit'], $balance['credit'] ) ? floatval( $balance['debit'] - $balance['credit'] ) : 0;
}
/**
* This method will get all the transactions for a vendor
*
* @since 3.5.1
*
* @param array $args
*
* @return array|WP_Error
*/
public function get_store_transactions( $args = [] ) {
$default_transactions_date = [
'from' => dokan_current_datetime()->modify( '-1 month' )->format( 'Y-m-d' ),
'to' => dokan_current_datetime()->format( 'Y-m-d' ),
];
$query_params = [
'vendor_id' => isset( $args['vendor_id'] ) ? $args['vendor_id'] : 0,
'trn_date' => isset( $args['trn_date'] ) && ! $this->is_empty( $args['trn_date'] ) ? $args['trn_date'] : $default_transactions_date,
'per_page' => isset( $args['per_page'] ) ? $args['per_page'] : -1,
'page' => isset( $args['page'] ) ? $args['page'] : 1,
'orderby' => 'id',
'order' => 'ASC',
];
if ( empty( $query_params['vendor_id'] ) || ! is_numeric( $query_params['vendor_id'] ) ) {
return new WP_Error( 'invalid_vendor_id', esc_html__( 'No vendor id provided', 'dokan-lite' ) );
}
$return = [
'balance' => [],
'count' => [],
'items' => [],
];
// get balance date
if ( ! empty( $query_params['trn_date']['from'] ) ) {
$one_day_before = dokan_current_datetime()->modify( $query_params['trn_date']['from'] )->setTime( 0, 0, 0 )->getTimestamp();
} else {
// get balance for 1 day before start date
$one_day_before = dokan_current_datetime()->setTime( 0, 0, 0 )->getTimestamp();
}
$balance_args = [
'vendor_id' => $query_params['vendor_id'],
'trn_date' => [
'to' => $one_day_before,
],
'return' => 'balance',
'per_page' => 1,
];
// we are getting opening balance here
$balance = $this->all( $balance_args );
if ( is_wp_error( $balance ) ) {
return $balance;
}
// prepare formatted balance
$balance['trn_type'] = 'opening_balance';
$balance['trn_date'] = $one_day_before;
$balance['vendor_id'] = isset( $balance['vendor_id'] ) ? absint( $balance['vendor_id'] ) : 0;
// set balance
$return['balance'] = $balance;
// get item count
$query_params['return'] = 'vendor_transaction_count';
$count = $this->all( $query_params );
// check for errors
if ( is_wp_error( $count ) ) {
return $count;
}
$return['count'] = $count;
// only run query if count value is greater than 0
if ( $count['total_transactions'] === 0 ) {
return $return;
}
$query_params['return'] = 'vendor_transaction';
$items = $this->all( $query_params );
// check for errors
if ( is_wp_error( $items ) ) {
return $items;
}
$return['items'] = $items;
return $return;
}
/**
* This method will return a single item from reverse withdrawal table
*
* @since 3.5.1
*
* @param int $id
*
* @return WP_Error|array
*/
public function get( $id = 0 ) {
$args = [
'id' => $id,
'per_page' => 1,
'return' => 'all',
];
$data = $this->all( $args );
if ( empty( $data ) ) {
return new WP_Error( 'get_reverse_withdrawal_error', esc_html__( 'No reverse withdrawal data found with given id.', 'dokan-lite' ) );
}
return $data;
}
/**
* Insert a new item into database.
*
* @since 3.5.1
*
* @param array $args
*
* @return int|WP_Error
*/
public function insert( $args = [] ) {
global $wpdb;
$default = [
'trn_id' => 0,
'trn_type' => 'order_commission',
'vendor_id' => 0,
'note' => '',
'debit' => 0,
'credit' => 0,
'trn_date' => time(),
];
$args = wp_parse_args( $args, $default );
// validate required fields
if ( isset( $args['trn_id'] ) && ! is_numeric( $args['trn_id'] ) ) {
return new WP_Error( 'insert_rw_invalid_transaction_id', esc_html__( 'Transaction id is required.', 'dokan-lite' ) );
}
if ( empty( $args['trn_type'] ) || ! array_key_exists( $args['trn_type'], Helper::get_transaction_types() ) ) {
return new WP_Error( 'insert_rw_invalid_transaction_type', esc_html__( 'Invalid transaction type is provide. Please check your input.', 'dokan-lite' ) );
}
if ( empty( $args['vendor_id'] ) ) {
return new WP_Error( 'insert_rw_invalid_vendor_id', esc_html__( 'Invalid vendor id provide. Please provide a valid vendor id.', 'dokan-lite' ) );
}
// just to make sure $args doesn't contain any unnecessary elements
$data = [
'trn_id' => $args['trn_id'],
'trn_type' => $args['trn_type'],
'vendor_id' => $args['vendor_id'],
'note' => $args['note'],
'debit' => $args['debit'],
'credit' => $args['credit'],
'trn_date' => $args['trn_date'],
];
$format = [
'%d',
'%s',
'%d',
'%s',
'%f',
'%f',
'%d',
];
// add data into database
$inserted = $wpdb->insert( $this->get_table(), $data, $format ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
$insert_id = $wpdb->insert_id;
if ( false === $inserted ) {
dokan_log( '[Dokan Reverse Withdrawal] Error while inserting data: <strong>' . $wpdb->last_error . '</strong>, Data: ' . print_r( $data, true ) );
return new WP_Error( 'insert_reverse_withdrawal_error', esc_html__( 'Something went wrong while inserting reverse withdrawal data. Please contact site admin.', 'dokan-lite' ) );
}
do_action( 'dokan_reverse_withdrawal_created', $data, $insert_id, $args );
return $insert_id;
}
/**
* Check if reverse withdrawal already inserted for an order
*
* @since 3.5.1
*
* @param int $order_id
*
* @return bool
*/
public function is_reverse_withdrawal_added( $order_id ) {
$args = [
'trn_id' => $order_id,
'trn_type' => 'order_commission',
'return' => 'count',
];
$count = $this->all( $args );
return $count > 0;
}
/**
* Check if reverse withdrawal payment already inserted for an order
*
* @since 3.5.1
*
* @param int $order_id
*
* @return bool
*/
public function is_payment_inserted( $order_id ) {
$args = [
'trn_id' => $order_id,
'trn_type' => 'vendor_payment',
'return' => 'count',
];
$count = $this->all( $args );
return $count > 0;
}
/**
* This method will return all refunded amount for a specific order
*
* @since 3.5.1
*
* @param int $order_id
*
* @return float
*/
public function get_total_refunded_amount_by_order( $order_id ) {
global $wpdb;
//@codingStandardsIgnoreStart
return (float) $wpdb->get_var(
$wpdb->prepare(
"SELECT SUM(credit) FROM {$this->get_table()} WHERE trn_id = %d AND trn_type = %s",
$order_id, 'order_refund'
)
);
//@codingStandardsIgnoreEnd
}
/**
* This method will return all the payments made by a vendor in a date range
*
* @since 3.5.1
*
* @param array $args
*
* @return WP_Error|float
*/
public function get_payments_by_vendor( $args = [] ) {
$default = [
'vendor_id' => dokan_get_current_user_id(),
'trn_date' => [
'from' => dokan_current_datetime()->modify( 'first day of this month' )->format( 'Y-m-d' ),
'to' => dokan_current_datetime()->modify( 'last day of this month' )->format( 'Y-m-d' ),
],
];
$args = wp_parse_args( $args, $default );
// validate vendor id
if ( empty( $args['vendor_id'] ) ) {
return new WP_Error( 'get_payments_by_vendor_error', esc_html__( 'Invalid vendor id provide. Please provide a valid vendor id.', 'dokan-lite' ) );
}
$params = [
'vendor_id' => $args['vendor_id'],
'trn_date' => $args['trn_date'],
'trn_type' => 'vendor_payment',
'return' => 'vendor_transaction_count',
];
$result = $this->all( $params );
if ( is_wp_error( $result ) ) {
return $result;
}
return $result['credit'];
}
/**
* This method will return commission amount for a specific order
*
* @since 3.5.1
*
* @param int $order_id
*
* @return float
*/
public function get_commission_amount_by_order( $order_id ) {
global $wpdb;
//@codingStandardsIgnoreStart
return (float) $wpdb->get_var(
$wpdb->prepare(
"SELECT debit FROM {$this->get_table()} WHERE trn_id = %d AND trn_type = %s",
$order_id, 'order_commission'
)
);
//@codingStandardsIgnoreEnd
}
/**
* This method will return unique stores under reverse withdrawal table
*
* @param array $args
*
* @since 3.5.1
*
* @return array|WP_Error
*/
public function get_stores( $args = [] ) {
$default = [
'per_page' => 20,
'page' => 1,
];
$args = wp_parse_args( $args, $default );
global $wpdb;
$fields = ' DISTINCT trn.vendor_id as id, u_meta.meta_value as name ';
$join = " LEFT JOIN {$wpdb->usermeta} AS u_meta ON trn.vendor_id = u_meta.user_id";
$where = ' AND u_meta.meta_key=%s';
$groupby = '';
$orderby = ' ORDER BY name ASC';
$limits = '';
$query_args = [ 1, 1, 'dokan_store_name' ];
// prepare search parameter
if ( ! empty( $args['search'] ) ) {
$like = '%' . $wpdb->esc_like( $args['search'] ) . '%';
$where .= ' AND u_meta.meta_value like %s';
$query_args[] = $like;
}
if ( $args['per_page'] ) {
$limit = absint( $args['per_page'] );
$page = absint( $args['page'] );
$page = $page ? $page : 1;
$offset = ( $page - 1 ) * $limit;
$limits = 'LIMIT %d, %d';
$query_args[] = $offset;
$query_args[] = $limit;
}
// @codingStandardsIgnoreStart
$data = $wpdb->get_results(
$wpdb->prepare(
"SELECT $fields FROM {$this->table} AS trn $join WHERE %d=%d $where $groupby $orderby $limits", //phpcs:ignore
$query_args
),
ARRAY_A
);
// @codingStandardsIgnoreEnd
// check for db error
if ( ! empty( $wpdb->last_error ) ) {
dokan_log( '[Dokan Reverse Withdrawal] Error while fetching data: <strong>' . $wpdb->last_error . '</strong>' );
return new WP_Error( 'db_query_error', $wpdb->last_error, $wpdb->last_query );
}
return null === $data ? [] : $data;
}
/**
* Get dokan_reverse_withdrawal table with prefix
*
* @since 3.5.1
*
* @return string
*/
public function get_table() {
return $this->table;
}
/**
* This will check if given var is empty or not.
*
* @since 3.5.1
*
* @param mixed $var
*
* @return bool
*/
protected function is_empty( $var ) {
if ( empty( $var ) ) {
return true;
}
if ( isset( $var[0] ) && intval( $var[0] ) === 0 ) {
return true;
}
return false;
}
}