448 行
17 KiB
PHP
448 行
17 KiB
PHP
<?php
|
||
|
||
namespace addons\shopro\service\partner;
|
||
|
||
/**
|
||
* 合伙股东配置读取
|
||
*/
|
||
class PartnerConfig
|
||
{
|
||
public static function get($key, $default = null)
|
||
{
|
||
$code = strpos($key, 'shop.commission.') === 0 ? $key : 'shop.commission.' . $key;
|
||
if (!function_exists('sheep_config')) {
|
||
$helper = defined('ROOT_PATH') ? (ROOT_PATH . 'addons/shopro/helper/helper.php') : (__DIR__ . '/../../helper/helper.php');
|
||
if (file_exists($helper)) {
|
||
require_once $helper;
|
||
}
|
||
}
|
||
$value = function_exists('sheep_config') ? sheep_config($code) : null;
|
||
if ($value === null || $value === '') {
|
||
return $default;
|
||
}
|
||
return $value;
|
||
}
|
||
|
||
public static function isPartnerMode()
|
||
{
|
||
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);
|
||
return $enable === null ? true : (bool) $enable;
|
||
}
|
||
|
||
public static function showMadowRate()
|
||
{
|
||
$show = self::get('partner_show_madow_rate', 1);
|
||
if ($show === null || $show === '') {
|
||
return 1;
|
||
}
|
||
return intval($show) ? 1 : 0;
|
||
}
|
||
|
||
public static function isMadowWithdrawEnabled()
|
||
{
|
||
$enable = self::get('partner_madow_withdraw_enable', 1);
|
||
if ($enable === null || $enable === '') {
|
||
return 1;
|
||
}
|
||
return intval($enable) ? 1 : 0;
|
||
}
|
||
|
||
public static function madowWithdrawMin()
|
||
{
|
||
$min = self::get('partner_madow_withdraw_min', 1);
|
||
if ($min === null || $min === '' || !is_numeric($min)) {
|
||
return 1.0;
|
||
}
|
||
return max(0.0, floatval($min));
|
||
}
|
||
|
||
public static function madowRuleTitle()
|
||
{
|
||
$title = trim((string) self::get('partner_madow_rule_title', '市值与增值规则')) ?: '市值与增值规则';
|
||
return str_replace('马币', '', $title);
|
||
}
|
||
|
||
public static function madowRules()
|
||
{
|
||
$defaultRules = [
|
||
[
|
||
'title' => 'DMEPA获取与核算',
|
||
'desc' => '平台合伙人与创客达成考核或完成订单后,系统将于次日 00:30 起统一参与每日DMEPA加权核算并自动分发。',
|
||
],
|
||
[
|
||
'title' => '市值动态增值',
|
||
'desc' => '市值随全平台订单增加而上浮增值。全网完成订单总量越多,DMEPA单价所对应的市值越高,共享生态红利。',
|
||
],
|
||
[
|
||
'title' => '价值说明与权益',
|
||
'desc' => '市值仅作为平台数字生态资产价值参考展示,不可直接兑换现金提现。具体权益按平台股东与合伙人章程执行。',
|
||
],
|
||
];
|
||
$rules = self::get('partner_madow_rules', $defaultRules);
|
||
$normalized = self::normalizeRules($rules, $defaultRules);
|
||
foreach ($normalized as &$rule) {
|
||
if (isset($rule['title'])) {
|
||
$rule['title'] = str_replace('马币', '', $rule['title']);
|
||
}
|
||
if (isset($rule['desc'])) {
|
||
$rule['desc'] = str_replace('马币', '', $rule['desc']);
|
||
}
|
||
}
|
||
unset($rule);
|
||
return $normalized;
|
||
}
|
||
|
||
public static function voucherRuleTitle()
|
||
{
|
||
return trim((string) self::get('partner_voucher_rule_title', '兑换券释放与使用规则')) ?: '兑换券释放与使用规则';
|
||
}
|
||
|
||
public static function voucherRules()
|
||
{
|
||
$defaultRules = [
|
||
[
|
||
'title' => '赠送与释放天数',
|
||
'desc' => '会员在平台完成符合条件的商城订单后,系统将按订单金额(默认 1.5 倍)生成兑换券计划,分 365 天按日线性释放。',
|
||
],
|
||
[
|
||
'title' => '每日自动到账',
|
||
'desc' => '系统将于次日 00:30 起统一执行日结核算,按期释放的兑换券将自动计入您的「可用兑换券」账户,无需手动领取。',
|
||
],
|
||
[
|
||
'title' => '全场购物直接抵扣',
|
||
'desc' => '可用兑换券可在平台商城下单结算时作为现金抵扣使用,尊享优惠抵扣权益。',
|
||
],
|
||
];
|
||
$rules = self::get('partner_voucher_rules', $defaultRules);
|
||
return self::normalizeRules($rules, $defaultRules);
|
||
}
|
||
|
||
private static function normalizeRules($rules, array $defaultRules)
|
||
{
|
||
if (is_string($rules)) {
|
||
$decoded = json_decode($rules, true);
|
||
if (is_array($decoded)) {
|
||
$rules = $decoded;
|
||
} else {
|
||
$lines = array_filter(array_map('trim', explode("\n", $rules)));
|
||
$parsed = [];
|
||
foreach ($lines as $line) {
|
||
$parts = preg_split('/[::]/u', $line, 2);
|
||
if (count($parts) === 2) {
|
||
$parsed[] = ['title' => trim($parts[0]), 'desc' => trim($parts[1])];
|
||
} else {
|
||
$parsed[] = ['title' => '', 'desc' => $line];
|
||
}
|
||
}
|
||
$rules = !empty($parsed) ? $parsed : $defaultRules;
|
||
}
|
||
}
|
||
if (!is_array($rules) || empty($rules)) {
|
||
return $defaultRules;
|
||
}
|
||
$result = [];
|
||
foreach ($rules as $item) {
|
||
if (is_array($item)) {
|
||
$title = isset($item['title']) ? trim((string) $item['title']) : '';
|
||
$desc = isset($item['desc']) ? trim((string) $item['desc']) : '';
|
||
if ($title !== '' || $desc !== '') {
|
||
$result[] = ['title' => $title, 'desc' => $desc];
|
||
}
|
||
} elseif (is_string($item) && trim($item) !== '') {
|
||
$result[] = ['title' => '', 'desc' => trim($item)];
|
||
}
|
||
}
|
||
return !empty($result) ? $result : $defaultRules;
|
||
}
|
||
|
||
public static function activeDays()
|
||
{
|
||
$days = intval(self::get('partner_active_days', 30));
|
||
return $days > 0 ? $days : 30;
|
||
}
|
||
|
||
public static function chainMaxDepth()
|
||
{
|
||
$depth = intval(self::get('partner_chain_max_depth', 50));
|
||
return $depth > 0 ? $depth : 50;
|
||
}
|
||
|
||
public static function push3Amounts()
|
||
{
|
||
$amounts = self::get('partner_push3_amounts', [398, 400, 600]);
|
||
if (!is_array($amounts) || count($amounts) < 3) {
|
||
return [398, 400, 600];
|
||
}
|
||
return array_map('floatval', array_values($amounts));
|
||
}
|
||
|
||
public static function makerBonus()
|
||
{
|
||
$bonus = self::get('partner_maker_bonus', [2 => 20, 3 => 40, 4 => 60, 5 => 80, 6 => 100, 7 => 120]);
|
||
if (!is_array($bonus)) {
|
||
return [2 => 20, 3 => 40, 4 => 60, 5 => 80, 6 => 100, 7 => 120];
|
||
}
|
||
$map = [];
|
||
foreach ($bonus as $level => $amount) {
|
||
$map[intval($level)] = floatval($amount);
|
||
}
|
||
return $map;
|
||
}
|
||
|
||
public static function roleNames()
|
||
{
|
||
return [
|
||
'taster' => trim((string) self::get('partner_role_name_taster', '品酒师')) ?: '品酒师',
|
||
'maker' => trim((string) self::get('partner_role_name_maker', '创客')) ?: '创客',
|
||
'venue' => trim((string) self::get('partner_role_name_venue', '酒道馆')) ?: '酒道馆',
|
||
'county' => trim((string) self::get('partner_role_name_county', '区县代理')) ?: '区县代理',
|
||
'partner' => trim((string) self::get('partner_role_name_partner', '合伙股东')) ?: '合伙股东',
|
||
];
|
||
}
|
||
|
||
public static function rewardTypeText($type)
|
||
{
|
||
$map = self::rewardTypeMap();
|
||
return $map[$type] ?? $type;
|
||
}
|
||
|
||
public static function rewardTypeMap()
|
||
{
|
||
$roles = self::roleNames();
|
||
$maker = $roles['maker'];
|
||
$venue = $roles['venue'];
|
||
$county = $roles['county'];
|
||
$countyShort = in_array($county, ['区县代理', '区县']) ? '区县' : $county;
|
||
$countyAgentShort = in_array($county, ['区县代理', '区县']) ? '区县代' : $county;
|
||
|
||
return [
|
||
'push3' => '推荐提成',
|
||
'maker_diff' => $maker . '进阶奖',
|
||
'maker_peer' => $maker . '协同奖',
|
||
'maker_overtaken' => $maker . '卓越奖',
|
||
'team_venue' => $venue . '管理奖',
|
||
'team_county' => $countyShort . '管理奖',
|
||
'venue_peer' => $venue . '平级奖',
|
||
'county_peer' => $countyAgentShort . '平级奖',
|
||
'venue_share' => $venue . '加权奖',
|
||
'county_share' => $countyShort . '加权奖',
|
||
'madow_share' => '每日贡献dmepa',
|
||
'madow_withdraw' => 'dmepa提现扣除',
|
||
'madow_withdraw_refund' => 'dmepa提现退还',
|
||
'admin_madow' => '管理员调整dmepa',
|
||
'voucher_grant' => '消费补贴发放',
|
||
'voucher_release' => '消费补贴到账',
|
||
'voucher_consume' => '消费券抵扣',
|
||
'voucher_consume_refund' => '消费券退款退还',
|
||
'admin_voucher' => '管理员调整兑换券',
|
||
];
|
||
}
|
||
|
||
public static function skipReasonText($code, $forUser = false)
|
||
{
|
||
$roles = self::roleNames();
|
||
$maker = $roles['maker'];
|
||
$venue = $roles['venue'];
|
||
$county = $roles['county'];
|
||
|
||
$inner = [
|
||
'no_parent' => '无推荐上级',
|
||
'self_buy' => '本人自购',
|
||
'inactive_30d' => '受益人 30 日无自购',
|
||
'not_maker' => '不是' . $maker . '身份',
|
||
'not_venue' => '不是' . $venue . '身份',
|
||
'not_county' => '不是' . $county . '身份',
|
||
'cap_not_higher' => '等级未超过基数水位',
|
||
'already_settled' => '幂等跳过',
|
||
'partner_goods_off' => '商品未参与',
|
||
'partner_off' => '结算未开启',
|
||
];
|
||
$user = [
|
||
'no_parent' => '暂无推荐人,不计提推荐提成',
|
||
'self_buy' => '本人下单不计提推荐提成',
|
||
'inactive_30d' => '需 30 日内有本人订单才能领取奖励',
|
||
'not_maker' => '',
|
||
'not_venue' => '',
|
||
'not_county' => '',
|
||
'cap_not_higher' => '同阶不计进阶差额,享受平级奖励',
|
||
'already_settled' => '',
|
||
'partner_goods_off' => '',
|
||
'partner_off' => '',
|
||
];
|
||
if ($forUser) {
|
||
return $user[$code] ?? '';
|
||
}
|
||
return $inner[$code] ?? $code;
|
||
}
|
||
|
||
public static function statusText($status)
|
||
{
|
||
$map = [
|
||
0 => '待入账',
|
||
1 => '已入账',
|
||
-1 => '已取消',
|
||
-2 => '已退回',
|
||
];
|
||
return $map[intval($status)] ?? '';
|
||
}
|
||
|
||
public static function instantTypes()
|
||
{
|
||
return [
|
||
'push3', 'maker_diff', 'maker_peer', 'maker_overtaken',
|
||
'team_venue', 'team_county', 'venue_peer', 'county_peer',
|
||
];
|
||
}
|
||
|
||
public static function defaultRules()
|
||
{
|
||
return [
|
||
'push3_amounts' => self::push3Amounts(),
|
||
'maker_bonus' => self::makerBonus(),
|
||
'maker_peer_rate' => (float) self::get('partner_maker_peer_rate', 0.10),
|
||
'maker_overtaken_rate' => (float) self::get('partner_maker_overtaken_rate', 0.05),
|
||
'venue_split' => (float) self::get('partner_venue_split', 50),
|
||
'county_full' => (float) self::get('partner_county_full', 100),
|
||
'venue_peer_rate' => (float) self::get('partner_venue_peer_rate', 0.10),
|
||
'county_peer_rate' => (float) self::get('partner_county_peer_rate', 0.10),
|
||
'voucher_times' => (float) self::get('partner_voucher_times', 1.5),
|
||
'voucher_days' => (int) self::get('partner_voucher_days', 365),
|
||
'venue_share' => (float) self::get('partner_venue_share_per_order', 100),
|
||
'county_share' => (float) self::get('partner_county_share_per_order', 50),
|
||
'is_custom' => false,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 获取指定商品/规格的生效分成规则(优先独立规则,未设置项回退默认规则)
|
||
*/
|
||
public static function getEffectiveRules($goodsId, $skuPriceId = 0)
|
||
{
|
||
$rules = self::defaultRules();
|
||
$goodsId = intval($goodsId);
|
||
if ($goodsId <= 0) {
|
||
return $rules;
|
||
}
|
||
|
||
try {
|
||
$cg = \think\Db::name('shopro_commission_goods')->where('goods_id', $goodsId)->find();
|
||
if (!$cg || intval($cg['status'] ?? 0) !== 1) {
|
||
// 未参与计奖
|
||
$rules['status'] = 0;
|
||
return $rules;
|
||
}
|
||
$rules['status'] = 1;
|
||
$rules['commission_order_status'] = intval($cg['commission_order_status'] ?? 1);
|
||
$selfRules = intval($cg['self_rules'] ?? 0);
|
||
$rules['self_rules'] = $selfRules;
|
||
|
||
if ($selfRules !== 1 && $selfRules !== 2) {
|
||
return $rules; // 默认规则
|
||
}
|
||
|
||
$raw = $cg['commission_rules'] ?? '';
|
||
$custom = is_array($raw) ? $raw : (json_decode($raw, true) ?: []);
|
||
if (empty($custom)) {
|
||
return $rules;
|
||
}
|
||
|
||
// 多规格支持:优先匹配特定规格配置
|
||
$skuKey = intval($skuPriceId);
|
||
if ($skuKey > 0 && isset($custom[$skuKey]) && is_array($custom[$skuKey])) {
|
||
$custom = $custom[$skuKey];
|
||
} elseif ($skuKey > 0 && isset($custom['sku_' . $skuKey]) && is_array($custom['sku_' . $skuKey])) {
|
||
$custom = $custom['sku_' . $skuKey];
|
||
}
|
||
|
||
if (isset($custom['push3_amounts']) && is_array($custom['push3_amounts']) && count($custom['push3_amounts']) >= 3) {
|
||
$rules['push3_amounts'] = array_map('floatval', array_values($custom['push3_amounts']));
|
||
}
|
||
if (isset($custom['maker_bonus']) && is_array($custom['maker_bonus'])) {
|
||
$mb = [];
|
||
foreach ($custom['maker_bonus'] as $lvl => $val) {
|
||
$mb[intval($lvl)] = floatval($val);
|
||
}
|
||
$rules['maker_bonus'] = $mb;
|
||
}
|
||
if (isset($custom['maker_peer_rate']) && is_numeric($custom['maker_peer_rate'])) {
|
||
$rules['maker_peer_rate'] = floatval($custom['maker_peer_rate']);
|
||
}
|
||
if (isset($custom['maker_overtaken_rate']) && is_numeric($custom['maker_overtaken_rate'])) {
|
||
$rules['maker_overtaken_rate'] = floatval($custom['maker_overtaken_rate']);
|
||
}
|
||
if (isset($custom['venue_split']) && is_numeric($custom['venue_split'])) {
|
||
$rules['venue_split'] = floatval($custom['venue_split']);
|
||
}
|
||
if (isset($custom['county_full']) && is_numeric($custom['county_full'])) {
|
||
$rules['county_full'] = floatval($custom['county_full']);
|
||
}
|
||
if (isset($custom['venue_peer_rate']) && is_numeric($custom['venue_peer_rate'])) {
|
||
$rules['venue_peer_rate'] = floatval($custom['venue_peer_rate']);
|
||
}
|
||
if (isset($custom['county_peer_rate']) && is_numeric($custom['county_peer_rate'])) {
|
||
$rules['county_peer_rate'] = floatval($custom['county_peer_rate']);
|
||
}
|
||
if (isset($custom['voucher_times']) && is_numeric($custom['voucher_times'])) {
|
||
$rules['voucher_times'] = floatval($custom['voucher_times']);
|
||
}
|
||
if (isset($custom['voucher_days']) && is_numeric($custom['voucher_days'])) {
|
||
$rules['voucher_days'] = intval($custom['voucher_days']);
|
||
}
|
||
if (isset($custom['venue_share']) && is_numeric($custom['venue_share'])) {
|
||
$rules['venue_share'] = floatval($custom['venue_share']);
|
||
}
|
||
if (isset($custom['county_share']) && is_numeric($custom['county_share'])) {
|
||
$rules['county_share'] = floatval($custom['county_share']);
|
||
}
|
||
|
||
$rules['is_custom'] = true;
|
||
return $rules;
|
||
} catch (\Exception $e) {
|
||
return $rules;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析订单中主计奖商品的生效分成规则
|
||
*/
|
||
public static function getOrderEffectiveRules($order)
|
||
{
|
||
$default = self::defaultRules();
|
||
$items = $order['items'] ?? [];
|
||
if (empty($items) && !empty($order['id'])) {
|
||
$fresh = \app\admin\model\shopro\order\Order::with(['items'])->where('id', $order['id'])->find();
|
||
if ($fresh) {
|
||
$items = $fresh['items'] ?? [];
|
||
}
|
||
}
|
||
|
||
// 优先寻找设置了独立分成规则的计奖商品
|
||
foreach ($items as $item) {
|
||
$ext = is_array($item['ext'] ?? null) ? $item['ext'] : (json_decode($item['ext'] ?? '', true) ?: []);
|
||
if (isset($ext['is_commission']) && !$ext['is_commission']) {
|
||
continue;
|
||
}
|
||
$goodsId = intval($item['goods_id'] ?? 0);
|
||
$skuId = intval($item['goods_sku_price_id'] ?? 0);
|
||
$rules = self::getEffectiveRules($goodsId, $skuId);
|
||
if (!empty($rules['is_custom'])) {
|
||
return $rules;
|
||
}
|
||
}
|
||
|
||
return $default;
|
||
}
|
||
}
|
||
|