feat: Add EggPrice management with resource, pages, model, migration, factory, and seeder for egg price tracking

This commit is contained in:
Yoga Pangestu 2026-02-19 04:13:40 +07:00
parent 557ae954d2
commit 93ab1d6eb1
7 changed files with 292 additions and 0 deletions

View File

@ -0,0 +1,134 @@
<?php
namespace App\Filament\Resources\Master\EggPrices;
use App\Filament\Actions\Cheerful\DeleteAction;
use App\Filament\Actions\Cheerful\EditAction;
use App\Filament\Actions\Cheerful\ForceDeleteAction;
use App\Filament\Actions\Cheerful\RestoreAction;
use App\Filament\Actions\DefaultBulkActions;
use App\Filament\Columns\TimestampColumns;
use App\Filament\Resources\Master\EggPrices\Pages\ManageEggPrices;
use App\Models\EggPrice;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Enums\Width;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use UnitEnum;
class EggPriceResource extends Resource
{
protected static ?string $model = EggPrice::class;
protected static string|UnitEnum|null $navigationGroup = 'Master';
protected static string|BackedEnum|null $navigationIcon = Heroicon::CurrencyDollar;
protected static ?string $navigationLabel = 'Harga Telur';
protected static ?int $navigationSort = 5;
protected static ?string $recordTitleAttribute = 'name';
protected static ?string $slug = 'master/egg-prices';
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label('Tipe Harga')
->placeholder('Ecer, Distributor, Grosir')
->required()
->maxLength(50)
->autofocus()
->autocomplete(false),
Select::make('unit_id')
->label('Satuan')
->relationship('unit', 'name')
->required()
->native(false)
->searchable()
->preload(),
TextInput::make('price')
->label('Harga')
->placeholder('0')
->required()
->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0)
->prefix('Rp')
->dehydrateStateUsing(fn ($state) => (int) str()->replace(',', '', (string) ($state ?? 0))),
])
->columns(1);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label('Tipe Harga')
->searchable()
->sortable(),
TextColumn::make('unit.name')
->label('Satuan')
->sortable(),
TextColumn::make('price')
->label('Harga')
->money('IDR', decimalPlaces: 0)
->sortable(),
...TimestampColumns::make(),
])
->filters([
TrashedFilter::make()
->native(false),
])
->recordActions([
EditAction::make()
->modalWidth(Width::Large),
DeleteAction::make(),
ForceDeleteAction::make(),
RestoreAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
...DefaultBulkActions::make('Harga Telur'),
]),
])
->emptyStateIcon(Heroicon::CurrencyDollar)
->emptyStateDescription('Setelah Anda membuat data pertama, maka akan muncul disini.')
->defaultSort('created_at', 'desc')
->deferFilters(false);
}
public static function getPages(): array
{
return [
'index' => ManageEggPrices::route('/'),
];
}
public static function getRecordRouteBindingEloquentQuery(): Builder
{
return parent::getRecordRouteBindingEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Filament\Resources\Master\EggPrices\Pages;
use App\Filament\Resources\Master\EggPrices\EggPriceResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ManageRecords;
use Filament\Support\Enums\Width;
class ManageEggPrices extends ManageRecords
{
protected static string $resource = EggPriceResource::class;
protected static ?string $title = 'Harga Telur';
protected function getHeaderActions(): array
{
return [
CreateAction::make()
->label('Tambah')
->modalHeading('Tambah Harga Telur')
->modalSubmitActionLabel('Simpan')
->modalCancelActionLabel('Batal')
->extraModalFooterActions(fn (CreateAction $action): array => [
$action->makeModalSubmitAction('createAnother', arguments: ['another' => true])
->label('Simpan dan Tambah Lagi'),
])
->modalWidth(Width::Large),
];
}
}

24
app/Models/EggPrice.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class EggPrice extends Model
{
use HasFactory, SoftDeletes;
protected $guarded = ['id'];
protected $casts = [
'price' => 'integer',
];
public function unit(): BelongsTo
{
return $this->belongsTo(Unit::class);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Database\Factories;
use App\Models\EggPrice;
use App\Models\Unit;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories.Factory<\App\Models\EggPrice>
*/
class EggPriceFactory extends Factory
{
protected $model = EggPrice::class;
public function definition(): array
{
$unit = Unit::inRandomOrder()->first() ?? Unit::factory()->create();
return [
'name' => $this->faker->randomElement(['Ecer', 'Grosir', 'Distributor']).' '.$this->faker->randomElement(['Pagi', 'Siang', 'Malam']),
'unit_id' => $unit->id,
'price' => $this->faker->numberBetween(1500, 3000),
];
}
}

View File

@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('egg_prices', function (Blueprint $table) {
$table->id();
$table->string('name', 50);
$table->foreignId('unit_id')->constrained()->cascadeOnDelete();
$table->unsignedInteger('price');
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->nullable()->useCurrentOnUpdate();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('egg_prices');
}
};

View File

@ -23,6 +23,7 @@ public function run(): void
FeedPurchaseSeeder::class,
EggCollectionSeeder::class,
CustomerSeeder::class,
EggPriceSeeder::class,
]);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Database\Seeders;
use App\Models\EggPrice;
use App\Models\Unit;
use Illuminate\Database\Seeder;
class EggPriceSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$unit = Unit::first() ?? Unit::factory()->create([
'name' => 'Kilogram',
'alias' => 'kg',
]);
$defaults = [
[
'name' => 'Ecer',
'price' => 2800,
],
[
'name' => 'Grosir',
'price' => 2600,
],
[
'name' => 'Distributor',
'price' => 2500,
],
];
foreach ($defaults as $data) {
EggPrice::firstOrCreate(
[
'name' => $data['name'],
'unit_id' => $unit->id,
],
[
'price' => $data['price'],
]
);
}
EggPrice::factory()->count(5)->create();
}
}