subscription/includes/payment/class-yoone-payment-token.php

534 lines
14 KiB
PHP

<?php
/**
* 支付令牌类
*
* 管理客户的支付令牌,用于订阅续费和重复支付
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* 支付令牌类
*/
class Yoone_Payment_Token extends Abstract_Yoone_Data {
/**
* 对象类型
*/
protected $object_type = 'yoone_payment_token';
/**
* 数据结构
*/
protected $data = array(
'customer_id' => 0,
'gateway_id' => '',
'token' => '',
'token_type' => 'credit_card',
'card_type' => '',
'last_four' => '',
'expiry_month' => '',
'expiry_year' => '',
'is_default' => false,
'expires_at' => null,
'created_at' => null,
'updated_at' => null
);
/**
* 构造函数
*/
public function __construct($id = 0) {
parent::__construct($id);
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
*/
/**
* 获取客户ID
*/
public function get_customer_id($context = 'view') {
return $this->get_prop('customer_id', $context);
}
/**
* 获取网关ID
*/
public function get_gateway_id($context = 'view') {
return $this->get_prop('gateway_id', $context);
}
/**
* 获取令牌
*/
public function get_token($context = 'view') {
return $this->get_prop('token', $context);
}
/**
* 获取令牌类型
*/
public function get_token_type($context = 'view') {
return $this->get_prop('token_type', $context);
}
/**
* 获取卡片类型
*/
public function get_card_type($context = 'view') {
return $this->get_prop('card_type', $context);
}
/**
* 获取卡片后四位
*/
public function get_last_four($context = 'view') {
return $this->get_prop('last_four', $context);
}
/**
* 获取过期月份
*/
public function get_expiry_month($context = 'view') {
return $this->get_prop('expiry_month', $context);
}
/**
* 获取过期年份
*/
public function get_expiry_year($context = 'view') {
return $this->get_prop('expiry_year', $context);
}
/**
* 是否为默认令牌
*/
public function is_default($context = 'view') {
return $this->get_prop('is_default', $context);
}
/**
* 获取过期时间
*/
public function get_expires_at($context = 'view') {
return $this->get_prop('expires_at', $context);
}
/**
* 获取创建时间
*/
public function get_created_at($context = 'view') {
return $this->get_prop('created_at', $context);
}
/**
* 获取更新时间
*/
public function get_updated_at($context = 'view') {
return $this->get_prop('updated_at', $context);
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
*/
/**
* 设置客户ID
*/
public function set_customer_id($customer_id) {
$this->set_prop('customer_id', absint($customer_id));
}
/**
* 设置网关ID
*/
public function set_gateway_id($gateway_id) {
$this->set_prop('gateway_id', sanitize_text_field($gateway_id));
}
/**
* 设置令牌
*/
public function set_token($token) {
$this->set_prop('token', sanitize_text_field($token));
}
/**
* 设置令牌类型
*/
public function set_token_type($type) {
$valid_types = array('credit_card', 'debit_card', 'bank_account');
if (in_array($type, $valid_types)) {
$this->set_prop('token_type', $type);
}
}
/**
* 设置卡片类型
*/
public function set_card_type($type) {
$this->set_prop('card_type', sanitize_text_field($type));
}
/**
* 设置卡片后四位
*/
public function set_last_four($last_four) {
$this->set_prop('last_four', sanitize_text_field($last_four));
}
/**
* 设置过期月份
*/
public function set_expiry_month($month) {
$this->set_prop('expiry_month', str_pad(absint($month), 2, '0', STR_PAD_LEFT));
}
/**
* 设置过期年份
*/
public function set_expiry_year($year) {
$this->set_prop('expiry_year', absint($year));
}
/**
* 设置为默认令牌
*/
public function set_default($is_default) {
$this->set_prop('is_default', (bool) $is_default);
// 如果设置为默认,需要取消其他令牌的默认状态
if ($is_default && $this->get_customer_id()) {
$this->unset_other_defaults();
}
}
/**
* 设置过期时间
*/
public function set_expires_at($expires_at) {
$this->set_prop('expires_at', $this->format_date($expires_at));
}
/*
|--------------------------------------------------------------------------
| 验证方法
|--------------------------------------------------------------------------
*/
/**
* 检查令牌是否有效
*/
public function is_valid() {
// 检查基本信息
if (empty($this->get_token()) || empty($this->get_gateway_id()) || !$this->get_customer_id()) {
return false;
}
// 检查是否过期
if ($this->is_expired()) {
return false;
}
return true;
}
/**
* 检查令牌是否过期
*/
public function is_expired() {
$expires_at = $this->get_expires_at();
if (!$expires_at) {
return false;
}
return strtotime($expires_at) < time();
}
/**
* 检查卡片是否过期
*/
public function is_card_expired() {
$month = $this->get_expiry_month();
$year = $this->get_expiry_year();
if (!$month || !$year) {
return false;
}
$expiry_date = mktime(23, 59, 59, $month, date('t', mktime(0, 0, 0, $month, 1, $year)), $year);
return $expiry_date < time();
}
/*
|--------------------------------------------------------------------------
| 辅助方法
|--------------------------------------------------------------------------
*/
/**
* 获取显示名称
*/
public function get_display_name() {
$card_type = $this->get_card_type();
$last_four = $this->get_last_four();
if ($card_type && $last_four) {
return sprintf('%s ending in %s', ucfirst($card_type), $last_four);
}
return __('支付方式', 'yoone-subscriptions');
}
/**
* 取消其他令牌的默认状态
*/
protected function unset_other_defaults() {
global $wpdb;
$wpdb->update(
$wpdb->prefix . 'yoone_payment_tokens',
array('is_default' => 0),
array(
'customer_id' => $this->get_customer_id(),
'gateway_id' => $this->get_gateway_id()
),
array('%d'),
array('%d', '%s')
);
}
/**
* 格式化日期
*/
protected function format_date($date) {
if (empty($date)) {
return null;
}
if (is_numeric($date)) {
return date('Y-m-d H:i:s', $date);
}
return date('Y-m-d H:i:s', strtotime($date));
}
/*
|--------------------------------------------------------------------------
| 数据库操作
|--------------------------------------------------------------------------
*/
/**
* 从数据库读取
*/
protected function read() {
global $wpdb;
$data = $wpdb->get_row($wpdb->prepare("
SELECT * FROM {$wpdb->prefix}yoone_payment_tokens WHERE id = %d
", $this->get_id()));
if ($data) {
$this->set_props(array(
'customer_id' => $data->customer_id,
'gateway_id' => $data->gateway_id,
'token' => $data->token,
'token_type' => $data->token_type,
'card_type' => $data->card_type,
'last_four' => $data->last_four,
'expiry_month' => $data->expiry_month,
'expiry_year' => $data->expiry_year,
'is_default' => (bool) $data->is_default,
'expires_at' => $data->expires_at,
'created_at' => $data->created_at,
'updated_at' => $data->updated_at
));
}
}
/**
* 创建记录
*/
protected function create() {
global $wpdb;
$data = array(
'customer_id' => $this->get_customer_id('edit'),
'gateway_id' => $this->get_gateway_id('edit'),
'token' => $this->get_token('edit'),
'token_type' => $this->get_token_type('edit'),
'card_type' => $this->get_card_type('edit'),
'last_four' => $this->get_last_four('edit'),
'expiry_month' => $this->get_expiry_month('edit'),
'expiry_year' => $this->get_expiry_year('edit'),
'is_default' => $this->is_default('edit') ? 1 : 0,
'expires_at' => $this->get_expires_at('edit'),
'created_at' => current_time('mysql'),
'updated_at' => current_time('mysql')
);
$result = $wpdb->insert(
$wpdb->prefix . 'yoone_payment_tokens',
$data,
array('%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s')
);
if ($result) {
$this->set_id($wpdb->insert_id);
do_action('yoone_payment_token_created', $this->get_id(), $this);
}
return $result;
}
/**
* 更新记录
*/
protected function update() {
global $wpdb;
$changes = $this->get_changes();
if (empty($changes)) {
return true;
}
$changes['updated_at'] = current_time('mysql');
$result = $wpdb->update(
$wpdb->prefix . 'yoone_payment_tokens',
$changes,
array('id' => $this->get_id()),
null,
array('%d')
);
if ($result !== false) {
do_action('yoone_payment_token_updated', $this->get_id(), $this);
}
return $result !== false;
}
/**
* 从数据库删除
*/
protected function delete_from_database($force_delete = false) {
global $wpdb;
$result = $wpdb->delete(
$wpdb->prefix . 'yoone_payment_tokens',
array('id' => $this->get_id()),
array('%d')
);
if ($result) {
do_action('yoone_payment_token_deleted', $this->get_id());
}
return $result !== false;
}
/**
* 设置多个属性
*/
protected function set_props($props) {
foreach ($props as $prop => $value) {
if (array_key_exists($prop, $this->data)) {
$this->data[$prop] = $value;
}
}
}
/*
|--------------------------------------------------------------------------
| 静态方法
|--------------------------------------------------------------------------
*/
/**
* 根据客户ID获取令牌
*/
public static function get_customer_tokens($customer_id, $gateway_id = '') {
global $wpdb;
$where = $wpdb->prepare("customer_id = %d", $customer_id);
if ($gateway_id) {
$where .= $wpdb->prepare(" AND gateway_id = %s", $gateway_id);
}
$where .= " AND (expires_at IS NULL OR expires_at > NOW())";
$results = $wpdb->get_results("
SELECT id FROM {$wpdb->prefix}yoone_payment_tokens
WHERE {$where}
ORDER BY is_default DESC, created_at DESC
");
$tokens = array();
foreach ($results as $result) {
$tokens[] = new self($result->id);
}
return $tokens;
}
/**
* 根据令牌字符串获取令牌对象
*/
public static function get_by_token($token, $gateway_id) {
global $wpdb;
$id = $wpdb->get_var($wpdb->prepare("
SELECT id FROM {$wpdb->prefix}yoone_payment_tokens
WHERE token = %s AND gateway_id = %s
", $token, $gateway_id));
return $id ? new self($id) : null;
}
/**
* 获取客户的默认令牌
*/
public static function get_default_token($customer_id, $gateway_id) {
global $wpdb;
$id = $wpdb->get_var($wpdb->prepare("
SELECT id FROM {$wpdb->prefix}yoone_payment_tokens
WHERE customer_id = %d AND gateway_id = %s AND is_default = 1
AND (expires_at IS NULL OR expires_at > NOW())
", $customer_id, $gateway_id));
return $id ? new self($id) : null;
}
/**
* 清理过期令牌
*/
public static function cleanup_expired_tokens() {
global $wpdb;
$count = $wpdb->query("
DELETE FROM {$wpdb->prefix}yoone_payment_tokens
WHERE expires_at IS NOT NULL AND expires_at < NOW()
");
if ($count > 0) {
Yoone_Logger::info("清理了 {$count} 个过期的支付令牌");
}
return $count;
}
}