feat(partner): 调整酒道馆与区县代理日结均分池为1分钟增量结算
这个提交包含在:
@@ -108,10 +108,8 @@ class DailySettleService
|
||||
|
||||
// 标记订单已结算马豆
|
||||
foreach ($unsettledOrders as $o) {
|
||||
$ext = $o['ext'] ?? [];
|
||||
if (is_string($ext)) {
|
||||
$ext = json_decode($ext, true) ?: [];
|
||||
}
|
||||
$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([
|
||||
@@ -123,7 +121,79 @@ class DailySettleService
|
||||
RateService::clearCache();
|
||||
}
|
||||
|
||||
// 3. 统计今日最新大盘并同步/创建今日 DailyReport
|
||||
// 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);
|
||||
@@ -145,6 +215,24 @@ class DailySettleService
|
||||
->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;
|
||||
@@ -152,6 +240,10 @@ class DailySettleService
|
||||
$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();
|
||||
@@ -164,10 +256,10 @@ class DailySettleService
|
||||
'rate' => $currentRate,
|
||||
'madow_pool' => $todayMadowPool,
|
||||
'share_user_count' => $madowRes['count'] ?? 0,
|
||||
'venue_pool' => 0,
|
||||
'venue_user_count' => 0,
|
||||
'county_pool' => 0,
|
||||
'county_user_count' => 0,
|
||||
'venue_pool' => $todayVenuePool,
|
||||
'venue_user_count' => $venueUserCount,
|
||||
'county_pool' => $todayCountyPool,
|
||||
'county_user_count' => $countyUserCount,
|
||||
'voucher_release_total' => $todayVoucherReleased,
|
||||
'status' => 1,
|
||||
'error_msg' => '',
|
||||
@@ -180,6 +272,8 @@ class DailySettleService
|
||||
$rateService->snapshot($today, $todayGmv, [
|
||||
'madow_pool' => $todayMadowPool,
|
||||
'share_user_count' => $madowRes['count'] ?? 0,
|
||||
'venue_pool' => $todayVenuePool,
|
||||
'county_pool' => $todayCountyPool,
|
||||
]);
|
||||
|
||||
return [
|
||||
@@ -189,7 +283,11 @@ class DailySettleService
|
||||
'madow_settled_gmv' => (float) $madowGmv,
|
||||
'madow_pool' => $madowRes['pool'],
|
||||
'madow_each' => $madowRes['each'],
|
||||
'settled_orders' => $settledOrderIds,
|
||||
'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);
|
||||
@@ -288,7 +386,8 @@ class DailySettleService
|
||||
'status' => 1,
|
||||
]);
|
||||
if ((float) $each > 0) {
|
||||
Wallet::change($userId, 'commission', $each, $type, [
|
||||
$walletType = PartnerConfig::rewardWalletType();
|
||||
Wallet::change($userId, $walletType, $each, $type, [
|
||||
'settle_date' => $settleDate,
|
||||
]);
|
||||
AgentModel::where('user_id', $userId)->setInc('total_income', $each);
|
||||
@@ -311,6 +410,82 @@ class DailySettleService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 临时分钟级均分分润(酒道馆 / 区县代理)
|
||||
*/
|
||||
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],
|
||||
'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;
|
||||
|
||||
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],
|
||||
'status' => 1,
|
||||
]);
|
||||
if ((float) $each > 0) {
|
||||
$walletType = PartnerConfig::rewardWalletType();
|
||||
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],
|
||||
'status' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
return ['pool' => $pool, 'count' => $count, 'each' => $each];
|
||||
}
|
||||
|
||||
public function clearDaily($settleDate)
|
||||
{
|
||||
(new VoucherService())->rollbackRelease($settleDate);
|
||||
@@ -323,7 +498,13 @@ class DailySettleService
|
||||
->select();
|
||||
foreach ($cashRows as $row) {
|
||||
if ((float) $row->amount > 0) {
|
||||
Wallet::change($row->user_id, 'commission', -$row->amount, 'reward_back', [
|
||||
$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,
|
||||
], '日结重跑扣回');
|
||||
|
||||
@@ -28,6 +28,12 @@ class PartnerConfig
|
||||
return (bool) self::get('partner_mode', 0);
|
||||
}
|
||||
|
||||
public static function rewardWalletType()
|
||||
{
|
||||
$type = (string) self::get('partner_reward_wallet', 'money');
|
||||
return in_array($type, ['money', 'commission']) ? $type : 'money';
|
||||
}
|
||||
|
||||
public static function isEnabled()
|
||||
{
|
||||
$enable = self::get('partner_enable', 1);
|
||||
|
||||
@@ -78,7 +78,12 @@ class PartnerRewardService
|
||||
|
||||
foreach ($rewards as $reward) {
|
||||
if (in_array($reward->reward_type, PartnerConfig::instantTypes()) && (float) $reward->amount > 0 && $reward->user_id > 0) {
|
||||
Wallet::change($reward->user_id, 'commission', -$reward->amount, 'reward_back', [
|
||||
$walletLog = \app\admin\model\shopro\user\WalletLog::where('user_id', $reward->user_id)
|
||||
->where('ext', 'like', '%"partner_reward_id":' . intval($reward->id) . '%')
|
||||
->order('id', 'desc')
|
||||
->find();
|
||||
$targetWallet = ($walletLog && $walletLog->type === 'commission') ? 'commission' : PartnerConfig::rewardWalletType();
|
||||
Wallet::change($reward->user_id, $targetWallet, -$reward->amount, 'reward_back', [
|
||||
'partner_reward_id' => $reward->id,
|
||||
'order_id' => $orderId,
|
||||
], '收益中心奖励退回');
|
||||
@@ -200,15 +205,45 @@ class PartnerRewardService
|
||||
return $qualifiedPayFee > 0;
|
||||
}
|
||||
|
||||
public function touchSelfOrder($userId, $time = null)
|
||||
/**
|
||||
* 刷新有效订单时间(自购及直推订单双向保活)
|
||||
* 1. 买家本人(自购)
|
||||
* 2. 买家直属推荐人(直推,严格限制一级上级,二级及以上不触发)
|
||||
*/
|
||||
public function touchOrderTimes($buyerId, $time = null)
|
||||
{
|
||||
$timestamp = $time ?: time();
|
||||
if (!$buyerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 买家本人自购保活
|
||||
$this->updateAgentOrderTime($buyerId, $timestamp);
|
||||
|
||||
// 2. 直推一级上级保活(限定自购以及直推订单都算有效)
|
||||
$parentUserId = \think\Db::name('user')->where('id', $buyerId)->value('parent_user_id');
|
||||
if ($parentUserId && intval($parentUserId) !== intval($buyerId)) {
|
||||
$this->updateAgentOrderTime($parentUserId, $timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateAgentOrderTime($userId, $timestamp)
|
||||
{
|
||||
$agent = AgentModel::where('user_id', $userId)->find();
|
||||
if ($agent) {
|
||||
$agent->last_self_order_time = $time ?: time();
|
||||
$agent->save();
|
||||
$current = intval($agent->last_self_order_time ?? 0);
|
||||
if ($timestamp >= $current) {
|
||||
$agent->last_self_order_time = $timestamp;
|
||||
$agent->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function touchSelfOrder($userId, $time = null)
|
||||
{
|
||||
$this->updateAgentOrderTime($userId, $time ?: time());
|
||||
}
|
||||
|
||||
public static function dailyOrderId($settleDate)
|
||||
{
|
||||
return -intval(date('Ymd', strtotime($settleDate)));
|
||||
@@ -287,7 +322,8 @@ class PartnerRewardService
|
||||
'status' => 1,
|
||||
]);
|
||||
if ($row && self::$lastWriteCreated && (float) $amount > 0 && $userId > 0 && $row->status == 1 && in_array($type, PartnerConfig::instantTypes())) {
|
||||
Wallet::change($userId, 'commission', $amount, $type, [
|
||||
$walletType = PartnerConfig::rewardWalletType();
|
||||
Wallet::change($userId, $walletType, $amount, $type, [
|
||||
'partner_reward_id' => $row->id,
|
||||
'order_id' => $orderId,
|
||||
]);
|
||||
|
||||
@@ -323,25 +323,57 @@ class Order extends Common
|
||||
}
|
||||
|
||||
if ($settleDate) {
|
||||
$dayStart = strtotime($settleDate . ' 00:00:00');
|
||||
$dayEnd = strtotime($settleDate . ' 23:59:59');
|
||||
|
||||
foreach ($shareTypes as $type) {
|
||||
$shareRows = \app\admin\model\shopro\partner\Reward::where('settle_date', $settleDate)
|
||||
$shareRows = \app\admin\model\shopro\partner\Reward::where(function ($q) use ($settleDate, $dayStart, $dayEnd) {
|
||||
$q->where('settle_date', $settleDate)
|
||||
->whereOr(function ($q2) use ($dayStart, $dayEnd) {
|
||||
$q2->whereNull('settle_date')->whereBetween('createtime', [$dayStart, $dayEnd]);
|
||||
});
|
||||
})
|
||||
->where('reward_type', $type)
|
||||
->where('status', 1)
|
||||
->where('user_id', '>', 0)
|
||||
->select();
|
||||
$userCount = count($shareRows);
|
||||
|
||||
$distinctUsers = [];
|
||||
$totalAmount = 0;
|
||||
$totalMadow = 0;
|
||||
foreach ($shareRows as $sr) {
|
||||
$totalAmount = round($totalAmount + (float) ($sr->amount ?? 0), 2);
|
||||
$totalMadow = function_exists('bcadd')
|
||||
? (float) bcadd((string) $totalMadow, (string) ($sr->madow ?? 0), 8)
|
||||
: ($totalMadow + (float) ($sr->madow ?? 0));
|
||||
$distinctUsers[intval($sr->user_id)] = true;
|
||||
}
|
||||
$userCount = count($distinctUsers);
|
||||
|
||||
if ($userCount <= 0) {
|
||||
// 分母为 0 进平台的记录
|
||||
$platform = \app\admin\model\shopro\partner\Reward::where('settle_date', $settleDate)
|
||||
$platRows = \app\admin\model\shopro\partner\Reward::where(function ($q) use ($settleDate, $dayStart, $dayEnd) {
|
||||
$q->where('settle_date', $settleDate)
|
||||
->whereOr(function ($q2) use ($dayStart, $dayEnd) {
|
||||
$q2->whereNull('settle_date')->whereBetween('createtime', [$dayStart, $dayEnd]);
|
||||
});
|
||||
})
|
||||
->where('reward_type', $type)
|
||||
->where('status', 1)
|
||||
->where('user_id', 0)
|
||||
->find();
|
||||
if (!$platform) {
|
||||
->select();
|
||||
if (empty($platRows) || count($platRows) <= 0) {
|
||||
continue;
|
||||
}
|
||||
$platAmount = (float) ($platform->amount ?? 0);
|
||||
$platMadow = (float) ($platform->madow ?? 0);
|
||||
$platAmount = 0;
|
||||
$platMadow = 0;
|
||||
foreach ($platRows as $pr) {
|
||||
$platAmount = round($platAmount + (float) ($pr->amount ?? 0), 2);
|
||||
$platMadow = function_exists('bcadd')
|
||||
? (float) bcadd((string) $platMadow, (string) ($pr->madow ?? 0), 8)
|
||||
: ($platMadow + (float) ($pr->madow ?? 0));
|
||||
}
|
||||
$platform = $platRows[0];
|
||||
$amountText = $type === 'madow_share'
|
||||
? \addons\shopro\service\partner\IdentityService::formatMadow($platMadow) . ' 马豆'
|
||||
: '¥' . number_format($platAmount, 2, '.', '');
|
||||
@@ -367,26 +399,15 @@ class Order extends Common
|
||||
'unit' => $type === 'madow_share' ? '马豆' : '元',
|
||||
'formula' => (string) ($platform->formula ?? ''),
|
||||
'skip_reason_text' => '',
|
||||
'tip' => '付款日日结均分:当日无人参与,奖池进平台',
|
||||
'tip' => '当日无人参与,奖池进平台',
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
$totalAmount = 0;
|
||||
$totalMadow = 0;
|
||||
foreach ($shareRows as $sr) {
|
||||
$totalAmount = round($totalAmount + (float) ($sr->amount ?? 0), 2);
|
||||
$totalMadow = function_exists('bcadd')
|
||||
? (float) bcadd((string) $totalMadow, (string) ($sr->madow ?? 0), 8)
|
||||
: ($totalMadow + (float) ($sr->madow ?? 0));
|
||||
}
|
||||
$first = $shareRows[0];
|
||||
$eachAmount = number_format((float) ($first->amount ?? 0), 2, '.', '');
|
||||
$eachMadow = \addons\shopro\service\partner\IdentityService::formatMadow($first->madow ?? 0);
|
||||
$ext = is_array($first->ext) ? $first->ext : [];
|
||||
if (!empty($ext['share_user_count'])) {
|
||||
$userCount = intval($ext['share_user_count']);
|
||||
}
|
||||
$eachAmount = function_exists('bcdiv') ? bcdiv((string) $totalAmount, (string) $userCount, 2) : number_format($totalAmount / $userCount, 2, '.', '');
|
||||
$eachMadowVal = function_exists('bcdiv') ? bcdiv((string) $totalMadow, (string) $userCount, 8) : ($totalMadow / $userCount);
|
||||
$eachMadow = \addons\shopro\service\partner\IdentityService::formatMadow($eachMadowVal);
|
||||
|
||||
$items[] = [
|
||||
'display' => 'share',
|
||||
@@ -409,7 +430,7 @@ class Order extends Common
|
||||
'unit' => $type === 'madow_share' ? '马豆' : '元',
|
||||
'formula' => (string) ($first->formula ?? ''),
|
||||
'skip_reason_text' => '',
|
||||
'tip' => '付款日日结均分(不列出参与用户名单)',
|
||||
'tip' => '日结均分(不列出参与用户名单)',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,19 @@ class WalletLog extends Common
|
||||
'recharge_gift' => '线上充值-赠送余额',
|
||||
'activity_gift' => '活动-赠送余额',
|
||||
'order_refund' => '订单退款-退还余额',
|
||||
'transfer_by_commission' => '服务收益-转入到余额'
|
||||
'transfer_by_commission' => '服务收益-转入到余额',
|
||||
'reward_income' => '收益分成-入账',
|
||||
'reward_back' => '收益分成-退还',
|
||||
'push3' => '推荐开拓奖',
|
||||
'maker_diff' => '创客进阶奖',
|
||||
'maker_peer' => '创客协同奖',
|
||||
'maker_overtaken' => '创客卓越奖',
|
||||
'team_venue' => '酒道馆运营奖',
|
||||
'team_county' => '区县统筹奖',
|
||||
'venue_peer' => '酒道馆协同奖',
|
||||
'county_peer' => '区县协同奖',
|
||||
'venue_share' => '酒道馆加权奖励',
|
||||
'county_share' => '区县加权奖励'
|
||||
],
|
||||
'commission' => [
|
||||
'withdraw' => '提现',
|
||||
@@ -64,7 +76,19 @@ class WalletLog extends Common
|
||||
];
|
||||
|
||||
public function getEventMap() {
|
||||
return $this->eventMap;
|
||||
$map = $this->eventMap;
|
||||
if (class_exists('\\addons\\shopro\\service\\partner\\PartnerConfig')) {
|
||||
$partnerMap = \addons\shopro\service\partner\PartnerConfig::rewardTypeMap();
|
||||
foreach ($partnerMap as $k => $v) {
|
||||
if (!isset($map['money'][$k])) {
|
||||
$map['money'][$k] = $v;
|
||||
}
|
||||
if (!isset($map['commission'][$k])) {
|
||||
$map['commission'][$k] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $map;
|
||||
}
|
||||
|
||||
public function scopeMoney($query)
|
||||
@@ -84,6 +108,9 @@ class WalletLog extends Common
|
||||
|
||||
public function getEventTextAttr($value, $data)
|
||||
{
|
||||
return $this->eventMap[$data['type']][$data['event']] ?? '';
|
||||
$type = $data['type'] ?? '';
|
||||
$event = $data['event'] ?? '';
|
||||
$eventMap = $this->getEventMap();
|
||||
return $eventMap[$type][$event] ?? ($eventMap['commission'][$event] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
console.log('========================================================');
|
||||
console.log(' 全网奖池(酒道馆/区县代/马豆/兑换券)1分钟结算规范验证');
|
||||
console.log('========================================================\n');
|
||||
|
||||
let passCount = 0;
|
||||
function test(name, fn) {
|
||||
try {
|
||||
fn();
|
||||
console.log(` [PASS] ${name}`);
|
||||
passCount++;
|
||||
} catch (err) {
|
||||
console.error(` [FAIL] ${name}: ${err.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 1. DailySettleService.php 验证
|
||||
const dailySettlePath = path.resolve(__dirname, '../addons/shopro/service/partner/DailySettleService.php');
|
||||
assert(fs.existsSync(dailySettlePath), 'DailySettleService.php 文件存在');
|
||||
const settleContent = fs.readFileSync(dailySettlePath, 'utf-8');
|
||||
|
||||
test('DailySettleService 包含酒道馆与区县增量均分逻辑', () => {
|
||||
assert(settleContent.includes("empty($ext['venue_settled'])"), '必须检查 venue_settled 增量标记');
|
||||
assert(settleContent.includes("empty($ext['county_settled'])"), '必须检查 county_settled 增量标记');
|
||||
assert(settleContent.includes("cashShareMinute($venueIds, $venuePool, 'venue_share'"), '调用 cashShareMinute 结算酒道馆均分');
|
||||
assert(settleContent.includes("cashShareMinute($countyIds, $countyPool, 'county_share'"), '调用 cashShareMinute 结算区县代理均分');
|
||||
assert(settleContent.includes("$ext['venue_settled'] = 1"), '订单必须打上 venue_settled = 1 标记');
|
||||
assert(settleContent.includes("$ext['county_settled'] = 1"), '订单必须打上 county_settled = 1 标记');
|
||||
});
|
||||
|
||||
test('DailySettleService 包含 cashShareMinute 方法与资金安全防重', () => {
|
||||
assert(settleContent.includes('function cashShareMinute('), '必须定义 cashShareMinute 方法');
|
||||
assert(settleContent.includes('min(-100000, $minId - 1)'), '使用严格递减负数虚拟 order_id');
|
||||
assert(settleContent.includes("'settle_date' => null"), 'settle_date 必须设为 null 避免 uk_daily_user_type 唯一索引冲突');
|
||||
assert(settleContent.includes('Wallet::change('), '均分收益实时调用钱包入账');
|
||||
assert(settleContent.includes("setInc('total_income'"), '分润金额实时累加至合伙人累计收益');
|
||||
});
|
||||
|
||||
test('DailySettleService runMinute 同步更新 DailyReport 的均分大盘数据', () => {
|
||||
assert(settleContent.includes('$existingTodayReport->venue_pool = $todayVenuePool'), '报表更新酒道馆池累计');
|
||||
assert(settleContent.includes('$existingTodayReport->county_pool = $todayCountyPool'), '报表更新区县池累计');
|
||||
assert(settleContent.includes("'venue_pool' => $todayVenuePool"), '报表新建酒道馆池累计');
|
||||
assert(settleContent.includes("'county_pool' => $todayCountyPool"), '报表新建区县池累计');
|
||||
});
|
||||
|
||||
// 2. Order.php 订单详情分成展示兼容验证
|
||||
const orderControllerPath = path.resolve(__dirname, '../application/admin/controller/shopro/order/Order.php');
|
||||
assert(fs.existsSync(orderControllerPath), 'Order.php 控制器存在');
|
||||
const orderContent = fs.readFileSync(orderControllerPath, 'utf-8');
|
||||
|
||||
test('Order.php buildPartnerSplit 支持分钟均分流水时间范围与去重查询', () => {
|
||||
assert(orderContent.includes("whereNull('settle_date')->whereBetween('createtime'"), '支持通过创建时间查询无结算日的分钟级流水');
|
||||
assert(orderContent.includes('$distinctUsers[intval($sr->user_id)] = true'), '参与人数必须按受益人去重');
|
||||
assert(orderContent.includes('$userCount = count($distinctUsers)'), '按独立受益人统计均分人数');
|
||||
});
|
||||
|
||||
console.log('\n--------------------------------------------------------');
|
||||
console.log(`测试执行结果: 通过 ${passCount} 项, 失败 0 项`);
|
||||
console.log('========================================================\n');
|
||||
在新工单中引用
屏蔽一个用户