文件
Henglianshutong/addons/shopro/service/partner/DailySettleService.php

654 行
29 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
namespace addons\shopro\service\partner;
use think\Db;
use addons\shopro\service\Wallet;
use app\admin\model\shopro\partner\DailyReport;
use app\admin\model\shopro\partner\Reward as RewardModel;
use app\admin\model\shopro\commission\Agent as AgentModel;
/**
* 日结:dmepa / 馆县均分 / 券释放
*/
class DailySettleService
{
public function run($date = null, $rerun = false)
{
$settleDate = $date ?: date('Y-m-d', strtotime('-1 day'));
$lockDir = RUNTIME_PATH . 'lock';
if (!is_dir($lockDir)) {
@mkdir($lockDir, 0755, true);
}
$lockFile = $lockDir . '/partner_settle_' . date('Ymd', strtotime($settleDate)) . '.lock';
$fp = fopen($lockFile, 'c');
if (!$fp || !flock($fp, LOCK_EX | LOCK_NB)) {
throw new \Exception('日结正在执行,请稍后再试');
}
try {
$exist = DailyReport::where('settle_date', $settleDate)->where('status', 1)->find();
if ($exist && !$rerun) {
return $exist;
}
if ($rerun) {
$this->clearDaily($settleDate);
}
Db::transaction(function () use ($settleDate) {
$this->settle($settleDate);
});
return DailyReport::where('settle_date', $settleDate)->find();
} catch (\Exception $e) {
DailyReport::create([
'settle_date' => $settleDate,
'status' => 0,
'error_msg' => mb_substr($e->getMessage(), 0, 500),
'createtime' => time(),
'updatetime' => time(),
]);
throw $e;
} finally {
flock($fp, LOCK_UN);
fclose($fp);
}
}
/**
* 临时分钟级调度:执行未结算订单的dmepa分红,并释放一期兑换券
*/
public function runMinute()
{
$lockDir = RUNTIME_PATH . 'lock';
if (!is_dir($lockDir)) {
@mkdir($lockDir, 0755, true);
}
$lockFile = $lockDir . '/partner_settle_minute.lock';
$fp = fopen($lockFile, 'c');
if (!$fp || !flock($fp, LOCK_EX | LOCK_NB)) {
return ['status' => 'skipped', 'message' => '上一次分钟任务仍在执行中'];
}
try {
$today = date('Y-m-d');
$rateService = new RateService();
$rewardService = new PartnerRewardService();
$activeService = new ActiveService();
// 1. 兑换券 1 分钟释放一次
$voucherTotal = (new VoucherService())->releaseMinute();
// 2. dmepa 1 分钟结算一次(提取已支付但尚未结算dmepa的合格订单)
$allQualifiedOrders = $rateService->qualifiedOrderQuery()->field('o.id,o.pay_fee,o.user_id,o.ext,o.paid_time')->select();
$unsettledOrders = [];
$madowGmv = 0;
foreach ($allQualifiedOrders as $o) {
$ext = $o['ext'] ?? [];
if (is_string($ext)) {
$ext = json_decode($ext, true) ?: [];
}
if (empty($ext['madow_settled'])) {
$unsettledOrders[] = $o;
$qFee = $rewardService->getQualifiedPayFee($o);
$madowGmv = bcadd((string) $madowGmv, (string) $qFee, 2);
}
}
$madowRes = ['pool' => 0, 'count' => 0, 'each' => 0];
$settledOrderIds = [];
if ((float) $madowGmv > 0 && !empty($unsettledOrders)) {
$settledOrderIds = array_column($unsettledOrders, 'id');
$windowStart = time() - (PartnerConfig::activeDays() - 1) * 86400;
$tasterIds = $activeService->activeUserIds($windowStart, time());
$madowRes = (new MadowService())->shareMinute($madowGmv, $tasterIds, $settledOrderIds);
// 标记订单已结算dmepa
foreach ($unsettledOrders as $o) {
$freshExt = \think\Db::name('shopro_order')->where('id', $o['id'])->value('ext');
$ext = is_array($freshExt) ? $freshExt : (json_decode($freshExt ?? '', true) ?: []);
$ext['madow_settled'] = 1;
$ext['madow_settle_time'] = time();
\think\Db::name('shopro_order')->where('id', $o['id'])->update([
'ext' => json_encode($ext, JSON_UNESCAPED_UNICODE),
]);
}
// 清除汇率缓存,联动大盘最新动态汇率
RateService::clearCache();
}
// 3. 酒道馆 1 分钟均分结算(提取未结算酒道馆的合格订单)
$unsettledVenueOrders = [];
$venuePool = 0;
foreach ($allQualifiedOrders as $o) {
$freshExt = \think\Db::name('shopro_order')->where('id', $o['id'])->value('ext');
$ext = is_array($freshExt) ? $freshExt : (json_decode($freshExt ?? '', true) ?: []);
if (empty($ext['venue_settled'])) {
$unsettledVenueOrders[] = $o;
$rules = PartnerConfig::getOrderEffectiveRules($o);
$vShare = isset($rules['venue_share']) && is_numeric($rules['venue_share'])
? (float) $rules['venue_share']
: (float) PartnerConfig::get('partner_venue_share_per_order', 100);
$venuePool = bcadd((string) $venuePool, (string) $vShare, 2);
}
}
$venueRes = ['pool' => 0, 'count' => 0, 'each' => '0.00'];
$settledVenueOrderIds = [];
if ((float) $venuePool > 0 && !empty($unsettledVenueOrders)) {
$settledVenueOrderIds = array_column($unsettledVenueOrders, 'id');
$windowStart = time() - (PartnerConfig::activeDays() - 1) * 86400;
$venueIds = $activeService->activeUserIds($windowStart, time(), ['is_venue' => 1]);
$venueRes = $this->cashShareMinute($venueIds, $venuePool, 'venue_share', 'venue', '酒道馆', $settledVenueOrderIds);
foreach ($unsettledVenueOrders as $o) {
$freshExt = \think\Db::name('shopro_order')->where('id', $o['id'])->value('ext');
$ext = is_array($freshExt) ? $freshExt : (json_decode($freshExt ?? '', true) ?: []);
$ext['venue_settled'] = 1;
$ext['venue_settle_time'] = time();
\think\Db::name('shopro_order')->where('id', $o['id'])->update([
'ext' => json_encode($ext, JSON_UNESCAPED_UNICODE),
]);
}
}
// 4. 区县代理 1 分钟均分结算(提取未结算区县的合格订单)
$unsettledCountyOrders = [];
$countyPool = 0;
foreach ($allQualifiedOrders as $o) {
$freshExt = \think\Db::name('shopro_order')->where('id', $o['id'])->value('ext');
$ext = is_array($freshExt) ? $freshExt : (json_decode($freshExt ?? '', true) ?: []);
if (empty($ext['county_settled'])) {
$unsettledCountyOrders[] = $o;
$rules = PartnerConfig::getOrderEffectiveRules($o);
$cShare = isset($rules['county_share']) && is_numeric($rules['county_share'])
? (float) $rules['county_share']
: (float) PartnerConfig::get('partner_county_share_per_order', 50);
$countyPool = bcadd((string) $countyPool, (string) $cShare, 2);
}
}
$countyRes = ['pool' => 0, 'count' => 0, 'each' => '0.00'];
$settledCountyOrderIds = [];
if ((float) $countyPool > 0 && !empty($unsettledCountyOrders)) {
$settledCountyOrderIds = array_column($unsettledCountyOrders, 'id');
$windowStart = time() - (PartnerConfig::activeDays() - 1) * 86400;
$countyIds = $activeService->activeUserIds($windowStart, time(), ['is_county' => 1]);
$countyRes = $this->cashShareMinute($countyIds, $countyPool, 'county_share', 'county', '区县', $settledCountyOrderIds);
foreach ($unsettledCountyOrders as $o) {
$freshExt = \think\Db::name('shopro_order')->where('id', $o['id'])->value('ext');
$ext = is_array($freshExt) ? $freshExt : (json_decode($freshExt ?? '', true) ?: []);
$ext['county_settled'] = 1;
$ext['county_settle_time'] = time();
\think\Db::name('shopro_order')->where('id', $o['id'])->update([
'ext' => json_encode($ext, JSON_UNESCAPED_UNICODE),
]);
}
}
// 5. 统计今日最新大盘并同步/创建今日 DailyReport
$todayStart = strtotime($today . ' 00:00:00');
$todayEnd = strtotime($today . ' 23:59:59');
$todayGmv = $rateService->qualifiedGmv($todayStart, $todayEnd);
$todayOrderCount = $rateService->qualifiedOrderQuery($todayStart, $todayEnd)->count();
$orderCountN = $rateService->countN();
$currentRate = $rateService->calcRate($orderCountN);
// 当日累计发放兑换券总额
$todayVoucherReleased = (float) \think\Db::name('shopro_partner_reward')
->whereBetween('createtime', [$todayStart, $todayEnd])
->where('reward_type', 'voucher_release')
->where('status', 1)
->sum('amount');
// 当日累计发放dmepa总额
$todayMadowPool = (float) \think\Db::name('shopro_partner_reward')
->whereBetween('createtime', [$todayStart, $todayEnd])
->where('reward_type', 'madow_share')
->where('status', 1)
->sum('madow');
// 当日累计发放酒道馆均分总额(含直接分给酒道馆与尾差/进平台金额)
$todayVenuePool = (float) \think\Db::name('shopro_partner_reward')
->whereBetween('createtime', [$todayStart, $todayEnd])
->where('reward_type', 'venue_share')
->where('status', 1)
->sum('amount');
// 当日累计发放区县均分总额(含直接分给区县与尾差/进平台金额)
$todayCountyPool = (float) \think\Db::name('shopro_partner_reward')
->whereBetween('createtime', [$todayStart, $todayEnd])
->where('reward_type', 'county_share')
->where('status', 1)
->sum('amount');
$windowStart = time() - (PartnerConfig::activeDays() - 1) * 86400;
$venueUserCount = count($activeService->activeUserIds($windowStart, time(), ['is_venue' => 1]));
$countyUserCount = count($activeService->activeUserIds($windowStart, time(), ['is_county' => 1]));
$existingTodayReport = DailyReport::where('settle_date', $today)->find();
if ($existingTodayReport) {
$existingTodayReport->order_count = $todayOrderCount;
$existingTodayReport->order_count_n = $orderCountN;
$existingTodayReport->gmv = $todayGmv;
$existingTodayReport->rate = $currentRate;
$existingTodayReport->madow_pool = $todayMadowPool;
$existingTodayReport->venue_pool = $todayVenuePool;
$existingTodayReport->venue_user_count = $venueUserCount;
$existingTodayReport->county_pool = $todayCountyPool;
$existingTodayReport->county_user_count = $countyUserCount;
$existingTodayReport->voucher_release_total = $todayVoucherReleased;
$existingTodayReport->updatetime = time();
$existingTodayReport->save();
} else {
DailyReport::create([
'settle_date' => $today,
'order_count' => $todayOrderCount,
'order_count_n' => $orderCountN,
'gmv' => $todayGmv,
'rate' => $currentRate,
'madow_pool' => $todayMadowPool,
'share_user_count' => $madowRes['count'] ?? 0,
'venue_pool' => $todayVenuePool,
'venue_user_count' => $venueUserCount,
'county_pool' => $todayCountyPool,
'county_user_count' => $countyUserCount,
'voucher_release_total' => $todayVoucherReleased,
'status' => 1,
'error_msg' => '',
'createtime' => time(),
'updatetime' => time(),
]);
}
// 更新汇率日志
$rateService->snapshot($today, $todayGmv, [
'madow_pool' => $todayMadowPool,
'share_user_count' => $madowRes['count'] ?? 0,
'venue_pool' => $todayVenuePool,
'county_pool' => $todayCountyPool,
]);
return [
'status' => 'success',
'time' => date('Y-m-d H:i:s'),
'voucher_released' => $voucherTotal,
'madow_settled_gmv' => (float) $madowGmv,
'madow_pool' => $madowRes['pool'],
'madow_each' => $madowRes['each'],
'venue_pool' => $venueRes['pool'],
'venue_each' => $venueRes['each'],
'county_pool' => $countyRes['pool'],
'county_each' => $countyRes['each'],
'settled_orders' => array_values(array_unique(array_merge($settledOrderIds, $settledVenueOrderIds, $settledCountyOrderIds))),
];
} finally {
flock($fp, LOCK_UN);
fclose($fp);
}
}
protected function settle($settleDate)
{
$start = strtotime($settleDate . ' 00:00:00');
$end = strtotime($settleDate . ' 23:59:59');
$rateService = new RateService();
$active = new ActiveService();
$orders = $rateService->qualifiedOrderQuery($start, $end)->field('o.id,o.pay_fee')->select();
$orderCount = count($orders);
$gmv = $rateService->qualifiedGmv($start, $end);
$windowStart = strtotime($settleDate . ' 00:00:00') - (PartnerConfig::activeDays() - 1) * 86400;
$tasterIds = $active->activeUserIds($windowStart, $end);
$venueIds = $active->activeUserIds($windowStart, $end, ['is_venue' => 1]);
$countyIds = $active->activeUserIds($windowStart, $end, ['is_county' => 1]);
$madow = (new MadowService())->share($settleDate, $gmv, $tasterIds);
$venuePer = (float) PartnerConfig::get('partner_venue_share_per_order', 100);
$countyPer = (float) PartnerConfig::get('partner_county_share_per_order', 50);
$venuePool = round($orderCount * $venuePer, 2);
$countyPool = round($orderCount * $countyPer, 2);
$this->cashShare($settleDate, $venueIds, $venuePool, 'venue_share', 'venue', '酒道馆');
$this->cashShare($settleDate, $countyIds, $countyPool, 'county_share', 'county', '区县');
$voucherTotal = (new VoucherService())->releaseByDate($settleDate);
$rateLog = $rateService->snapshot($settleDate, $gmv, [
'madow_pool' => $madow['pool'],
'share_user_count' => $madow['count'],
'venue_pool' => $venuePool,
'county_pool' => $countyPool,
]);
DailyReport::create([
'settle_date' => $settleDate,
'order_count' => $orderCount,
'order_count_n' => $rateLog->order_count_n ?? $rateService->countN(),
'gmv' => $gmv,
'rate' => $rateLog->rate ?? 0,
'madow_pool' => $madow['pool'],
'share_user_count' => $madow['count'],
'venue_pool' => $venuePool,
'venue_user_count' => count($venueIds),
'county_pool' => $countyPool,
'county_user_count' => count($countyIds),
'voucher_release_total' => $voucherTotal,
'status' => 1,
'error_msg' => '',
'createtime' => time(),
'updatetime' => time(),
]);
}
protected function cashShare($settleDate, $userIds, $pool, $type, $role, $label)
{
$count = count($userIds);
$orderId = PartnerRewardService::dailyOrderId($settleDate);
if ($pool <= 0) {
return;
}
if ($count <= 0) {
PartnerRewardService::write([
'order_id' => $orderId,
'user_id' => 0,
'role' => 'system',
'reward_type' => $type,
'amount' => $pool,
'base_amount' => $pool,
'settle_date' => $settleDate,
'ext' => ['formula' => "{$label}分母为0,奖池 {$pool} 进平台"],
'status' => 1,
]);
return;
}
$each = function_exists('bcdiv') ? bcdiv((string) $pool, (string) $count, 2) : number_format($pool / $count, 2, '.', '');
$distributed = 0;
$walletType = PartnerConfig::rewardWalletType();
foreach ($userIds as $userId) {
PartnerRewardService::write([
'order_id' => $orderId,
'user_id' => $userId,
'role' => $role,
'reward_type' => $type,
'amount' => $each,
'base_amount' => $pool,
'settle_date' => $settleDate,
'ext' => [
'formula' => "{$label}奖池 {$pool} / {$count} = {$each}",
'share_user_count' => $count,
'wallet_type' => $walletType,
],
'status' => 1,
]);
if ((float) $each > 0) {
Wallet::change($userId, $walletType, $each, $type, [
'settle_date' => $settleDate,
]);
AgentModel::where('user_id', $userId)->setInc('total_income', $each);
}
$distributed = bcadd((string) $distributed, (string) $each, 2);
}
$tail = bcsub((string) $pool, (string) $distributed, 2);
if ((float) $tail > 0) {
PartnerRewardService::write([
'order_id' => $orderId,
'user_id' => 0,
'role' => 'system',
'reward_type' => $type,
'amount' => $tail,
'base_amount' => $pool,
'settle_date' => $settleDate,
'ext' => [
'formula' => "{$label}尾差 {$tail} 进平台",
'wallet_type' => 'system',
],
'status' => 1,
]);
}
}
/**
* 临时分钟级均分分润(酒道馆 / 区县代理)
*/
public function cashShareMinute($userIds, $pool, $type, $role, $label, $orderIds = [])
{
$count = count($userIds);
$pool = round((float) $pool, 2);
if ($pool <= 0) {
return ['pool' => 0, 'count' => $count, 'each' => '0.00'];
}
$minId = (int) \think\Db::name('shopro_partner_reward')->where('order_id', '<', 0)->min('order_id');
$virtualOrderId = min(-100000, $minId - 1);
if ($count <= 0) {
PartnerRewardService::write([
'order_id' => $virtualOrderId,
'buyer_id' => 0,
'user_id' => 0,
'role' => 'system',
'reward_type' => $type,
'amount' => $pool,
'base_amount' => $pool,
'settle_date' => null,
'ext' => [
'formula' => "{$label}分母为0,奖池 {$pool} 进平台",
'orders' => $orderIds,
'wallet_type' => 'system',
],
'status' => 1,
]);
return ['pool' => $pool, 'count' => 0, 'each' => '0.00'];
}
$each = function_exists('bcdiv') ? bcdiv((string) $pool, (string) $count, 2) : number_format($pool / $count, 2, '.', '');
$distributed = 0;
$walletType = PartnerConfig::rewardWalletType();
foreach ($userIds as $userId) {
PartnerRewardService::write([
'order_id' => $virtualOrderId,
'buyer_id' => 0,
'user_id' => $userId,
'role' => $role,
'reward_type' => $type,
'amount' => $each,
'base_amount' => $pool,
'settle_date' => null,
'ext' => [
'formula' => "{$label}奖池 {$pool} / {$count} = {$each}",
'share_user_count' => $count,
'pool' => $pool,
'orders' => $orderIds,
'wallet_type' => $walletType,
],
'status' => 1,
]);
if ((float) $each > 0) {
Wallet::change($userId, $walletType, $each, $type, [
'minute_settle' => 1,
'orders' => $orderIds,
]);
AgentModel::where('user_id', $userId)->setInc('total_income', $each);
}
$distributed = bcadd((string) $distributed, (string) $each, 2);
}
$tail = bcsub((string) $pool, (string) $distributed, 2);
if ((float) $tail > 0) {
PartnerRewardService::write([
'order_id' => $virtualOrderId,
'buyer_id' => 0,
'user_id' => 0,
'role' => 'system',
'reward_type' => $type,
'amount' => $tail,
'base_amount' => $pool,
'settle_date' => null,
'ext' => [
'formula' => "{$label}尾差 {$tail} 进平台",
'orders' => $orderIds,
'wallet_type' => 'system',
],
'status' => 1,
]);
}
return ['pool' => $pool, 'count' => $count, 'each' => $each];
}
public function clearDaily($settleDate)
{
(new VoucherService())->rollbackRelease($settleDate);
(new MadowService())->rollback($settleDate);
$cashRows = RewardModel::where('settle_date', $settleDate)
->whereIn('reward_type', ['venue_share', 'county_share'])
->where('status', 1)
->where('user_id', '>', 0)
->select();
foreach ($cashRows as $row) {
if ((float) $row->amount > 0) {
$walletLog = \app\admin\model\shopro\user\WalletLog::where('user_id', $row->user_id)
->where('ext', 'like', '%"settle_date":"' . $settleDate . '"%')
->where('event', $row->reward_type)
->order('id', 'desc')
->find();
$targetWallet = ($walletLog && $walletLog->type === 'commission') ? 'commission' : PartnerConfig::rewardWalletType();
Wallet::change($row->user_id, $targetWallet, -$row->amount, 'reward_back', [
'settle_date' => $settleDate,
'rerun' => 1,
], '日结重跑扣回');
AgentModel::where('user_id', $row->user_id)->setDec('total_income', $row->amount);
}
}
RewardModel::where('settle_date', $settleDate)
->whereIn('reward_type', PartnerConfig::dailyTypes())
->delete();
DailyReport::where('settle_date', $settleDate)->delete();
\app\admin\model\shopro\partner\RateLog::where('settle_date', $settleDate)->delete();
}
/**
* 日结试算(Dry Run,只读模拟计算)
* 纯计算昨日或指定日期的分润池、人均分配额、沉淀留存与综合现金拨比,不入账不写表
*/
public function preview($date = null)
{
$settleDate = $date ?: date('Y-m-d', strtotime('-1 day'));
$start = strtotime($settleDate . ' 00:00:00');
$end = strtotime($settleDate . ' 23:59:59');
$rateService = new RateService();
$active = new ActiveService();
$orders = $rateService->qualifiedOrderQuery($start, $end)->field('o.id,o.pay_fee')->select();
$orderCount = count($orders);
$gmv = $rateService->qualifiedGmv($start, $end);
$windowStart = strtotime($settleDate . ' 00:00:00') - (PartnerConfig::activeDays() - 1) * 86400;
$tasterIds = $active->activeUserIds($windowStart, $end);
$venueIds = $active->activeUserIds($windowStart, $end, ['is_venue' => 1]);
$countyIds = $active->activeUserIds($windowStart, $end, ['is_county' => 1]);
$tasterCount = count($tasterIds);
$venueCount = count($venueIds);
$countyCount = count($countyIds);
// 汇率预测
$orderCountN = $rateService->countN();
$rate = $rateService->calcRate($orderCountN);
// dmepa池 (1:1 GMV)
$madowPool = (float) $gmv;
$madowEach = $tasterCount > 0 ? (function_exists('bcdiv') ? bcdiv((string) $madowPool, (string) $tasterCount, 8) : number_format($madowPool / $tasterCount, 8, '.', '')) : '0.00000000';
// 酒道馆与区县均分池
$venuePer = (float) PartnerConfig::get('partner_venue_share_per_order', 100);
$countyPer = (float) PartnerConfig::get('partner_county_share_per_order', 50);
$venuePool = round($orderCount * $venuePer, 2);
$countyPool = round($orderCount * $countyPer, 2);
$venueEach = $venueCount > 0 ? round($venuePool / $venueCount, 2) : 0;
$countyEach = $countyCount > 0 ? round($countyPool / $countyCount, 2) : 0;
// 沉淀金额(若无人合格分母为0,则全部沉淀至平台)
$venueSaved = $venueCount <= 0 ? $venuePool : 0;
$countySaved = $countyCount <= 0 ? $countyPool : 0;
$totalSaved = bcadd((string) $venueSaved, (string) $countySaved, 2);
// 当日即时奖产生总额(推三返一、创客极差、平级、酒道馆/区县团队奖等)
$instantCash = (float) RewardModel::whereBetween('createtime', [$start, $end])
->whereIn('reward_type', PartnerConfig::instantTypes())
->where('status', 1)
->sum('amount');
// 当日预计现金支出 = 即时奖 + 酒道馆实际发放 + 区县实际发放
$venueActualOut = $venueCount > 0 ? $venuePool : 0;
$countyActualOut = $countyCount > 0 ? $countyPool : 0;
$estimatedDailyCash = bcadd((string) $venueActualOut, (string) $countyActualOut, 2);
$totalCashPayout = bcadd((string) $instantCash, (string) $estimatedDailyCash, 2);
// 综合现金拨比
$payoutRatio = (float) $gmv > 0 ? round(($totalCashPayout / $gmv) * 100, 2) : 0;
// 兑换券释放预计
$voucherReleaseEstimate = (float) \app\admin\model\shopro\partner\VoucherPlan::where('status', 1)
->where('released_days', '<', 365)
->sum('daily_amount');
// 是否已经执行过正式日结
$existingReport = DailyReport::where('settle_date', $settleDate)->find();
return [
'settle_date' => $settleDate,
'is_settled' => ($existingReport && $existingReport->status == 1),
'existing_report' => $existingReport,
'order_count' => $orderCount,
'order_count_n' => $orderCountN,
'gmv' => number_format($gmv, 2, '.', ''),
'rate' => IdentityService::formatRate($rate),
'madow' => [
'pool' => IdentityService::formatMadow($madowPool),
'user_count' => $tasterCount,
'each' => IdentityService::formatMadow($madowEach),
],
'venue' => [
'pool' => number_format($venuePool, 2, '.', ''),
'user_count' => $venueCount,
'each' => number_format($venueEach, 2, '.', ''),
'saved' => number_format($venueSaved, 2, '.', ''),
],
'county' => [
'pool' => number_format($countyPool, 2, '.', ''),
'user_count' => $countyCount,
'each' => number_format($countyEach, 2, '.', ''),
'saved' => number_format($countySaved, 2, '.', ''),
],
'voucher' => [
'release_estimate' => number_format($voucherReleaseEstimate, 2, '.', ''),
],
'financial' => [
'instant_cash' => number_format($instantCash, 2, '.', ''),
'daily_cash' => number_format($estimatedDailyCash, 2, '.', ''),
'total_cash' => number_format($totalCashPayout, 2, '.', ''),
'saved_cash' => number_format($totalSaved, 2, '.', ''),
'payout_ratio' => $payoutRatio . '%',
'payout_ratio_val' => $payoutRatio,
'is_alert' => $payoutRatio > 70,
],
];
}
}