diff --git a/app/Models/Attachment.php b/app/Models/Attachment.php new file mode 100644 index 0000000..6152331 --- /dev/null +++ b/app/Models/Attachment.php @@ -0,0 +1,31 @@ +created_at->format('Y-m-d').'/'.$this->name.'.'.$this->extension; + } + + public function attachmentable(): MorphTo + { + return $this->morphTo(); + } +} diff --git a/app/Models/Attendance.php b/app/Models/Attendance.php new file mode 100644 index 0000000..683884d --- /dev/null +++ b/app/Models/Attendance.php @@ -0,0 +1,36 @@ +belongsTo(User::class); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } + + public function attachments(): MorphMany + { + return $this->morphMany(Attachment::class, 'attachmentable'); + } +} diff --git a/app/Models/Barbershop.php b/app/Models/Barbershop.php new file mode 100644 index 0000000..62f3177 --- /dev/null +++ b/app/Models/Barbershop.php @@ -0,0 +1,76 @@ +hasMany(User::class); + } + + public function customers(): HasMany + { + return $this->hasMany(Customer::class); + } + + public function services(): HasMany + { + return $this->hasMany(Service::class); + } + + public function attendances(): HasMany + { + return $this->hasMany(Attendance::class); + } + + public function expenses(): HasMany + { + return $this->hasMany(Expense::class); + } + + public function inventory(): HasMany + { + return $this->hasMany(Inventory::class); + } + + public function transactions(): HasMany + { + return $this->hasMany(Transaction::class); + } + + public function payrolls(): HasMany + { + return $this->hasMany(Payroll::class); + } + + public function cash(): HasMany + { + return $this->hasMany(Cash::class); + } + + public function attachment(): MorphOne + { + return $this->morphOne(Attachment::class, 'attachmentable'); + } +} diff --git a/app/Models/Biography.php b/app/Models/Biography.php new file mode 100644 index 0000000..48a3ad3 --- /dev/null +++ b/app/Models/Biography.php @@ -0,0 +1,28 @@ +belongsTo(User::class); + } +} diff --git a/app/Models/Cash.php b/app/Models/Cash.php new file mode 100644 index 0000000..6a42c68 --- /dev/null +++ b/app/Models/Cash.php @@ -0,0 +1,38 @@ +belongsTo(User::class); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } + + public function attachment(): MorphOne + { + return $this->morphOne(Attachment::class, 'attachmentable'); + } +} diff --git a/app/Models/Customer.php b/app/Models/Customer.php new file mode 100644 index 0000000..e0d9a58 --- /dev/null +++ b/app/Models/Customer.php @@ -0,0 +1,30 @@ +belongsTo(User::class); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } +} diff --git a/app/Models/Expense.php b/app/Models/Expense.php new file mode 100644 index 0000000..fd66e0a --- /dev/null +++ b/app/Models/Expense.php @@ -0,0 +1,36 @@ +belongsTo(User::class); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } + + public function attachment(): MorphOne + { + return $this->morphOne(Attachment::class, 'attachmentable'); + } +} diff --git a/app/Models/Inventory.php b/app/Models/Inventory.php new file mode 100644 index 0000000..aff1eb8 --- /dev/null +++ b/app/Models/Inventory.php @@ -0,0 +1,39 @@ +belongsTo(User::class); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } + + public function attachment(): MorphOne + { + return $this->morphOne(Attachment::class, 'attachmentable'); + } +} diff --git a/app/Models/Payroll.php b/app/Models/Payroll.php new file mode 100644 index 0000000..5791fd0 --- /dev/null +++ b/app/Models/Payroll.php @@ -0,0 +1,45 @@ +belongsTo(User::class); + } + + public function employee(): BelongsTo + { + return $this->belongsTo(User::class, 'employee_id'); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } + + public function attachment(): MorphOne + { + return $this->morphOne(Attachment::class, 'attachmentable'); + } +} diff --git a/app/Models/Role.php b/app/Models/Role.php new file mode 100644 index 0000000..2291354 --- /dev/null +++ b/app/Models/Role.php @@ -0,0 +1,20 @@ +hasMany(User::class); + } +} diff --git a/app/Models/Service.php b/app/Models/Service.php new file mode 100644 index 0000000..9353f80 --- /dev/null +++ b/app/Models/Service.php @@ -0,0 +1,31 @@ +belongsTo(User::class); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } +} diff --git a/app/Models/Setting.php b/app/Models/Setting.php new file mode 100644 index 0000000..4a4e7b6 --- /dev/null +++ b/app/Models/Setting.php @@ -0,0 +1,25 @@ +morphOne(Attachment::class, 'attachmentable'); + } +} diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php new file mode 100644 index 0000000..260905d --- /dev/null +++ b/app/Models/Transaction.php @@ -0,0 +1,50 @@ +belongsTo(User::class); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } + + public function customer(): BelongsTo + { + return $this->belongsTo(Customer::class); + } + + public function service(): BelongsTo + { + return $this->belongsTo(Service::class); + } + + public function attachment(): MorphOne + { + return $this->morphOne(Attachment::class, 'attachmentable'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 3dfbd80..a5be2f3 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,45 +4,86 @@ // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\HasOne; +use Illuminate\Database\Eloquent\Relations\MorphOne; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { - /** @use HasFactory<\Database\Factories\UserFactory> */ - use HasFactory, Notifiable; + use HasFactory, Notifiable, SoftDeletes; - /** - * The attributes that are mass assignable. - * - * @var array - */ protected $fillable = [ - 'name', + 'role_id', + 'barbershop_id', + 'username', 'email', 'password', + 'base_salary', + 'sop', + 'is_active', ]; - /** - * The attributes that should be hidden for serialization. - * - * @var array - */ - protected $hidden = [ - 'password', - 'remember_token', - ]; - - /** - * Get the attributes that should be cast. - * - * @return array - */ - protected function casts(): array + public function role(): BelongsTo { - return [ - 'email_verified_at' => 'datetime', - 'password' => 'hashed', - ]; + return $this->belongsTo(Role::class); + } + + public function barbershop(): BelongsTo + { + return $this->belongsTo(Barbershop::class); + } + + public function biography(): HasOne + { + return $this->hasOne(Biography::class); + } + + public function customers(): HasMany + { + return $this->hasMany(Customer::class); + } + + public function services(): HasMany + { + return $this->hasMany(Service::class); + } + + public function attendances(): HasMany + { + return $this->hasMany(Attendance::class); + } + + public function expenses(): HasMany + { + return $this->hasMany(Expense::class); + } + + public function inventory(): HasMany + { + return $this->hasMany(Inventory::class); + } + + public function transactions(): HasMany + { + return $this->hasMany(Transaction::class); + } + + public function payrolls(): HasMany + { + return $this->hasMany(Payroll::class); + } + + public function cash(): HasMany + { + return $this->hasMany(Cash::class); + } + + public function attachment(): MorphOne + { + return $this->morphOne(Attachment::class, 'attachmentable'); } } diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index 05fb5d9..5d83329 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -11,14 +11,38 @@ */ public function up(): void { + Schema::create('roles', function (Blueprint $table) { + $table->id(); + $table->string('name', 20); + $table->timestamps(); + $table->softDeletes(); + }); + + Schema::create('barbershop', function (Blueprint $table) { + $table->id(); + $table->string('name', 50); + $table->string('contact_number', 15); + $table->string('landmark', 30); + $table->text('address'); + $table->date('opened'); + $table->date('closed')->nullable(); + $table->decimal('cash', 10, 2)->default(0.00); + $table->timestamps(); + $table->softDeletes(); + }); + Schema::create('users', function (Blueprint $table) { $table->id(); - $table->string('name'); + $table->foreignId('role_id')->constrained()->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->string('username', 15)->unique(); $table->string('email')->unique(); - $table->timestamp('email_verified_at')->nullable(); - $table->string('password'); - $table->rememberToken(); + $table->string('password', 60); + $table->decimal('base_salary', 10, 2)->default(0.00); + $table->text('sop')->nullable(); + $table->enum('is_active', ['1', '0'])->default('1'); $table->timestamps(); + $table->softDeletes(); }); Schema::create('password_reset_tokens', function (Blueprint $table) { diff --git a/database/migrations/2024_11_18_172111_create_biographies_table.php b/database/migrations/2024_11_18_172111_create_biographies_table.php new file mode 100644 index 0000000..1792c49 --- /dev/null +++ b/database/migrations/2024_11_18_172111_create_biographies_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('full_name'); + $table->string('pob', 75); + $table->dateTime('dob'); + $table->string('contact_number', 15); + $table->text('address'); + $table->enum('gender', ['1', '2'])->comment('1:Laki-Laki 2:Perempuan'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('biographies'); + } +}; diff --git a/database/migrations/2024_11_18_172439_create_customers_table.php b/database/migrations/2024_11_18_172439_create_customers_table.php new file mode 100644 index 0000000..47ff146 --- /dev/null +++ b/database/migrations/2024_11_18_172439_create_customers_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->string('name', 30); + $table->string('contact_number', 15); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('customers'); + } +}; diff --git a/database/migrations/2024_11_18_172545_create_services_table.php b/database/migrations/2024_11_18_172545_create_services_table.php new file mode 100644 index 0000000..d46f3a1 --- /dev/null +++ b/database/migrations/2024_11_18_172545_create_services_table.php @@ -0,0 +1,33 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->string('name', 100); + $table->decimal('price', 8, 2); + $table->text('description'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('services'); + } +}; diff --git a/database/migrations/2024_11_18_172745_create_expenses_table.php b/database/migrations/2024_11_18_172745_create_expenses_table.php new file mode 100644 index 0000000..ea5e231 --- /dev/null +++ b/database/migrations/2024_11_18_172745_create_expenses_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->string('name'); + $table->decimal('amount', 10, 2); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('expenses'); + } +}; diff --git a/database/migrations/2024_11_18_172841_create_payrolls_table.php b/database/migrations/2024_11_18_172841_create_payrolls_table.php new file mode 100644 index 0000000..ca96e23 --- /dev/null +++ b/database/migrations/2024_11_18_172841_create_payrolls_table.php @@ -0,0 +1,36 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('employee_id')->constrained('users')->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->decimal('amount', 10, 2)->comment('Base salary'); + $table->decimal('incentive', 10, 2); + $table->decimal('cut', 10, 2); + $table->decimal('total', 10, 2); + $table->text('description'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('payrolls'); + } +}; diff --git a/database/migrations/2024_11_18_191551_create_cash_table.php b/database/migrations/2024_11_18_191551_create_cash_table.php new file mode 100644 index 0000000..b3c48b0 --- /dev/null +++ b/database/migrations/2024_11_18_191551_create_cash_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->text('name'); + $table->decimal('amount', 10, 2); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cashes'); + } +}; diff --git a/database/migrations/2024_11_18_191648_create_attendances_table.php b/database/migrations/2024_11_18_191648_create_attendances_table.php new file mode 100644 index 0000000..7b7335e --- /dev/null +++ b/database/migrations/2024_11_18_191648_create_attendances_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->time('check_in'); + $table->time('check_out')->nullable(); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('attendances'); + } +}; diff --git a/database/migrations/2024_11_18_191728_create_transactions_table.php b/database/migrations/2024_11_18_191728_create_transactions_table.php new file mode 100644 index 0000000..6300a1f --- /dev/null +++ b/database/migrations/2024_11_18_191728_create_transactions_table.php @@ -0,0 +1,36 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->foreignId('customer_id')->constrained()->cascadeOnDelete(); + $table->foreignId('service_id')->constrained()->cascadeOnDelete(); + $table->decimal('price', 8, 2); + $table->decimal('discount', 8, 2)->default(0); + $table->decimal('total', 9, 2); + $table->enum('payment_method', ['1', '2', '3'])->comment('1:Cash 2:Qris 3:Other'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('transactions'); + } +}; diff --git a/database/migrations/2024_11_18_191906_create_inventory_table.php b/database/migrations/2024_11_18_191906_create_inventory_table.php new file mode 100644 index 0000000..fcb2f2e --- /dev/null +++ b/database/migrations/2024_11_18_191906_create_inventory_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('barbershop_id')->constrained('barbershop')->cascadeOnDelete(); + $table->string('name', 100); + $table->integer('quantity'); + $table->text('description'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('inventories'); + } +}; diff --git a/database/migrations/2024_11_18_192512_create_settings_table.php b/database/migrations/2024_11_18_192512_create_settings_table.php new file mode 100644 index 0000000..a29248e --- /dev/null +++ b/database/migrations/2024_11_18_192512_create_settings_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name', 30); + $table->string('email'); + $table->string('contact_number', 15); + $table->text('description'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('settings'); + } +}; diff --git a/database/migrations/2024_11_18_193153_create_attachments_table.php b/database/migrations/2024_11_18_193153_create_attachments_table.php new file mode 100644 index 0000000..35edb20 --- /dev/null +++ b/database/migrations/2024_11_18_193153_create_attachments_table.php @@ -0,0 +1,32 @@ +id(); + $table->nullableMorphs('attachmentable'); + $table->string('name', 50); + $table->string('extension', 10); + $table->string('size', 10); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('attachments'); + } +}; diff --git a/database/seeders/BarbershopSeeder.php b/database/seeders/BarbershopSeeder.php new file mode 100644 index 0000000..92c0399 --- /dev/null +++ b/database/seeders/BarbershopSeeder.php @@ -0,0 +1,23 @@ + 'XYZ Barbershop', + 'contact_number' => '08123456789', + 'landmark' => 'Depan J.co', + 'address' => 'Jl.Babaru Nagri', + 'opened' => '2023-01-01', + ]); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d01a0ef..41d6376 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,7 +2,6 @@ namespace Database\Seeders; -use App\Models\User; // use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; @@ -13,11 +12,11 @@ class DatabaseSeeder extends Seeder */ public function run(): void { - // User::factory(10)->create(); - - User::factory()->create([ - 'name' => 'Test User', - 'email' => 'test@example.com', + $this->call([ + RoleSeeder::class, + BarbershopSeeder::class, + UserSeeder::class, + SettingSeeder::class, ]); } } diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php new file mode 100644 index 0000000..e216e2e --- /dev/null +++ b/database/seeders/RoleSeeder.php @@ -0,0 +1,29 @@ + $role, + ]); + } + } +} diff --git a/database/seeders/SettingSeeder.php b/database/seeders/SettingSeeder.php new file mode 100644 index 0000000..c95b3e4 --- /dev/null +++ b/database/seeders/SettingSeeder.php @@ -0,0 +1,22 @@ + 'XYZ Barbershop', + 'email' => 'barbershop@example.com', + 'contact_number' => '08123456789', + 'description' => 'Selamat datang di XYZ Barbershop, tempat di mana seni mencukur rambut bertemu dengan kenyamanan dan layanan berkualitas tinggi. Kami menghadirkan pengalaman potong rambut terbaik untuk pria yang ingin tampil percaya diri dan penuh gaya.', + ]); + } +} diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php new file mode 100644 index 0000000..4545453 --- /dev/null +++ b/database/seeders/UserSeeder.php @@ -0,0 +1,70 @@ + 1, + 'barbershop_id' => 1, + 'username' => 'yoga', + 'email' => 'yoga@developer.com', + 'password' => Hash::make(env('PASSWORD_DEFAULT_USER')), + ]); + + // Create biography for the user + Biography::create([ + 'user_id' => $newUser->id, + 'full_name' => 'Yoga Pangestu', + 'pob' => 'Subang', + 'dob' => '2000-01-01', + 'contact_number' => '082121495806', + 'address' => 'Jl.Babaru Nagri', + 'gender' => 1, + ]); + + // Path to the image file + $imagePath = public_path('assets/admin/images/avatar/speed.jpeg'); + + // Check if the file exists + if (file_exists($imagePath)) { + // Create a Symfony file instance + $file = new \Symfony\Component\HttpFoundation\File\File($imagePath); + + // Generate a unique file name + $fileName = Str::uuid().'.'.$file->getExtension(); + + // Create an attachment record + Attachment::create([ + 'attachmentable_id' => $newUser->id, + 'attachmentable_type' => User::class, + 'name' => $fileName, + 'extension' => $file->getExtension(), + 'size' => $file->getSize(), + ]); + + // Define the storage path for avatars + $path = 'avatars/'.now()->format('Y-m-d'); + + // Store the file in the defined path using Storage facade + Storage::disk('public')->putFileAs($path, $file, $fileName); + } + }); + } +}