| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- <?php
- namespace Longyi\FreeGift\Services;
- /**
- * 赠品折扣计算。
- *
- * 对应 Amasty 的 Model\DiscountCalculator,保持同样的 4 种写法:
- * - '' → 全免(等同 100%)
- * - '100%' → 全免
- * - '50%' → 半价
- * - '-10' → 立减 10
- * - '99' → 一口价 99(原价 - 99)
- */
- class GiftDiscountCalculator
- {
- /**
- * 计算减免金额。
- *
- * @param string|null $promo
- * @param float $price
- */
- public function discountFor($promo, float $price): float
- {
- $promo = trim((string) $promo);
- if ($promo === '' || $promo === '100%') {
- return $price;
- }
- if (str_contains($promo, '%')) {
- $percent = (float) $promo;
- // 支持 "0.5" 与 "50" 两种百分比写法
- $percent = $percent > 1 ? $percent / 100 : $percent;
- return $price * min(1, max(0, $percent));
- }
- if (str_starts_with($promo, '-')) {
- return min(abs((float) $promo), $price);
- }
- // 一口价
- return max(0, $price - (float) $promo);
- }
- /**
- * minimal_items_price 兜底:折后单价不得低于最低价。
- */
- public function clampToMinimal(float $discount, float $price, $minimal): float
- {
- $minimal = (float) $minimal;
- if ($minimal > 0 && ($price - $discount) < $minimal) {
- return max(0, $price - $minimal);
- }
- return $discount;
- }
- /**
- * 一步算出赠品的实际单价。
- *
- * @param string|null $promo
- * @param float $price
- * @param float|null $minimal
- */
- public function priceFor($promo, float $price, $minimal = null): float
- {
- $discount = $this->discountFor($promo, $price);
- $discount = $this->clampToMinimal($discount, $price, $minimal);
- return round(max(0, $price - $discount), 4);
- }
- }
|