parfum/database/factories/OrderFactory.php

207 lines
6.0 KiB
PHP

<?php
namespace Database\Factories;
use App\Enums\OrderChannel;
use App\Enums\OrderStatus;
use App\Models\Customer;
use App\Models\Order;
use App\Models\Outlet;
use App\Models\User;
use App\Models\Voucher;
use Illuminate\Database\Eloquent\Factories\Factory;
class OrderFactory extends Factory
{
protected $model = Order::class;
public function definition(): array
{
$subtotal = $this->faker->numberBetween(50000, 1000000);
$discount = $this->faker->numberBetween(0, (int) ($subtotal * 0.3)); // Max 30% discount
$total = $subtotal - $discount;
$cogs = (int) ($subtotal * 0.4); // COGS is typically 40% of subtotal
// Generate invoice number: INV + YYYYMMDD + 4 digit sequence
// For testing, use random sequence to ensure uniqueness
$sequence = $this->faker->numberBetween(1, 9999);
$invoiceNumber = 'INV'.now()->format('Ymd').str_pad($sequence, 4, '0', STR_PAD_LEFT);
return [
'outlet_id' => Outlet::factory(),
'user_id' => User::factory(),
'customer_id' => null,
'voucher_id' => null,
'invoice_number' => $invoiceNumber,
'cogs' => $cogs,
'subtotal' => $subtotal,
'discount' => $discount,
'total' => $total,
'channel' => $this->faker->randomElement(OrderChannel::cases()),
'status' => $this->faker->randomElement(OrderStatus::cases()),
'ordered_at' => $this->faker->dateTimeBetween('-1 year', 'now'),
];
}
public function draft(): Factory
{
return $this->state(fn () => ['status' => OrderStatus::DRAFT]);
}
public function pending(): Factory
{
return $this->state(fn () => ['status' => OrderStatus::PENDING]);
}
public function partial(): Factory
{
return $this->state(fn () => ['status' => OrderStatus::PARTIAL]);
}
public function paid(): Factory
{
return $this->state(fn () => ['status' => OrderStatus::PAID]);
}
public function overdue(): Factory
{
return $this->state(fn () => ['status' => OrderStatus::OVERDUE]);
}
public function canceled(): Factory
{
return $this->state(fn () => ['status' => OrderStatus::CANCELED]);
}
public function outlet(): Factory
{
return $this->state(fn () => ['channel' => OrderChannel::OUTLET]);
}
public function shopee(): Factory
{
return $this->state(fn () => ['channel' => OrderChannel::SHOPEE]);
}
public function tokopedia(): Factory
{
return $this->state(fn () => ['channel' => OrderChannel::TOKOPEDIA]);
}
public function website(): Factory
{
return $this->state(fn () => ['channel' => OrderChannel::WEBSITE]);
}
public function instagram(): Factory
{
return $this->state(fn () => ['channel' => OrderChannel::INSTAGRAM]);
}
public function whatsapp(): Factory
{
return $this->state(fn () => ['channel' => OrderChannel::WHATSAPP]);
}
public function other(): Factory
{
return $this->state(fn () => ['channel' => OrderChannel::OTHER]);
}
public function withCustomer(?Customer $customer = null): Factory
{
return $this->state(fn () => ['customer_id' => $customer?->id ?? Customer::factory()]);
}
public function withVoucher(?Voucher $voucher = null): Factory
{
return $this->state(fn () => ['voucher_id' => $voucher?->id ?? Voucher::factory()]);
}
public function withOutlet(?Outlet $outlet = null): Factory
{
return $this->state(fn () => ['outlet_id' => $outlet?->id ?? Outlet::factory()]);
}
public function withUser(?User $user = null): Factory
{
return $this->state(fn () => ['user_id' => $user?->id ?? User::factory()]);
}
public function withAmounts(int $subtotal, ?int $discount = null, ?int $cogs = null): Factory
{
return $this->state(function (array $attributes) use ($subtotal, $discount, $cogs) {
$discount = $discount ?? $this->faker->numberBetween(0, (int) ($subtotal * 0.3));
$total = $subtotal - $discount;
$cogs = $cogs ?? (int) ($subtotal * 0.4);
return [
'subtotal' => $subtotal,
'discount' => $discount,
'total' => $total,
'cogs' => $cogs,
];
});
}
public function withDiscount(int $discount): Factory
{
return $this->state(function (array $attributes) use ($discount) {
$subtotal = $attributes['subtotal'] ?? $this->faker->numberBetween(50000, 1000000);
$total = $subtotal - $discount;
return [
'discount' => $discount,
'total' => max(0, $total),
];
});
}
public function withoutDiscount(): Factory
{
return $this->state(function (array $attributes) {
$subtotal = $attributes['subtotal'] ?? $this->faker->numberBetween(50000, 1000000);
return [
'discount' => 0,
'total' => $subtotal,
];
});
}
public function today(): Factory
{
return $this->state(fn () => [
'ordered_at' => now(),
'created_at' => now(),
]);
}
public function yesterday(): Factory
{
return $this->state(function () {
$yesterday = now()->subDay();
return [
'ordered_at' => $yesterday,
'created_at' => $yesterday,
];
});
}
public function thisWeek(): Factory
{
return $this->state(fn () => ['ordered_at' => $this->faker->dateTimeBetween('-7 days', 'now')]);
}
public function thisMonth(): Factory
{
return $this->state(fn () => ['ordered_at' => $this->faker->dateTimeBetween('-30 days', 'now')]);
}
public function lastMonth(): Factory
{
return $this->state(fn () => ['ordered_at' => $this->faker->dateTimeBetween('-60 days', '-30 days')]);
}
}