207 行
6.5 KiB
PHP
207 行
6.5 KiB
PHP
<?php
|
|
|
|
namespace addons\shopro\library\commission;
|
|
|
|
use think\Db;
|
|
|
|
/**
|
|
* 复购立减服务类
|
|
* 针对指定商品(开启复购规则)且买家历史买过的商品,在付款时直接减免
|
|
*/
|
|
class RepurchaseService
|
|
{
|
|
/**
|
|
* 获取全局复购立减配置
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getConfig()
|
|
{
|
|
$config = [];
|
|
try {
|
|
$configModel = new Config();
|
|
$config = [
|
|
'enable' => $configModel->isRepurchaseEnable(),
|
|
'self_enable' => $configModel->isRepurchaseSelfEnable(),
|
|
'self_type' => $configModel->getRepurchaseSelfType(),
|
|
'self_amount' => $configModel->getRepurchaseSelfAmount(),
|
|
'self_rate' => $configModel->getRepurchaseSelfRate(),
|
|
];
|
|
} catch (\Throwable $e) {
|
|
$config = [
|
|
'enable' => false,
|
|
'self_enable' => false,
|
|
'self_type' => 'fixed',
|
|
'self_amount' => 0.0,
|
|
'self_rate' => 0.0,
|
|
];
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* 检查商品是否开启复购规则
|
|
*
|
|
* @param int $goodsId
|
|
* @return bool
|
|
*/
|
|
public static function isGoodsRepurchaseEnable($goodsId)
|
|
{
|
|
if (!$goodsId) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$row = Db::name('shopro_commission_goods')
|
|
->where('goods_id', $goodsId)
|
|
->where('status', 1)
|
|
->field('repurchase_enable')
|
|
->find();
|
|
return !empty($row['repurchase_enable']);
|
|
} catch (\Throwable $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查用户是否曾购买过该指定商品(有效付款订单)
|
|
*
|
|
* @param int $userId
|
|
* @param int $goodsId
|
|
* @return bool
|
|
*/
|
|
public static function isUserRepurchasedGoods($userId, $goodsId)
|
|
{
|
|
if (!$userId || !$goodsId) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$count = Db::name('shopro_order_item')
|
|
->alias('oi')
|
|
->join('shopro_order o', 'o.id = oi.order_id')
|
|
->where('o.user_id', $userId)
|
|
->where('o.status', 'in', [1, 2])
|
|
->where('oi.goods_id', $goodsId)
|
|
->where('oi.refund_status', '<=', 0)
|
|
->count();
|
|
|
|
return $count > 0;
|
|
} catch (\Throwable $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算单项商品的复购立减金额
|
|
*
|
|
* @param array $item 商品信息 (goods_id, goods_num, goods_price, goods_amount)
|
|
* @param array $config 复购配置
|
|
* @param bool $isGoodsEnable 该商品是否开启复购
|
|
* @param bool $isUserRepurchase 该用户是否复购该商品
|
|
* @return float
|
|
*/
|
|
public static function calculateItemDiscount($item, $config, $isGoodsEnable, $isUserRepurchase)
|
|
{
|
|
if (empty($config['enable']) || empty($config['self_enable'])) {
|
|
return 0.0;
|
|
}
|
|
|
|
if (!$isGoodsEnable || !$isUserRepurchase) {
|
|
return 0.0;
|
|
}
|
|
|
|
$goodsNum = isset($item['goods_num']) ? intval($item['goods_num']) : 1;
|
|
$goodsAmount = isset($item['goods_amount']) ? floatval($item['goods_amount']) : 0.0;
|
|
$goodsPrice = isset($item['goods_price']) ? floatval($item['goods_price']) : ($goodsNum > 0 ? $goodsAmount / $goodsNum : 0.0);
|
|
|
|
if ($goodsAmount <= 0) {
|
|
return 0.0;
|
|
}
|
|
|
|
$discount = 0.0;
|
|
$selfType = $config['self_type'] ?? 'fixed';
|
|
|
|
if ($selfType === 'rate') {
|
|
$rate = floatval($config['self_rate'] ?? 0);
|
|
if ($rate > 0) {
|
|
$discount = round($goodsAmount * $rate * 0.01, 2);
|
|
}
|
|
} else {
|
|
// 固定金额模式:按件数累加立减
|
|
$unitAmount = floatval($config['self_amount'] ?? 0);
|
|
if ($unitAmount > 0) {
|
|
// 单件立减不可超过单件售价
|
|
$validUnitDiscount = min($unitAmount, $goodsPrice);
|
|
$discount = round($validUnitDiscount * $goodsNum, 2);
|
|
}
|
|
}
|
|
|
|
// 兜底保护:总立减金额不可超过商品总额
|
|
if ($discount > $goodsAmount) {
|
|
$discount = $goodsAmount;
|
|
}
|
|
|
|
return max(0.0, $discount);
|
|
}
|
|
|
|
/**
|
|
* 批量计算订单中各商品的复购立减金额
|
|
*
|
|
* @param array $goodsList 商品列表
|
|
* @param int $userId 用户ID
|
|
* @param array|null $config 配置
|
|
* @param callable|null $goodsRuleChecker 自定义商品规则检查器 (用于单测或依赖注入)
|
|
* @param callable|null $historyChecker 自定义历史购买检查器 (用于单测或依赖注入)
|
|
* @return array ['goods_list' => ..., 'total_repurchase_discount' => float]
|
|
*/
|
|
public static function calculateOrderRepurchaseDiscounts(
|
|
$goodsList,
|
|
$userId,
|
|
$config = null,
|
|
$goodsRuleChecker = null,
|
|
$historyChecker = null
|
|
) {
|
|
if ($config === null) {
|
|
$config = self::getConfig();
|
|
}
|
|
|
|
$totalDiscount = 0.0;
|
|
|
|
foreach ($goodsList as $key => $item) {
|
|
$goodsId = $item['goods_id'] ?? 0;
|
|
|
|
// 检查商品是否参与复购
|
|
$isGoodsEnable = false;
|
|
if ($goodsRuleChecker !== null) {
|
|
$isGoodsEnable = (bool) call_user_func($goodsRuleChecker, $goodsId);
|
|
} else {
|
|
$isGoodsEnable = self::isGoodsRepurchaseEnable($goodsId);
|
|
}
|
|
|
|
// 检查用户是否复购该商品
|
|
$isUserRepurchase = false;
|
|
if ($isGoodsEnable) {
|
|
if ($historyChecker !== null) {
|
|
$isUserRepurchase = (bool) call_user_func($historyChecker, $userId, $goodsId);
|
|
} else {
|
|
$isUserRepurchase = self::isUserRepurchasedGoods($userId, $goodsId);
|
|
}
|
|
}
|
|
|
|
$discount = self::calculateItemDiscount($item, $config, $isGoodsEnable, $isUserRepurchase);
|
|
|
|
$goodsList[$key]['repurchase_discount_money'] = $discount;
|
|
$goodsList[$key]['is_repurchase'] = ($isGoodsEnable && $isUserRepurchase && $discount > 0) ? 1 : 0;
|
|
|
|
$totalDiscount = bcadd((string) $totalDiscount, (string) $discount, 2);
|
|
}
|
|
|
|
return [
|
|
'goods_list' => $goodsList,
|
|
'total_repurchase_discount' => floatval($totalDiscount)
|
|
];
|
|
}
|
|
}
|