Files
cycle_api/app/Models/Api/Wallet/CustomerWalletBalanceTransactionModel.php
2024-03-29 11:10:00 +08:00

884 lines
45 KiB
PHP

<?php
namespace App\Models\Api\Wallet;
use App\Bean\Model\Api\Order\CustomerUserPostOrderBean;
use App\Bean\Model\Api\Wallet\CustomerWalletBalanceTransactionBean;
use App\Cache\Table\Api\TableCustomerSettingCache;
use App\Exceptions\ModelException;
use App\Models\Api\Base\ApiBaseModel;
use App\Models\Api\Order\CustomerUserPostOrderModel;
use App\Tools\Logs;
use App\Tools\Math;
use App\Tools\Times;
use Illuminate\Support\Facades\DB;
class CustomerWalletBalanceTransactionModel extends ApiBaseModel
{
protected $table = 'customer_wallet_balance_transaction';
protected $primaryKey = 'id';
protected $fillable = [
'id',
'type',
'status',
'wallet_id',
'uid',
'currency_code',
'amount',
'fee_amount',
'before_total_amount',
'after_total_amount',
'source_params',
'remark',
'target_uid',
'target_post_order_id',
'target_post_order_dispute_id',
'sign',
'callback_time',
'delay_payment_time',
'created_at',
'updated_at',
];
const TYPE_RECHARGE_ADD = 1;
const TYPE_WITHDRAW_DEC = 2;
const TYPE_ORDER_PAY_DEC = 3;
const TYPE_ORDER_RECEIVE_ADD = 4;
const TYPE_ORDER_REFUND_SUB = 5;
const TYPE_BALANCE_TO_SECURITY = 6;
const TYPE_SECURITY_TO_BALANCE = 7;
const TYPE_DISPUTE_ADD = 8;
const TYPE_DISPUTE_SUB = 9;
const TYPE_TRANSACTION_FEE_SUB = 10;
const TYPE_TRANSACTION_FEE_ADD = 11;
const TYPE_ADMIN_ADD = 12;
const TYPE_ADMIN_SUB = 13;
const TYPE_TRANSFER_TO_USER_DEC = 14;
const TYPE_TRANSFER_RECEIVE_ADD = 15;
const TYPE_ORDER_DISPUTE_FEE_DEC = 16;
const TYPE_ORDER_DISPUTE_FEE_ADD = 17;
const TYPE = [
self::TYPE_RECHARGE_ADD => '充值',
self::TYPE_WITHDRAW_DEC => '提现',
self::TYPE_ORDER_PAY_DEC => '订单支付',
self::TYPE_ORDER_RECEIVE_ADD => '订单收款',
self::TYPE_ORDER_REFUND_SUB => '订单退款',
self::TYPE_BALANCE_TO_SECURITY => '余额转保证金',
self::TYPE_SECURITY_TO_BALANCE => '保证金转余额',
self::TYPE_DISPUTE_ADD => '纠纷加款',
self::TYPE_DISPUTE_SUB => '纠纷扣款',
self::TYPE_TRANSACTION_FEE_SUB => '交易手续费扣除',
self::TYPE_TRANSACTION_FEE_ADD => '交易手续费增加',
self::TYPE_ADMIN_ADD => '管理员加款',
self::TYPE_ADMIN_SUB => '管理员扣款',
self::TYPE_TRANSFER_TO_USER_DEC => '转账给用户',
self::TYPE_TRANSFER_RECEIVE_ADD => '转账收款',
self::TYPE_ORDER_DISPUTE_FEE_DEC => '纠纷仲裁费用扣除',
self::TYPE_ORDER_DISPUTE_FEE_ADD => '纠纷仲裁费用退还',
];
const STATUS_WAIT = 1;
const STATUS_PROCESSING = 2;
const STATUS_SUCCESS = 3;
const STATUS_FAIL = 4;
const STATUS_DELAY_PAYMENT = 5;
const STATUS = [
self::STATUS_WAIT => '等待处理',
self::STATUS_PROCESSING => '处理中',
self::STATUS_SUCCESS => '成功',
self::STATUS_FAIL => '失败',
self::STATUS_DELAY_PAYMENT => '延期到账',
];
const SOURCE_PARAMS_BALANCE = 1;
const SOURCE_PARAMS_SECURITY = 2;
const SOURCE_PARAMS = [
self::SOURCE_PARAMS_BALANCE => '余额',
self::SOURCE_PARAMS_SECURITY => '保证金',
];
function getDelayPayList($datetime, $col = ['*']): \Illuminate\Database\Eloquent\Collection|array
{
return $this->newQuery()->where('status', self::STATUS_DELAY_PAYMENT)->where('delay_payment_time', '<=', $datetime)->limit(100)->get($col);
}
//纠纷仲裁费用退还
function typeOrderDisputeFeeAdd($uid, $currency_code, $amount, $remark = null): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(abs($amount)); //正数
$bean->setType(self::TYPE_ORDER_DISPUTE_FEE_ADD);
$bean->setStatus(self::STATUS_SUCCESS);
$bean->setRemark($remark);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
$res = $oCustomerWalletBalanceModel->addAvailableAmount($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('order dispute fee add fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//纠纷仲裁费用扣除
function typeOrderDisputeFeeDec($uid, $currency_code, $amount, $remark = null): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(-abs($amount)); //账变负数
$bean->setType(self::TYPE_ORDER_DISPUTE_FEE_DEC);
$bean->setStatus(self::STATUS_SUCCESS);
$bean->setRemark($remark);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
if (Math::bcComp($resWalletBalanceModel->available_amount, abs($bean->getAmount())) != -1) throw new ModelException('balance not enough');
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
$res = $oCustomerWalletBalanceModel->subAvailableAmount($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('order dispute fee dec fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//处理延期账变
function dealDelayPaymentTransactionCmd(): void
{
$datetimeNow = Times::getNowDateTime();
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
while (true) {
$resList = $this->getDelayPayList($datetimeNow, ['id']);
if ($resList->isEmpty()) {
break;
}
foreach ($resList as $itemId) {
try {
DB::beginTransaction();
$item = $this->findItem($itemId->id);
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findItem($item->wallet_id);
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$updateItem = [
'id' => $item->id,
'status' => self::STATUS_SUCCESS,
'updated_at' => Times::getNowDateTime(),
];
$res = $this->updateItem($updateItem);
if (!$res) throw new ModelException('updateItem fail');
$res = $oCustomerWalletBalanceModel->unFrozenAmount($item->wallet_id, $item->amount);
if (!$res) throw new ModelException('unFrozenAmount fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
}
}
}
}
//转账给用户
function typeTransferToUser($uid, $target_uid, $currency_code, $amount, $remark = null): bool
{
$senderWalletTransactionBean = new CustomerWalletBalanceTransactionBean();
$receiverWalletTransactionBean = new CustomerWalletBalanceTransactionBean();
$senderWalletTransactionBean->setUid($uid);
$senderWalletTransactionBean->setTargetUid($target_uid);
$senderWalletTransactionBean->setCurrencyCode($currency_code);
$senderWalletTransactionBean->setAmount(-abs($amount)); //账变负数
$senderWalletTransactionBean->setType(self::TYPE_TRANSFER_TO_USER_DEC);
$senderWalletTransactionBean->setStatus(self::STATUS_SUCCESS);
$senderWalletTransactionBean->setRemark($remark);
$receiverWalletTransactionBean->setUid($target_uid);
$receiverWalletTransactionBean->setTargetUid($uid);
$receiverWalletTransactionBean->setCurrencyCode($currency_code);
$receiverWalletTransactionBean->setAmount(abs($amount)); //账变正数
$receiverWalletTransactionBean->setType(self::TYPE_TRANSFER_RECEIVE_ADD);
$receiverWalletTransactionBean->setStatus(self::STATUS_SUCCESS);
$receiverWalletTransactionBean->setRemark($remark);
try {
DB::beginTransaction();
//查询发送人余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resSenderWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($senderWalletTransactionBean->getUid(), $senderWalletTransactionBean->getCurrencyCode());
if (!$resSenderWalletBalanceModel) throw new ModelException('sender wallet not found');
//加悲观锁
$resSenderWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resSenderWalletBalanceModel->id);
//查询接收人余额
$resReceiverWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($receiverWalletTransactionBean->getUid(), $receiverWalletTransactionBean->getCurrencyCode());
if (!$resReceiverWalletBalanceModel) throw new ModelException('receiver wallet not found');
//加悲观锁
$resReceiverWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resReceiverWalletBalanceModel->id);
//检查发送人余额是否足够
if (Math::bcComp($resSenderWalletBalanceModel->available_amount, abs($senderWalletTransactionBean->getAmount())) != -1) throw new ModelException('balance not enough');
$senderWalletTransactionBean->setWalletId($resSenderWalletBalanceModel->id);
$senderWalletTransactionBean->setBeforeTotalAmount($resSenderWalletBalanceModel->total_amount);
$senderWalletTransactionBean->setAfterTotalAmount(Math::bcAdd($resSenderWalletBalanceModel->total_amount, $senderWalletTransactionBean->getAmount()));
//发送人新增账变
$res = $this->addTransaction($senderWalletTransactionBean);
if (!$res) throw new ModelException('addTransaction fail');
//发送人变更余额
$res = $oCustomerWalletBalanceModel->subAvailableAmount($senderWalletTransactionBean->getWalletId(), $senderWalletTransactionBean->getAmount());
if (!$res) throw new ModelException('transfer to user dec fail');
//接收人账变
$receiverWalletTransactionBean->setWalletId($resReceiverWalletBalanceModel->id);
$receiverWalletTransactionBean->setBeforeTotalAmount($resReceiverWalletBalanceModel->total_amount);
$receiverWalletTransactionBean->setAfterTotalAmount(Math::bcAdd($resReceiverWalletBalanceModel->total_amount, $receiverWalletTransactionBean->getAmount()));
//接收人新增账变
$res = $this->addTransaction($receiverWalletTransactionBean);
if (!$res) throw new ModelException('addTransaction fail');
//接收人变更余额
$res = $oCustomerWalletBalanceModel->addAvailableAmount($receiverWalletTransactionBean->getWalletId(), $receiverWalletTransactionBean->getAmount());
if (!$res) throw new ModelException('transfer receive add fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//管理员扣除
function typeAdminSub($uid, $currency_code, $amount, $remark = null): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(-abs($amount)); //账变负数
$bean->setType(self::TYPE_ADMIN_SUB);
$bean->setStatus(self::STATUS_SUCCESS);
$bean->setRemark($remark);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
if (Math::bcComp($resWalletBalanceModel->available_amount, abs($bean->getAmount())) != -1) throw new ModelException('balance not enough');
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
$res = $oCustomerWalletBalanceModel->subAvailableAmount($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('admin sub fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//管理员增加
function typeAdminAdd($uid, $currency_code, $amount, $remark = null): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(abs($amount)); //正数
$bean->setType(self::TYPE_ADMIN_ADD);
$bean->setStatus(self::STATUS_SUCCESS);
$bean->setRemark($remark);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
$res = $oCustomerWalletBalanceModel->addAvailableAmount($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('admin add fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//手续费增加
function typeTransactionFeeAdd($uid, $currency_code, $amount, $remark = null): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(abs($amount)); //正数
$bean->setType(self::TYPE_TRANSACTION_FEE_ADD);
$bean->setStatus(self::STATUS_SUCCESS);
$bean->setRemark($remark);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
$res = $oCustomerWalletBalanceModel->addAvailableAmount($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('transaction fee add fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//手续费扣除
function typeTransactionFeeSub($uid, $currency_code, $amount, $remark = null): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(-abs($amount)); //账变负数
$bean->setType(self::TYPE_TRANSACTION_FEE_SUB);
$bean->setStatus(self::STATUS_SUCCESS);
$bean->setRemark($remark);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
//检查余额是否足够
if (Math::bcComp($resWalletBalanceModel->available_amount, abs($bean->getAmount())) != -1) { //从余额中扣除
$bean->setSourceParams(self::SOURCE_PARAMS_BALANCE);
$res = $oCustomerWalletBalanceModel->subAvailableAmount($bean->getWalletId(), $bean->getAmount());
} else if (Math::bcComp($resWalletBalanceModel->security_amount, abs($bean->getAmount())) != -1) { //从保证金中扣除
$bean->setSourceParams(self::SOURCE_PARAMS_SECURITY);
$res = $oCustomerWalletBalanceModel->subSecurityAmount($bean->getWalletId(), $bean->getAmount());
} else {
throw new ModelException('balance and security not enough');
}
if (!$res) throw new ModelException('transaction fee sub fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//仲裁判罚扣除
function typeDisputeSub($uid, $currency_code, $amount, $target_post_order_dispute_id, $remark = null): bool|int
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(-abs($amount)); //账变负数
$bean->setType(self::TYPE_DISPUTE_SUB);
$bean->setStatus(self::STATUS_SUCCESS);
$bean->setRemark($remark);
$bean->setTargetPostOrderDisputeId($target_post_order_dispute_id);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$resModel = $this->addTransaction($bean);
if (!$resModel) throw new ModelException('addTransaction fail');
//变更余额
//检查余额是否足够
if (Math::bcComp($resWalletBalanceModel->available_amount, abs($bean->getAmount())) != -1) { //从余额中扣除
$bean->setSourceParams(self::SOURCE_PARAMS_BALANCE);
$res = $oCustomerWalletBalanceModel->subAvailableAmount($bean->getWalletId(), $bean->getAmount());
} else if (Math::bcComp($resWalletBalanceModel->security_amount, abs($bean->getAmount())) != -1) { //从保证金中扣除
$bean->setSourceParams(self::SOURCE_PARAMS_SECURITY);
$res = $oCustomerWalletBalanceModel->subSecurityAmount($bean->getWalletId(), $bean->getAmount());
} else {
throw new ModelException('balance and security not enough');
}
if (!$res) throw new ModelException('dispute sub fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return $resModel->id;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//仲裁判罚增加
function typeDisputeAdd($uid, $currency_code, $amount, $target_post_order_dispute_id, $remark = null): bool|int
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(abs($amount)); //正数
$bean->setType(self::TYPE_DISPUTE_ADD);
$bean->setStatus(self::STATUS_SUCCESS);
$bean->setRemark($remark);
$bean->setTargetPostOrderDisputeId($target_post_order_dispute_id);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$resModel = $this->addTransaction($bean);
if (!$resModel) throw new ModelException('addTransaction fail');
//变更余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$res = $oCustomerWalletBalanceModel->addAvailableAmount($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('dispute add fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return $resModel->id;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//押金转余额
function typeSecurityToBalance($uid, $currency_code, $amount): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(abs($amount)); //正数
$bean->setType(self::TYPE_SECURITY_TO_BALANCE);
$bean->setStatus(self::STATUS_SUCCESS);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//检查保证金是否足够
if (Math::bcComp($resWalletBalanceModel->security_amount, abs($bean->getAmount())) == -1) throw new ModelException('security not enough');
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$res = $oCustomerWalletBalanceModel->securityToBalance($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('securityToBalance fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//余额转押金
function typeBalanceToSecurity($uid, $currency_code, $amount): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(-abs($amount)); //账变负数
$bean->setType(self::TYPE_BALANCE_TO_SECURITY);
$bean->setStatus(self::STATUS_SUCCESS);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//检查余额是否足够
if (Math::bcComp($resWalletBalanceModel->available_amount, abs($bean->getAmount())) == -1) throw new ModelException('balance not enough');
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$res = $oCustomerWalletBalanceModel->balanceToSecurity($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('balanceToSecurity fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//订单支付
function typeOrderPay(CustomerUserPostOrderBean $orderBean): bool
{
//初始检测
if ($orderBean->getBuyerCurrencyCode() != $orderBean->getSellerCurrencyCode()) throw new ModelException('currency_code not match');
if ($orderBean->getBuyerUid() == $orderBean->getSellerUid()) throw new ModelException('buyer_uid can not match seller_uid');
if ($orderBean->getAmount() <= 0) throw new ModelException('amount error');
$orderBean->setAmount(abs($orderBean->getAmount())); //限制正数
$buyerWalletTransactionBean = new CustomerWalletBalanceTransactionBean();
$sellerWalletTransactionBean = new CustomerWalletBalanceTransactionBean();
//买家初始化
$buyerWalletTransactionBean->setType(self::TYPE_ORDER_PAY_DEC);
$buyerWalletTransactionBean->setStatus(self::STATUS_SUCCESS);
$buyerWalletTransactionBean->setAmount(-$orderBean->getAmount()); //负数
$buyerWalletTransactionBean->setUid($orderBean->getBuyerUid());
$buyerWalletTransactionBean->setCurrencyCode($orderBean->getBuyerCurrencyCode());
$buyerWalletTransactionBean->setTargetPostOrderId($orderBean->getId());
//卖家初始化
$sellerWalletTransactionBean->setType(self::TYPE_ORDER_RECEIVE_ADD);
$sellerWalletTransactionBean->setStatus(self::STATUS_DELAY_PAYMENT);
$sellerWalletTransactionBean->setAmount($orderBean->getAmount()); //正数
$sellerWalletTransactionBean->setUid($orderBean->getSellerUid());
$sellerWalletTransactionBean->setCurrencyCode($orderBean->getSellerCurrencyCode());
$sellerWalletTransactionBean->setTargetPostOrderId($orderBean->getId());
//@@计算订单延期到账时间
$delay_payment_time = Times::getNowDateTimeAddDays(1);
$sellerWalletTransactionBean->setDelayPaymentTime($delay_payment_time);
try {
DB::beginTransaction();
//查询买家余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resBuyerWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($buyerWalletTransactionBean->getUid(), $buyerWalletTransactionBean->getCurrencyCode());
if (!$resBuyerWalletBalanceModel) throw new ModelException('buyer wallet not found');
//加悲观锁
$resBuyerWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resBuyerWalletBalanceModel->id);
//检查买家余额是否足够
if (Math::bcComp($resBuyerWalletBalanceModel->available_amount, abs($orderBean->getAmount())) == -1) throw new ModelException('buyer balance not enough');
//设置买家卖家钱包id
$buyerWalletTransactionBean->setWalletId($resBuyerWalletBalanceModel->id);
$buyerWalletTransactionBean->setBeforeTotalAmount($resBuyerWalletBalanceModel->total_amount);
$buyerWalletTransactionBean->setAfterTotalAmount(Math::bcAdd($resBuyerWalletBalanceModel->total_amount, $buyerWalletTransactionBean->getAmount()));
//设置卖家卖家钱包id
$resSellerWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($sellerWalletTransactionBean->getUid(), $sellerWalletTransactionBean->getCurrencyCode());
if (!$resSellerWalletBalanceModel) throw new ModelException('seller wallet not found');
//加悲观锁
$resSellerWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resSellerWalletBalanceModel->id);
$sellerWalletTransactionBean->setWalletId($resSellerWalletBalanceModel->id);
$sellerWalletTransactionBean->setBeforeTotalAmount($resSellerWalletBalanceModel->total_amount);
$sellerWalletTransactionBean->setAfterTotalAmount(Math::bcAdd($resSellerWalletBalanceModel->total_amount, $sellerWalletTransactionBean->getAmount()));
//买家新增账变
$resBuyerTransaction = $this->addTransaction($buyerWalletTransactionBean);
if (!$resBuyerTransaction) throw new ModelException('buyer addTransaction fail');
$buyerWalletTransactionBean->setId($resBuyerTransaction->id);
//买家变更余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$res = $oCustomerWalletBalanceModel->subAvailableAmount($buyerWalletTransactionBean->getWalletId(), $buyerWalletTransactionBean->getAmount());
if (!$res) throw new ModelException('buyer order pay fail');
//卖家新增账变
$resSellerTransaction = $this->addTransaction($sellerWalletTransactionBean);
if (!$resSellerTransaction) throw new ModelException('seller addTransaction fail');
$sellerWalletTransactionBean->setId($resSellerTransaction->id);
//卖家变更余额
$res = $oCustomerWalletBalanceModel->addFrozenAmount($sellerWalletTransactionBean->getWalletId(), $sellerWalletTransactionBean->getAmount());
if (!$res) throw new ModelException('seller order receive fail');
//更新订单状态
$oCustomerUserPostOrderModel = new CustomerUserPostOrderModel();
$updateItem = [
'id' => $orderBean->getId(),
'pay_status' => CustomerUserPostOrderModel::PAY_STATUS_PAID,
'buyer_wallet_transaction_id' => $buyerWalletTransactionBean->getId(),
'seller_wallet_transaction_id' => $sellerWalletTransactionBean->getId(),
'updated_at' => Times::getNowDateTime(),
];
$res = $oCustomerUserPostOrderModel->updateItem($updateItem);
if (!$res) throw new ModelException('updateItem fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//发起提现
function typeWithdrawFirst($uid, $currency_code, $amount): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(-abs($amount)); //负数
$bean->setUid($uid);
$bean->setType(self::TYPE_WITHDRAW_DEC);
$bean->setStatus(self::STATUS_PROCESSING);
try {
DB::beginTransaction();
//获取提现手续费
$oTableCustomerSettingCache = new TableCustomerSettingCache();
$withdraw_fee = $oTableCustomerSettingCache->getWithdrawFeeAmount();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
//检查余额是否足够
if (Math::bcComp(Math::bcSub($resWalletBalanceModel->available_amount, $withdraw_fee), abs($bean->getAmount())) == -1) throw new ModelException('balance not enough');
$bean->setFeeAmount($withdraw_fee);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount($resWalletBalanceModel->total_amount);
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//先扣除手续费
$res = $this->typeTransactionFeeSub($uid, $currency_code, $withdraw_fee, $res->id . ' withdraw fee');
if (!$res) throw new ModelException('withdraw fee fail');
//变更余额
//先冻结,等回调成功再扣减
$res = $oCustomerWalletBalanceModel->frozenAmount($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('withdraw fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
//@@发送到提现通知钱包队列
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//提现回调
function typeWithdrawSecondCallback($id, $status, $remark = null): bool
{
try {
DB::beginTransaction();
$resModel = $this->findItem($id);
if (!$resModel) throw new ModelException('transaction not found');
if ($resModel->status != self::STATUS_PROCESSING) throw new ModelException('transaction status error');
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findItem($resModel->wallet_id);
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
if ($status == self::STATUS_SUCCESS) {
//扣减冻结金额
$res = $oCustomerWalletBalanceModel->subFrozenAmount($resModel->wallet_id, $resModel->amount);
if (!$res) throw new ModelException('withdraw fail');
//更新账变状态
$updateItem = [
'id' => $id,
'status' => self::STATUS_SUCCESS,
'updated_at' => Times::getNowDateTime(),
'before_total_amount' => $resWalletBalanceModel->total_amount,
'after_total_amount' => Math::bcAdd($resWalletBalanceModel->total_amount, $resModel->amount)
];
if (!empty($remark)) $updateItem['remark'] = $remark;
$res = $this->updateItem($updateItem);
if (!$res) throw new ModelException('updateItem fail');
} else { //失败
//解冻
$res = $oCustomerWalletBalanceModel->unFrozenAmount($resModel->wallet_id, $resModel->amount);
if (!$res) throw new ModelException('withdraw fail');
//更新账变状态
$updateItem = [
'id' => $id,
'status' => self::STATUS_FAIL,
'updated_at' => Times::getNowDateTime(),
];
if (!empty($remark)) $updateItem['remark'] = $remark;
$res = $this->updateItem($updateItem);
if (!$res) throw new ModelException('updateItem fail');
//返还手续费
$res = $this->typeTransactionFeeAdd($resModel->uid, $resModel->currency_code, $resModel->fee_amount, $resModel->id . ' withdraw fail return fee');
if (!$res) throw new ModelException('withdraw fail return fee fail');
}
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args());
return false;
}
}
//充值
function typeRecharge($uid, $currency_code, $amount): bool
{
$bean = new CustomerWalletBalanceTransactionBean();
$bean->setUid($uid);
$bean->setCurrencyCode($currency_code);
$bean->setAmount(abs($amount)); //正数
$bean->setUid($uid);
$bean->setType(self::TYPE_RECHARGE_ADD);
$bean->setStatus(self::STATUS_SUCCESS);
try {
DB::beginTransaction();
//查询用户余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
//加悲观锁
$resWalletBalanceModel = $oCustomerWalletBalanceModel->findByWhereWithLock($resWalletBalanceModel->id);
$bean->setWalletId($resWalletBalanceModel->id);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
$bean->setAfterTotalAmount(Math::bcAdd($resWalletBalanceModel->total_amount, $bean->getAmount()));
//新增账变
$res = $this->addTransaction($bean);
if (!$res) throw new ModelException('addTransaction fail');
//变更余额
$oCustomerWalletBalanceModel = new CustomerWalletBalanceModel();
$res = $oCustomerWalletBalanceModel->addAvailableAmount($bean->getWalletId(), $bean->getAmount());
if (!$res) throw new ModelException('recharge fail');
DB::commit();
Logs::SuccLog(__FUNCTION__, func_get_args());
return true;
} catch (\Exception $e) {
DB::rollBack();
Logs::ErrLog(__FUNCTION__.'typeRecharge error rollBack', $e);
return false;
}
}
function addTransaction(CustomerWalletBalanceTransactionBean &$bean): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool
{
if (!$bean->getWalletId()) throw new ModelException('wallet_id is required');
if (!$bean->getType()) throw new ModelException('type is required');
if (!$bean->getStatus()) $bean->setStatus(self::STATUS_WAIT);
if (empty($bean->getUid()) || empty($bean->getBeforeTotalAmount())) {
$oWalletBalanceModel = new CustomerWalletBalanceModel();
$resWalletBalanceModel = $oWalletBalanceModel->findItem($bean->getWalletId());
if (!$resWalletBalanceModel) throw new ModelException('wallet not found');
$bean->setUid($resWalletBalanceModel->uid);
$bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount);
}
$bean->setCreatedAt(Times::getNowDateTime());
$bean->setUpdatedAt(Times::getNowDateTime());
return $this->addItem($bean->toArrayNotNull());
}
}