feat: implement priority_weighted_plus_percent pricing algorithm
This commit is contained in:
@@ -40,7 +40,7 @@ class WebsiteGroupBinding(Base):
|
||||
target_group_name: Mapped[str] = mapped_column(String(255), default="")
|
||||
source_groups_json: Mapped[str] = mapped_column(Text, default="[]")
|
||||
percent: Mapped[str] = mapped_column(String(32), default="0")
|
||||
algorithm: Mapped[str] = mapped_column(String(64), default="max_plus_percent")
|
||||
algorithm: Mapped[str] = mapped_column(String(64), default="priority_weighted_plus_percent")
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
|
||||
@@ -73,7 +73,7 @@ SENSITIVE_CREDENTIAL_KEYS = {
|
||||
"aws_secret_access_key", "aws_session_token",
|
||||
"service_account_json", "service_account", "private_key",
|
||||
}
|
||||
ALGORITHMS = {"max_plus_percent", "average_plus_percent", "min_plus_percent"}
|
||||
ALGORITHMS = {"max_plus_percent", "average_plus_percent", "min_plus_percent", "priority_weighted_plus_percent"}
|
||||
|
||||
|
||||
def _mask(cfg: dict) -> dict:
|
||||
|
||||
@@ -91,7 +91,7 @@ class BindingCreate(BaseModel):
|
||||
target_group_name: str = ""
|
||||
source_groups: list[BindingSourceGroup] = Field(default_factory=list)
|
||||
percent: float = Field(default=0, ge=0)
|
||||
algorithm: str = "max_plus_percent"
|
||||
algorithm: str = "priority_weighted_plus_percent"
|
||||
enabled: bool = True
|
||||
|
||||
|
||||
|
||||
@@ -65,12 +65,32 @@ def calculate_target_rate(values: list[Any], percent: Any = 0, algorithm: str =
|
||||
base = min(rates)
|
||||
elif algorithm == "max_plus_percent":
|
||||
base = max(rates)
|
||||
elif algorithm == "priority_weighted_plus_percent":
|
||||
rates_sorted = sorted(rates)
|
||||
N = len(rates_sorted)
|
||||
if N == 1:
|
||||
base = rates_sorted[0]
|
||||
else:
|
||||
base = Decimal("0")
|
||||
remaining = Decimal("1.0")
|
||||
for i in range(N):
|
||||
if i == N - 1:
|
||||
weight = remaining
|
||||
else:
|
||||
weight = remaining * Decimal("0.85")
|
||||
remaining -= weight
|
||||
base += rates_sorted[i] * weight
|
||||
else:
|
||||
raise WebsiteError(f"不支持的算法:{algorithm}")
|
||||
pct = Decimal(str(percent or 0))
|
||||
if pct < 0:
|
||||
raise WebsiteError("百分比不能为负数")
|
||||
return (base * (Decimal("1") + pct / Decimal("100"))).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
||||
target_rate = (base * (Decimal("1") + pct / Decimal("100"))).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
||||
if algorithm == "priority_weighted_plus_percent":
|
||||
min_rate = min(rates)
|
||||
if target_rate < min_rate:
|
||||
target_rate = min_rate
|
||||
return target_rate
|
||||
|
||||
|
||||
def _unwrap_data(value: Any) -> Any:
|
||||
|
||||
@@ -399,3 +399,19 @@ def test_list_accounts_pagination_returns_none_when_any_page_fails():
|
||||
assert len(requests_called) == 2
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
|
||||
def test_calculate_target_rate_priority_weighted():
|
||||
# 0.18、0.25 + 50% 应得到约 0.29
|
||||
assert calculate_target_rate(["0.18", "0.25"], 50, "priority_weighted_plus_percent") == Decimal("0.29")
|
||||
# 单来源时等同于该来源倍率 + 百分比
|
||||
assert calculate_target_rate(["0.18"], 50, "priority_weighted_plus_percent") == Decimal("0.27")
|
||||
# 多来源时权重按低倍率优先,最高倍率不会主导价格
|
||||
assert calculate_target_rate(["0.18", "0.25", "0.38"], 50, "priority_weighted_plus_percent") == Decimal("0.29")
|
||||
|
||||
# 无可用正数倍率时报错
|
||||
with pytest.raises(WebsiteError, match="没有可用的正数上游倍率"):
|
||||
calculate_target_rate([], 50, "priority_weighted_plus_percent")
|
||||
|
||||
# 旧算法结果不变
|
||||
assert calculate_target_rate(["0.18", "0.25"], 50, "max_plus_percent") == Decimal("0.38")
|
||||
|
||||
Reference in New Issue
Block a user