Refactor order service to utilize new marketplace snapshot structure. Update create and update methods to call buildOrderSnapshot with total amount and line items for improved fee calculation. Introduce lineItemsForSnapshot method for consistent item formatting in snapshots.
This commit is contained in:
parent
7d721cab31
commit
c30fe015e2
@ -299,7 +299,11 @@ public function create(array $validated, User $user): Order
|
||||
'created_by_id' => $user->id,
|
||||
'subtotal' => $subtotal,
|
||||
'discount' => $discount,
|
||||
'marketplace_settings_snapshot' => $this->marketplaceService->snapshotForChannel($channel),
|
||||
'marketplace_settings_snapshot' => $this->marketplaceService->buildOrderSnapshot(
|
||||
$channel,
|
||||
$totalAmount,
|
||||
$this->lineItemsForSnapshot($draftItems),
|
||||
),
|
||||
'total_amount' => $totalAmount,
|
||||
'notes' => $validated['notes'] ?? null,
|
||||
]);
|
||||
@ -346,7 +350,11 @@ public function update(Order $order, array $validated): void
|
||||
$order->price_type = $priceType;
|
||||
$order->subtotal = $subtotal;
|
||||
$order->discount = $discount;
|
||||
$order->marketplace_settings_snapshot = $this->marketplaceService->snapshotForChannel($channel);
|
||||
$order->marketplace_settings_snapshot = $this->marketplaceService->buildOrderSnapshot(
|
||||
$channel,
|
||||
$totalAmount,
|
||||
$this->lineItemsForSnapshot($lineItems),
|
||||
);
|
||||
$order->total_amount = $totalAmount;
|
||||
$order->notes = $validated['notes'] ?? null;
|
||||
$order->save();
|
||||
@ -531,6 +539,21 @@ private function incrementStock(OrderItem $item): void
|
||||
->increment('stock', $item->quantity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EloquentCollection<int, OrderItem>|list<array{quantity: int, subtotal: int}> $items
|
||||
* @return list<array{quantity: int, subtotal: int}>
|
||||
*/
|
||||
private function lineItemsForSnapshot(EloquentCollection|array $items): array
|
||||
{
|
||||
return collect($items)
|
||||
->map(fn (OrderItem|array $item) => [
|
||||
'quantity' => (int) (is_array($item) ? $item['quantity'] : $item->quantity),
|
||||
'subtotal' => (int) (is_array($item) ? $item['subtotal'] : $item->subtotal),
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
private function applySorting(Builder $query, string $sort, string $direction): void
|
||||
{
|
||||
if (in_array($sort, ['created_at', 'total_amount', 'discount', 'subtotal', 'order_number'], true)) {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
use App\Enums\OrderChannel;
|
||||
use App\Settings\MarketplaceSettings;
|
||||
use App\Support\Marketplace\MarketplaceFeeCalculator;
|
||||
use App\Support\Marketplace\MarketplaceFeeRule;
|
||||
|
||||
class MarketplaceService
|
||||
@ -76,9 +77,37 @@ public function updateMarketplace(array $validated): void
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array{quantity: int, subtotal: int}> $lineItems
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function snapshotForChannel(OrderChannel $channel): ?array
|
||||
public function buildOrderSnapshot(OrderChannel $channel, int $totalAmount, array $lineItems): ?array
|
||||
{
|
||||
$feeSnapshot = $this->feeRulesForChannel($channel);
|
||||
|
||||
if ($feeSnapshot === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$calculation = app(MarketplaceFeeCalculator::class)->calculate(
|
||||
$feeSnapshot['fees'],
|
||||
$totalAmount,
|
||||
$lineItems,
|
||||
);
|
||||
|
||||
return [
|
||||
'platform' => $feeSnapshot['platform'],
|
||||
'fees' => $feeSnapshot['fees'],
|
||||
'base_amount' => $totalAmount,
|
||||
'results' => $calculation['results'],
|
||||
'total_fee_amount' => $calculation['total_fee_amount'],
|
||||
'net_amount' => $calculation['net_amount'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{platform: string, fees: array<string, array{scope: string, value_type: string, value: float}>}|null
|
||||
*/
|
||||
private function feeRulesForChannel(OrderChannel $channel): ?array
|
||||
{
|
||||
$settings = app(MarketplaceSettings::class);
|
||||
|
||||
|
||||
77
app/Support/Marketplace/MarketplaceFeeCalculator.php
Normal file
77
app/Support/Marketplace/MarketplaceFeeCalculator.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user