wallet
This commit is contained in:
@ -0,0 +1,346 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Wallet\PlatformUser;
|
||||
|
||||
use App\Cache\Lock\WalletPlatformUserTransactionLock;
|
||||
use App\Exceptions\ModelException;
|
||||
use App\Jobs\UserActiveStatusQueue;
|
||||
use App\Jobs\WalletPlatformUserWithdrawQueue;
|
||||
use App\Models\Wallet\Base\WalletBaseModel;
|
||||
use App\Models\Wallet\Platform\WalletPlatformBalanceModel;
|
||||
use App\Models\Wallet\Platform\WalletPlatformBalanceTransactionModel;
|
||||
use App\Models\Wallet\Wallet\WalletAddrModel;
|
||||
use App\Models\Wallet\Wallet\WalletAddrTransactionModel;
|
||||
use App\Models\Wallet\Wallet\WalletCurrencyModel;
|
||||
use App\Structs\QueueUserActiveStatusStruct;
|
||||
use App\Structs\QueueWalletPlatformUserWithdrawStruct;
|
||||
use App\Tools\Math;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class WalletPlatformUserTransactionModel extends WalletBaseModel
|
||||
{
|
||||
protected $table = 'wallet_platform_user_transaction';
|
||||
protected $primaryKey = 'id';
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'type',
|
||||
'platform_id',
|
||||
'uid',
|
||||
'currency_id',
|
||||
'currency_code',
|
||||
'currency_type',
|
||||
'from_wallet_addr_id',
|
||||
'wallet_addr',
|
||||
'received_amount',
|
||||
'entered_amount',
|
||||
'fee_amount',
|
||||
'desc_key',
|
||||
'desc',
|
||||
'remark',
|
||||
'sign',
|
||||
'platform_notify_status',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
];
|
||||
|
||||
const TYPE_RECHARGE = 1;
|
||||
const TYPE_WITHDRAW = 2;
|
||||
const TYPE = [
|
||||
self::TYPE_RECHARGE => '充值',
|
||||
self::TYPE_WITHDRAW => '提现',
|
||||
];
|
||||
|
||||
const STATUS_WAITING_QUEUE = 1;
|
||||
const STATUS_CODE_PROCESSING = 2;
|
||||
const STATUS_CHAIN_WAITING = 3;
|
||||
const STATUS_SUCCESS = 4;
|
||||
const STATUS_FAIL = 5;
|
||||
const STATUS = [
|
||||
self::STATUS_WAITING_QUEUE => '等待队列',
|
||||
self::STATUS_CODE_PROCESSING => '程序处理中',
|
||||
self::STATUS_CHAIN_WAITING => '链上等待',
|
||||
self::STATUS_SUCCESS => '成功',
|
||||
self::STATUS_FAIL => '失败',
|
||||
];
|
||||
|
||||
const DESC_KEY_NOT_FOUND_WITHDRAW_AMOUNT_WALLET_ADDR = 'notFoundWithdrawAmountWalletAddr';
|
||||
const DESC_KEY_WITHDRAW_WALLET_AMOUNT_LOW = 'withdrawWalletAmountLow';
|
||||
const DESC_KEY_WITHDRAW_CALL_CHAIN_WRONG = 'withdrawCallChainWrong';
|
||||
|
||||
const DESC = [
|
||||
self::DESC_KEY_NOT_FOUND_WITHDRAW_AMOUNT_WALLET_ADDR => '未找到足额提现金额钱包地址',
|
||||
self::DESC_KEY_WITHDRAW_WALLET_AMOUNT_LOW => '提现钱包金额不足',
|
||||
self::DESC_KEY_WITHDRAW_CALL_CHAIN_WRONG => '提现调用链上接口失败',
|
||||
];
|
||||
|
||||
//请求提现发起
|
||||
function withdrawFirst($amount, $platform_id, $uid, $currency_code, $desc_key = null, $remark = ''): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool
|
||||
{
|
||||
try {
|
||||
Db::beginTransaction();
|
||||
$amount = abs($amount);
|
||||
//检查平台余额
|
||||
$oWalletPlatformBalanceModel = new WalletPlatformBalanceModel();
|
||||
$resWalletPlatformBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalance($platform_id, $currency_code);
|
||||
if (!$resWalletPlatformBalanceModel) throw new ModelException('platform_id or currency_code error');
|
||||
if (Math::bcComp($resWalletPlatformBalanceModel->available_amount, $amount) == -1) throw new ModelException('platform balance not enough');
|
||||
|
||||
//冻结平台余额并增加账变
|
||||
$oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel();
|
||||
$resWalletPlatformBalanceTransactionModel = $oWalletPlatformBalanceTransactionModel->newWithdrawPlatformTransaction($amount, $platform_id, $currency_code);
|
||||
if (!$resWalletPlatformBalanceTransactionModel) throw new ModelException('newWithdrawPlatformTransaction error');
|
||||
|
||||
//根据币种计算费率
|
||||
$oWalletCurrencyModel = new WalletCurrencyModel();
|
||||
$oWalletCurrencyModel = $oWalletCurrencyModel->findByCode($currency_code);
|
||||
if (!$oWalletCurrencyModel) throw new ModelException('currency_code error');
|
||||
$fee_amount = $oWalletCurrencyModel->computeTransferRate($amount, $oWalletCurrencyModel->transfer_rate);
|
||||
//预计费率计算
|
||||
if ($fee_amount <= 0) throw new ModelException('fee_amount error');
|
||||
$desc = isset(self::DESC[$desc_key]) ? self::DESC[$desc_key] : '';
|
||||
$resModel = $this->addWithdrawTransaction($platform_id, $uid, $oWalletCurrencyModel, $amount, $fee_amount, $desc_key, $desc, $remark);
|
||||
if (!$resModel) throw new ModelException('addItem error');
|
||||
$oWalletPlatformBalanceTransactionModel->updateItem([
|
||||
'id' => $resWalletPlatformBalanceTransactionModel->id,
|
||||
'from_user_transaction_id' => $resModel->id,
|
||||
]);
|
||||
$this->putWithdrawToQueue($resModel->id); //投递到队列处理
|
||||
Db::commit();
|
||||
Log::info('newWithdrawSucc', ['platform_id' => $platform_id, 'uid' => $uid, 'currency_code' => $currency_code, 'amount' => $amount]);
|
||||
return $resModel;
|
||||
} catch (\Exception $e) {
|
||||
Db::rollBack();
|
||||
Log::error('newWithdrawErr', ['platform_id' => $platform_id, 'uid' => $uid, 'currency_code' => $currency_code, 'amount' => $amount, 'msg' => $e->getMessage()]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function addWithdrawTransaction($platform_id, $uid, $oWalletCurrencyModel, $amount, $fee_amount, $desc_key = null, $desc = '', $remark = ''): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool
|
||||
{
|
||||
$insert = [
|
||||
'type' => self::TYPE_WITHDRAW,
|
||||
'status' => self::STATUS_WAITING_QUEUE,
|
||||
'platform_id' => $platform_id,
|
||||
'uid' => $uid,
|
||||
'currency_id' => $oWalletCurrencyModel->id,
|
||||
'currency_code' => $oWalletCurrencyModel->code,
|
||||
'currency_type' => $oWalletCurrencyModel->type,
|
||||
'received_amount' => abs($amount),
|
||||
// 'entered_amount' => abs($entered_amount),
|
||||
'fee_amount' => abs($fee_amount),
|
||||
'desc_key' => $desc_key ?? '',
|
||||
'desc' => $desc,
|
||||
'remark' => $remark,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
return $this->addItem($insert);
|
||||
}
|
||||
|
||||
function addRechargeTransaction($platform_id, $uid, $oWalletCurrencyModel, $amount, $desc_key = null, $desc = '', $remark = ''): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool
|
||||
{
|
||||
$amount = abs($amount);
|
||||
$insert = [
|
||||
'type' => self::TYPE_RECHARGE,
|
||||
'status' => self::STATUS_SUCCESS, //充提成功
|
||||
'platform_id' => $platform_id,
|
||||
'uid' => $uid,
|
||||
'currency_id' => $oWalletCurrencyModel->id,
|
||||
'currency_code' => $oWalletCurrencyModel->code,
|
||||
'currency_type' => $oWalletCurrencyModel->type,
|
||||
'received_amount' => $amount,
|
||||
'entered_amount' => $amount,
|
||||
'desc_key' => $desc_key ?? '',
|
||||
'desc' => $desc,
|
||||
'remark' => $remark,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
return $this->addItem($insert);
|
||||
}
|
||||
|
||||
function addTransactionWithPlatformBalance($platform_id, $uid, $oWalletCurrencyModel, $amount, $desc_key = null, $desc = '', $remark = '')
|
||||
{
|
||||
try {
|
||||
Db::beginTransaction();
|
||||
$resModel = $this->addRechargeTransaction($platform_id, $uid, $oWalletCurrencyModel, $amount, $desc_key, $desc, $remark);
|
||||
if(!$resModel) throw new ModelException('addRechargeTransaction error');
|
||||
$oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel();
|
||||
$res = $oWalletPlatformBalanceTransactionModel->newRechargePlatformTransaction($amount, $platform_id, $oWalletCurrencyModel->code);
|
||||
if(!$res) throw new ModelException('newRechargePlatformTransaction error');
|
||||
Db::commit();
|
||||
return true;
|
||||
}catch (\Exception $e) {
|
||||
Db::rollBack();
|
||||
Log::error('addTransactionWithBalance', ['platform_id' => $platform_id, 'uid' => $uid, 'amount' => $amount, 'msg' => $e->getMessage()]);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//@@投递到rabbitmq队列处理
|
||||
function putWithdrawToQueue($wallet_platform_user_transaction_id): void
|
||||
{
|
||||
$params = [
|
||||
'wallet_platform_user_transaction_id' => $wallet_platform_user_transaction_id,
|
||||
];
|
||||
WalletPlatformUserWithdrawQueue::dispatch($params)->onQueue(QueueWalletPlatformUserWithdrawStruct::QUEUE_NAME);
|
||||
}
|
||||
|
||||
//处理用户提现队列,发起链上提现
|
||||
function withdrawConsumer($id): void
|
||||
{
|
||||
//@新增任务处理表
|
||||
//查询前先检查redis中锁
|
||||
$oWalletPlatformUserTransactionLock = new WalletPlatformUserTransactionLock();
|
||||
$isLock = $oWalletPlatformUserTransactionLock->checkLock($oWalletPlatformUserTransactionLock->getWithdrawKey($id));
|
||||
if ($isLock) return; //有锁就跳过
|
||||
//加锁
|
||||
$isLock = $oWalletPlatformUserTransactionLock->setLock($oWalletPlatformUserTransactionLock->getWithdrawKey($id));
|
||||
if (!$isLock) return; //加锁失败
|
||||
//查询任务
|
||||
$resWalletPlatformUserTransactionModel = $this->findItem($id);
|
||||
if (!$resWalletPlatformUserTransactionModel) throw new ModelException('id error');
|
||||
if ($resWalletPlatformUserTransactionModel->type != self::TYPE_WITHDRAW) throw new ModelException('type error');
|
||||
if ($resWalletPlatformUserTransactionModel->status != self::STATUS_WAITING_QUEUE) throw new ModelException('status error');
|
||||
$resWalletPlatformUserTransactionModel->status = self::STATUS_CODE_PROCESSING;
|
||||
$resWalletPlatformUserTransactionModel->save();
|
||||
|
||||
//获取提现地址
|
||||
$oWalletAddrModel = new WalletAddrModel();
|
||||
try {
|
||||
$resWalletAddrModel = $oWalletAddrModel->findWithdrawAddrWithAmount($resWalletPlatformUserTransactionModel->received_amount, $resWalletPlatformUserTransactionModel->currency_code);
|
||||
if (!$resWalletAddrModel) throw new ModelException('not found withdraw amount wallet addr');
|
||||
} catch (ModelException $e) { //未找到足额提现金额钱包地址
|
||||
$code = $e->getCode();
|
||||
$msg = $e->getMessage();
|
||||
$resWalletPlatformUserTransactionModel->status = self::STATUS_FAIL;
|
||||
if ($code == ModelException::CODE_WALLET_AMOUNT_ADDR_NOT_FOUND) { //未找到足额提现金额钱包地址
|
||||
$resWalletPlatformUserTransactionModel->desc_key = self::DESC_KEY_NOT_FOUND_WITHDRAW_AMOUNT_WALLET_ADDR;
|
||||
$resWalletPlatformUserTransactionModel->desc = self::DESC[self::DESC_KEY_NOT_FOUND_WITHDRAW_AMOUNT_WALLET_ADDR];
|
||||
}
|
||||
if ($code == ModelException::CODE_WALLET_ADDR_BALANCE_LOW) { //提现钱包金额不足
|
||||
$resWalletPlatformUserTransactionModel->desc_key = self::DESC_KEY_WITHDRAW_WALLET_AMOUNT_LOW;
|
||||
$resWalletPlatformUserTransactionModel->desc = self::DESC[self::DESC_KEY_WITHDRAW_WALLET_AMOUNT_LOW];
|
||||
}
|
||||
|
||||
$resWalletPlatformUserTransactionModel->save();
|
||||
$this->withdrawFailUnLock($id); //解锁
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$resWalletPlatformUserTransactionModel->from_wallet_addr_id = $resWalletAddrModel->id;
|
||||
$resWalletPlatformUserTransactionModel->wallet_addr = $resWalletAddrModel->addr;
|
||||
$resWalletPlatformUserTransactionModel->save();
|
||||
|
||||
//增加钱包账变
|
||||
$oWalletAddrTransactionModel = new WalletAddrTransactionModel();
|
||||
$resWalletAddrTransactionModel = $oWalletAddrTransactionModel->newPlatformUserWithdraw(
|
||||
$resWalletAddrModel->id,
|
||||
$resWalletPlatformUserTransactionModel->entered_amount,
|
||||
$resWalletPlatformUserTransactionModel->id
|
||||
);
|
||||
if (!$resWalletAddrTransactionModel) {
|
||||
$this->withdrawFailUnLock($id); //解锁
|
||||
return;
|
||||
}
|
||||
//调用链上接口
|
||||
$resChain = $oWalletAddrModel->callWalletAddrChainTransferApi($resWalletPlatformUserTransactionModel->id, $resWalletAddrModel->id);
|
||||
if (!$resChain) { //链上提现失败
|
||||
$resWalletPlatformUserTransactionModel->status = self::STATUS_FAIL;
|
||||
$resWalletPlatformUserTransactionModel->desc_key = self::DESC_KEY_WITHDRAW_CALL_CHAIN_WRONG;
|
||||
$resWalletPlatformUserTransactionModel->desc = self::DESC[self::DESC_KEY_WITHDRAW_CALL_CHAIN_WRONG];
|
||||
$resWalletPlatformUserTransactionModel->save();
|
||||
//解冻钱包余额
|
||||
$oWalletAddrTransactionModel->platformUserWithdrawCallback($resWalletAddrTransactionModel->id, $resWalletAddrTransactionModel->received_amount, WalletAddrTransactionModel::STATUS_FAIL);
|
||||
$this->withdrawFailUnLock($id); //解锁
|
||||
return;
|
||||
}
|
||||
$resWalletPlatformUserTransactionModel->status = self::STATUS_CHAIN_WAITING;
|
||||
$resWalletPlatformUserTransactionModel->save();
|
||||
$this->withdrawFailUnLock($id); //解锁
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('withdrawConsumer', ['id' => $id, 'msg' => $e->getMessage()]);
|
||||
$this->withdrawFailUnLock($id); //解锁
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//用户提现失败解锁并返还平台余额
|
||||
function withdrawFailUnLock($id): void
|
||||
{
|
||||
//返还用户余额
|
||||
$oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel();
|
||||
$oWalletPlatformBalanceTransactionModel->withdrawErrByUserTransactionId($id);
|
||||
//解锁
|
||||
$oWalletPlatformUserTransactionLock = new WalletPlatformUserTransactionLock();
|
||||
$oWalletPlatformUserTransactionLock->unLock($oWalletPlatformUserTransactionLock->getWithdrawKey($id));
|
||||
}
|
||||
|
||||
//提现链上回调监听
|
||||
function listenWithdrawCallback($wallet_addr_transaction_id): void
|
||||
{
|
||||
Log::info('listenWithdrawCallback', ['wallet_addr_transaction_id' => $wallet_addr_transaction_id]);
|
||||
//查找钱包账变
|
||||
$oWalletAddrTransactionModel = new WalletAddrTransactionModel();
|
||||
$resWalletAddrTransactionModel = $oWalletAddrTransactionModel->findItem($wallet_addr_transaction_id);
|
||||
if (!$resWalletAddrTransactionModel) throw new ModelException('wallet_addr_transaction_id error');
|
||||
if ($resWalletAddrTransactionModel->type !== WalletAddrTransactionModel::TYPE_TRANSFER) throw new ModelException('wallet_addr_transaction_type error');
|
||||
if (!in_array($resWalletAddrTransactionModel->status, [WalletAddrTransactionModel::STATUS_SUCCESS, WalletAddrTransactionModel::STATUS_FAIL])) throw new ModelException('status error');
|
||||
if ($resWalletAddrTransactionModel->status == WalletAddrTransactionModel::STATUS_SUCCESS) $status = self::STATUS_SUCCESS;
|
||||
if ($resWalletAddrTransactionModel->status == WalletAddrTransactionModel::STATUS_FAIL) $status = self::STATUS_FAIL;
|
||||
if (empty($resWalletAddrTransactionModel->platform_user_transaction_id)) throw new ModelException('platform_user_transaction_id error');
|
||||
$id = $resWalletAddrTransactionModel->platform_user_transaction_id;
|
||||
|
||||
if (!in_array($status, [self::STATUS_SUCCESS, self::STATUS_FAIL])) throw new ModelException('status error');
|
||||
$resWalletPlatformUserTransactionModel = $this->findItem($id);
|
||||
if (!$resWalletPlatformUserTransactionModel) throw new ModelException('id error');
|
||||
if ($resWalletPlatformUserTransactionModel->type != self::TYPE_WITHDRAW) throw new ModelException('type error');
|
||||
if ($resWalletPlatformUserTransactionModel->status != self::STATUS_CHAIN_WAITING) throw new ModelException('status error');
|
||||
//用户账变处理
|
||||
$resWalletPlatformUserTransactionModel->status = $status;
|
||||
$resWalletPlatformUserTransactionModel->save();
|
||||
|
||||
//平台余额和账变处理
|
||||
$oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel();
|
||||
if ($status == self::STATUS_SUCCESS) { //成功
|
||||
$oWalletPlatformBalanceTransactionModel->withdrawSuccByUserTransactionId($id);
|
||||
} else { //失败
|
||||
$oWalletPlatformBalanceTransactionModel->withdrawErrByUserTransactionId($id);
|
||||
}
|
||||
}
|
||||
|
||||
function listenRechargeCallback($wallet_addr_transaction_id): void
|
||||
{
|
||||
Log::info('listenRechargeCallback', ['wallet_addr_transaction_id' => $wallet_addr_transaction_id]);
|
||||
//查找钱包账变
|
||||
$oWalletAddrTransactionModel = new WalletAddrTransactionModel();
|
||||
$resWalletAddrTransactionModel = $oWalletAddrTransactionModel->findItem($wallet_addr_transaction_id);
|
||||
if (!$resWalletAddrTransactionModel) throw new ModelException('wallet_addr_transaction_id error');
|
||||
if ($resWalletAddrTransactionModel->type !== WalletAddrTransactionModel::TYPE_RECHARGE) throw new ModelException('wallet_addr_transaction_type error');
|
||||
if (!in_array($resWalletAddrTransactionModel->status, [WalletAddrTransactionModel::STATUS_SUCCESS, WalletAddrTransactionModel::STATUS_FAIL])) throw new ModelException('status error');
|
||||
if ($resWalletAddrTransactionModel->status == WalletAddrTransactionModel::STATUS_SUCCESS) $status = self::STATUS_SUCCESS;
|
||||
if ($resWalletAddrTransactionModel->status == WalletAddrTransactionModel::STATUS_FAIL) $status = self::STATUS_FAIL;
|
||||
if ($status != self::STATUS_SUCCESS) throw new ModelException('status not success');
|
||||
|
||||
$oWalletCurrencyModel = new WalletCurrencyModel();
|
||||
$resWalletCurrencyModel = $oWalletCurrencyModel->findItem($resWalletAddrTransactionModel->currency_id);
|
||||
|
||||
//查找用户绑定钱包地址
|
||||
$oWalletPlatformUserWalletAddrModel = new WalletPlatformUserWalletAddrModel();
|
||||
$resWalletPlatformUserWalletAddrModel = $oWalletPlatformUserWalletAddrModel->findByWalletAddrId($resWalletAddrTransactionModel->wallet_addr_id);
|
||||
if (!$resWalletPlatformUserWalletAddrModel) throw new ModelException('找不到wallet_addr_id绑定用户');
|
||||
|
||||
//给用户增加账变/平台增加账变增加余额
|
||||
$this->addTransactionWithPlatformBalance(
|
||||
$resWalletPlatformUserWalletAddrModel->platform_id,
|
||||
$resWalletPlatformUserWalletAddrModel->uid,
|
||||
$resWalletCurrencyModel,
|
||||
$resWalletAddrTransactionModel->received_amount,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user