parfum/database/factories/OrderFactory.php
Yoga Pangestu c4b90acf53 feat: membuat factory seluruh model
- menyesuaikan model jika ada yang salah seperti kurangnya trait SoftDeletes, casting yang salah, relasi yang kurang dan lainnya
- memperbaiki enum di migrasi
2025-12-09 08:25:07 +07:00

197 lines
5.9 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' => fake()->randomElement(OrderChannel::cases()),
'status' => fake()->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(fn () => tap(now()->subDay(), fn ($d) => null) && ['ordered_at' => $d = now()->subDay(), 'created_at' => $d]);
}
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')]);
}
}