78 lines
2.3 KiB
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);
|
|
}
|
|
}
|