123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- <?php
- namespace App\Services\Settlement;
- use App\Cache\FinanceCache;
- use App\Consts\BaseConst;
- use App\Consts\ErrorConst;
- use App\Consts\FinanceConsts;
- use App\Dao\Bank\BankDao;
- use App\Dao\Bank\WithdrawDao;
- use App\Dao\Settlement\BillDao;
- use App\Dao\Settlement\FinancialDao;
- use App\Facade\Site;
- use App\Libs\Utils;
- use App\Exceptions\ApiException;
- use App\Models\Settlement\FinancialStats;
- use Illuminate\Support\Facades\DB;
- class SettlementService
- {
- private $billDao;
- private $bankDao;
- private $financialDao;
- private $withdrawDao;
- public function __construct(
- BillDao $billDao,
- BankDao $bankDao,
- FinancialDao $financialDao,
- WithdrawDao $withdrawDao
- )
- {
- $this->billDao = $billDao;
- $this->bankDao = $bankDao;
- $this->financialDao = $financialDao;
- $this->withdrawDao = $withdrawDao;
- }
- /**
- * 结算列表
- *
- * @param $params
- * @return mixed
- */
- public function bills($params)
- {
- // 站点信息
- $channelId = Site::getCurrentChannelId();
- $params['channel_id'] = $channelId;
- // 结算列表
- $bills = $this->billDao->getBills($params);
- // 导出逻辑
- $export = (int)getProp($params, 'export');
- if ($export) {
- $this->exportBills($bills);
- }
- return $bills;
- }
- /**
- * 结算单订单明细
- *
- * @param $date
- * @return mixed
- */
- public function billOrders($date)
- {
- // 站点信息
- $channelId = Site::getCurrentChannelId();
- // 查询订单
- return $this->billDao->billOrders($channelId, $date);
- }
- /**
- * 结算信息-汇总数据
- *
- * @return array
- */
- public function billsStat(): array
- {
- // 站点id
- $channelId = Site::getCurrentChannelId();
- // 站点提现信息
- $financialStat = $this->financialDao->getChannelFinancialStat($channelId);
- $enableWithdrawalAmount = getProp($financialStat, 'enable_withdrawal_amount_7day', 0.00); // t-7可提现余额
- $accumulativeWithdrawalAmount = getProp($financialStat, 'accumulative_withdrawal_amount', 0.00);
- $latestWithdrawalAmount = getProp($financialStat, 'latest_withdrawal_amount', 0.00);
- $withdrawPendingAmount = getProp($financialStat, 'withdraw_pending_amount', 0.00);
- $latestWithdrawalTime = getProp($financialStat, 'latest_withdraw_time');
- // 充值总额
- // $totalRechargeAmount = $this->orderDao->getChannelRechargeAmount($channelId);
- // 充值总额(默认7日前数据)
- [$startDate, $endDate] = ['', date('Y-m-d', strtotime('-' . BaseConst::DATE_RANGE_DAYS . ' days'))];
- $totalRechargeAmountBefore7Days = $this->billDao->getBillsRechargeAmount($channelId, $startDate, $endDate);
- // 月充值总额(前7日数据不显示)
- $monthRechargeAmountWithout7Days = 0.00;
- $startDate = date('Y-m-01');
- if (date('j') > BaseConst::DATE_RANGE_DAYS) {
- $monthRechargeAmountWithout7Days = $this->billDao->getBillsRechargeAmount($channelId, $startDate, $endDate);
- }
- // 最近一笔提现中
- $latestWithdrawLog = $this->withdrawDao->getLatestWithdrawingCash($channelId);
- $withdrawingAmount = getProp($latestWithdrawLog, 'amount', 0.00);
- // 结算总额
- // $totalSettlementAmount = $accumulativeWithdrawalAmount + $enableWithdrawalAmount + $withdrawPendingAmount;
- // 站点统计
- return [
- 'total_recharge_amount' => 0.00, // floor($totalRechargeAmount * 100) / 100, // 充值总额
- 'total_recharge_amount_without_today' => 0.00, // 充值总额(不含当日)
- 'month_recharge_amount_without_today' => 0.00, // 月充值总额(不含当日)
- 'total_recharge_amount_without_7day' => floor($totalRechargeAmountBefore7Days * 100) / 100, // 充值总额(不含当日)
- 'month_recharge_amount_without_7day' => floor($monthRechargeAmountWithout7Days * 100) / 100, // 月充值总额(不含当日)
- 'enable_withdrawal_amount' => floor($enableWithdrawalAmount * 100) / 100, // 可提现总余额
- 'total_withdraw_amount' => floor($accumulativeWithdrawalAmount * 100) / 100, // 累计提现金额
- 'total_settlement_amount' => 0.00, // floor($totalSettlementAmount * 100) / 100, // 结算总额
- 'latest_withdrawal_amount' => floor($latestWithdrawalAmount * 100) / 100, // 最近一笔提现金额
- 'latest_withdraw_time' => $latestWithdrawalTime ?: '', // 最近一笔提现时间
- 'withdrawing_amount' => floor($withdrawingAmount * 100) / 100, // 提现中金额
- ];
- }
- /**
- * 提现列表
- *
- * @param $params
- * @return mixed
- */
- public function withdrawCashes($params)
- {
- // 站点id
- $channelId = Site::getCurrentChannelId();
- $params['channel_id'] = $channelId;
- // 获取提现记录
- return $this->withdrawDao->getWithdrawCashes($params);
- }
- /**
- * 提现
- *
- * @param $params
- * @return array
- * @throws ApiException
- */
- public function applyWithDraw($params): array
- {
- dLog('withdraw')->info('applyWithDraw-1', $params);
- // 相关参数
- $channelId = Site::getCurrentChannelId();
- $channelUserId = Site::getUid();
- $amount = (float)getProp($params, 'amount');
- $cardId = (int)getProp($params, 'card_id');
- $isCompany = (int)getProp($params, 'is_company');
- // 金额不小于1
- if (!is_numeric($amount) || $amount < 1 || $cardId < 1) {
- Utils::throwError(ErrorConst::PARAM_ERROR_CODE);
- }
- // 单笔提现下限
- if ($amount < FinanceConsts::WITH_DRAW_PRIVATE_MIN) {
- Utils::throwError(ErrorConst::WITHDRAW_CASH_AMOUNT);
- }
- // 单笔提现上限
- if ($amount >= FinanceConsts::WITH_DRAW_PRIVATE_MAX) {
- Utils::throwError(ErrorConst::WITHDRAW_CASH_AMOUNT_MORE);
- }
- // 核对银行卡信息
- $bankAccount = $this->bankDao->getValidCashAccountById($cardId);
- if (empty($bankAccount)) {
- Utils::throwError(ErrorConst::WITHDRAW_CASH_AMOUNT_ACCOUNT);
- }
- if ($bankAccount['is_company'] != $isCompany) {
- Utils::throwError(ErrorConst::WITHDRAW_CASH_AMOUNT_NOT_MATCH);
- }
- if ((int)$bankAccount['channel_user_id'] != $channelUserId) {
- Utils::throwError(ErrorConst::PRIVATE_ACCOUNT_NO_ACCESS);
- }
- dLog('withdraw')->info('applyWithDraw-2', compact('bankAccount'));
- // 判断当前渠道今日是否已有提现
- $isWithDrawn = $this->checkChannelIsWithDrawByChannelId($channelId);
- if ($isWithDrawn) {
- Utils::throwError(ErrorConst::WITHDRAW_CASH_TODAY_USE);
- }
- dLog('withdraw')->info('applyWithDraw-3', compact('isWithDrawn'));
- // 判断账户可提现余额是否满足
- $financialStat = $this->financialDao->getChannelFinancialStat($channelId);
- $enableWithDrawAmount = getProp($financialStat, 'enable_withdrawal_amount_7day'); // t-7可提现余额
- dLog('withdraw')->info('applyWithDraw-4', compact('financialStat', 'enableWithDrawAmount'));
- // 余额判断(-1 小于, 0 等于, 1 大于, 第3个参数必须带上)
- if (bccomp($amount, $enableWithDrawAmount, 2) >= 1) {
- Utils::throwError(ErrorConst::WITHDRAW_NOT_ENOUGH);
- }
- // 执行提现
- $result = $this->runWithDraw($channelId, $amount, $bankAccount, $financialStat);
- if (!$result) {
- Utils::throwError(ErrorConst::WITHDRAW_CASHES_FAILED);
- }
- return [
- 'enable_amount' => $enableWithDrawAmount - $amount,
- 'withdraw_pending_amount' => $amount
- ];
- }
- /**
- * 执行提现
- *
- * @param $channelId
- * @param $amount
- * @param $bankAccount
- * @param FinancialStats $financialStat
- * @return bool
- */
- private function runWithDraw($channelId, $amount, $bankAccount, FinancialStats $financialStat): bool
- {
- try {
- DB::beginTransaction();
- // 更新渠道可提现金额
- $financialStat->latest_withdrawal_amount = $amount; //最近提现金额
- $financialStat->enable_withdrawal_amount -= $amount; //修改可提现金额
- $financialStat->enable_withdrawal_amount_7day -= $amount; //修改可提现金额
- $financialStat->withdraw_pending_amount += $amount; //修改提现中金额
- $financialStat->latest_withdraw_time = date('Y-m-d H:i:s'); //修改提现时间
- $financialStat->save();
- // 创建提现单
- $this->withdrawDao->addWithDrawCashes([
- 'distribution_channel_id' => $channelId,
- 'distribution_channel_name' => Site::getCurrentChannelName(),
- 'tallage' => 0,
- 'amount' => $amount,
- 'status' => FinanceConsts::CHECK_PENDING,
- 'is_company' => (int)getProp($bankAccount, 'is_company'),
- 'account_bank' => getProp($bankAccount, 'account_bank'),
- 'bank_account' => getProp($bankAccount, 'card_number'),
- 'account_name' => getProp($bankAccount, 'account_name'),
- 'pay_merchant_company_id' => 1, // 目前只有一个公司主体
- 'bank' => getProp($bankAccount, 'bank'),
- ]);
- DB::commit();
- // 添加渠道到今日提现队列中
- FinanceCache::sAddChannelIdToWithDraw($channelId, date('Ymd'));
- return true;
- } catch (\Exception $e) {
- dLog('withdraw')->info('runWithDraw-exception', [$e->getMessage()]);
- $msg = sprintf('异常-站点 %s 提现 %s 元失败', $channelId, $amount);
- sendNotice($msg);
- DB::rollBack();
- return false;
- }
- }
- /**
- * 校验渠道当日是否已有提现
- *
- * @param $channelId
- * @return bool
- */
- private function checkChannelIsWithDrawByChannelId($channelId): bool
- {
- // 缓存层判断
- $ymd = date('Ymd');
- if (FinanceCache::checkChannelIdIsInWithDraw($channelId, $ymd)) {
- return true;
- }
- // 数据库层判断
- [$startTime, $endTime] = [date('Y-m-d'), date('Y-m-d') . ' 23:59:59'];
- $checkRes = $this->withdrawDao->checkChannelIdIsInWithDraw($channelId, $startTime, $endTime);
- if (!$checkRes) {
- return false;
- }
- // 更新缓存
- FinanceCache::sAddChannelIdToWithDraw($channelId, $ymd);
- return true;
- }
- /**
- * 结算导出
- *
- * @param $bills
- * @return void
- */
- private function exportBills($bills)
- {
- // 设置超时时间
- set_time_limit(0);
- // 组装下载数据
- $data = [];
- if ($bills->count()) {
- foreach ($bills as $bill) {
- $data[] = [
- getProp($bill, 'date'),
- getProp($bill, 'recharge_amount'),
- getProp($bill, 'rate') * 100 . '%',
- getProp($bill, 'service_amount'),
- getProp($bill, 'settlement_price'),
- ];
- }
- }
- $title = ['结算日期', '充值金额', '佣金比例', '支付通道费', '结算后金额'];
- exportExcel($data, $title, '结算信息-' . date("YmdHis"));
- exit();
- }
- }
|