store/app/Support/Marketplace/MarketplaceFeeCalculator.php

78 lines
2.3 KiB
PHP

<?php
namespace App\Support\Marketplace;
use App\Enums\MarketplaceFeeScope;
use App\Enums\MarketplaceFeeValueType;
class MarketplaceFeeCalculator
{
/**
* @param array<string, array{scope: string, value_type: string, value: float|int}> $fees
* @param list<array{quantity: int, subtotal: int}> $lineItems
* @return array{
* results: array<string, array{amount: int, balance_after: int}>,
* total_fee_amount: int,
* net_amount: int
* }
*/
public function calculate(array $fees, int $totalAmount, array $lineItems): array
{
$results = [];
$balance = $totalAmount;
$totalFeeAmount = 0;
foreach ($fees as $key => $ruleData) {
$amount = $this->calculateFeeAmount(
MarketplaceFeeRule::fromArray($ruleData),
$totalAmount,
$lineItems,
);
$balance = max($balance - $amount, 0);
$totalFeeAmount += $amount;
$results[$key] = [
'amount' => $amount,
'balance_after' => $balance,
];
}
return [
'results' => $results,
'total_fee_amount' => $totalFeeAmount,
'net_amount' => max($totalAmount - $totalFeeAmount, 0),
];
}
/**
* @param list<array{quantity: int, subtotal: int}> $lineItems
*/
private function calculateFeeAmount(MarketplaceFeeRule $rule, int $totalAmount, array $lineItems): int
{
if ($rule->scope === MarketplaceFeeScope::TRANSACTION) {
return $this->calculateFromBasis(
$rule,
$totalAmount,
);
}
return (int) collect($lineItems)->sum(function (array $item) use ($rule): int {
if ($rule->valueType === MarketplaceFeeValueType::FLAT) {
return (int) round($rule->value * $item['quantity']);
}
return (int) round($item['subtotal'] * $rule->value / 100);
});
}
private function calculateFromBasis(MarketplaceFeeRule $rule, int $basis): int
{
if ($rule->valueType === MarketplaceFeeValueType::FLAT) {
return (int) round($rule->value);
}
return (int) round($basis * $rule->value / 100);
}
}