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

151 行
5.5 KiB
PHP

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

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

<?php
namespace addons\shopro\service\partner;
use app\admin\model\shopro\partner\RateLog;
use app\admin\model\shopro\order\Order as OrderModel;
use app\admin\model\shopro\commission\CommissionGoods;
/**
* dmepa汇率:rate = base * floor(N / n)
*/
class RateService
{
/**
* 获取大盘当前即时生效汇率(基于全网合格订单 N 实时动态计算,短缓存 120 秒保障高并发读性能)
*
* @param bool $forceRefresh 是否强制穿透缓存实时重算
* @return float
*/
public function currentRate($forceRefresh = false)
{
if (!$forceRefresh) {
$cached = cache('partner_madow_current_rate');
if ($cached !== null && $cached !== false && (float) $cached > 0) {
return (float) $cached;
}
}
$rate = $this->calcRate($this->countN());
cache('partner_madow_current_rate', $rate, 120);
return $rate;
}
/**
* 主动清除当前dmepa汇率缓存(订单支付、退款或后台调整时调用)
*/
public static function clearCache()
{
cache('partner_madow_current_rate', null);
}
public function calcRate($n = null)
{
$n = $n === null ? $this->countN() : intval($n);
$rawBase = PartnerConfig::get('partner_madow_base_rate', '0.00000075');
$base = is_numeric($rawBase) ? (float) $rawBase : 0.00000075;
// 关键防坑:PHP 8.0+ 下小于 0.0001 的浮点数转为 string 时会自动变成科学计数法 (如 "7.5E-7")
// 传给 bcmul() 会直接抛出 Fatal error: Argument #1 ($num1) is not well-formed
// 必须使用 number_format 格式化为无科学计数法的高精度十进制字符串
$baseStr = number_format($base, 12, '.', '');
$step = intval(PartnerConfig::get('partner_madow_step_orders', 1));
$step = $step > 0 ? $step : 1;
$multiple = max(1, floor($n / $step));
$multipleStr = number_format($multiple, 0, '.', '');
if (function_exists('bcmul')) {
return (float) bcmul($baseStr, $multipleStr, 12);
}
return (float) ($base * $multiple);
}
public function countN()
{
return $this->qualifiedOrderQuery()->count();
}
public function snapshot($settleDate, $gmv = 0, $extra = [])
{
$n = $this->countN();
$rate = $this->calcRate($n);
$row = RateLog::where('settle_date', $settleDate)->find();
$data = array_merge([
'settle_date' => $settleDate,
'order_count_n' => $n,
'rate' => $rate,
'gmv' => $gmv,
'createtime' => time(),
], $extra);
if ($row) {
$row->save($data);
cache('partner_madow_current_rate', (float) $rate, 300);
return $row;
}
$created = RateLog::create($data);
cache('partner_madow_current_rate', (float) $rate, 300);
return $created;
}
public function qualifiedOrderQuery($start = null, $end = null)
{
$goodsTable = (new CommissionGoods())->getQuery()->getTable();
$orderTable = (new OrderModel())->getQuery()->getTable();
$itemTable = \think\Db::name('shopro_order_item')->getTable();
$query = OrderModel::alias('o')
->where('o.type', '<>', 'score')
->where('o.pay_fee', '>', 0)
->whereIn('o.status', [OrderModel::STATUS_PAID, OrderModel::STATUS_COMPLETED])
->whereExists(function ($q) use ($orderTable, $itemTable, $goodsTable) {
$q->table($itemTable)->alias('oi')
->join($goodsTable . ' cg', 'cg.goods_id = oi.goods_id')
->whereRaw('oi.order_id = o.id')
->where('cg.status', CommissionGoods::GOODS_COMMISSION_STATUS_ON);
});
if ($start !== null) {
$query->where('o.paid_time', '>=', $start);
}
if ($end !== null) {
$query->where('o.paid_time', '<=', $end);
}
return $query;
}
/**
* 汇总指定时间区间内所有合格订单中“计奖商品”的实付总额(排除非计奖商品及活动不参与项)
*/
public function qualifiedGmv($start = null, $end = null)
{
$goodsTable = (new CommissionGoods())->getQuery()->getTable();
$orderTable = (new OrderModel())->getQuery()->getTable();
$itemTable = \think\Db::name('shopro_order_item')->getTable();
$query = \think\Db::table($itemTable)->alias('oi')
->join($orderTable . ' o', 'o.id = oi.order_id')
->join($goodsTable . ' cg', 'cg.goods_id = oi.goods_id')
->where('o.type', '<>', 'score')
->where('o.pay_fee', '>', 0)
->whereIn('o.status', [OrderModel::STATUS_PAID, OrderModel::STATUS_COMPLETED])
->where('cg.status', CommissionGoods::GOODS_COMMISSION_STATUS_ON)
->where(function ($q) {
$q->whereNull('oi.ext')
->whereOr('oi.ext', '')
->whereOr(function ($sq) {
$sq->where('oi.ext', 'not like', '%"is_commission":false%')
->where('oi.ext', 'not like', '%"is_commission":0%');
});
});
if ($start !== null) {
$query->where('o.paid_time', '>=', $start);
}
if ($end !== null) {
$query->where('o.paid_time', '<=', $end);
}
$gmv = $query->sum('oi.pay_fee');
return round((float) $gmv, 2);
}
}