Merge branch 'production' of https://git.abbauf.com/Magang-2025/Kasir into production

This commit is contained in:
adityaalfarison 2025-08-29 11:22:42 +07:00
commit b2f93c4537
20 changed files with 218 additions and 19 deletions

View File

@ -0,0 +1,82 @@
<?php
namespace App\Http\Controllers;
use App\Models\Kategori;
use Illuminate\Http\Request;
class KategoriController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return response()->json(
Kategori::withCount('produk')->get()
);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validated = $request->validate([
'nama' => 'required|string|max:100',
],
[
'nama' => 'Nama kategori harus diisi.'
]);
Kategori::create($validated);
return response()->json([
'message' => 'Kategori berhasil dibuat'
],201);
}
/**
* Display the specified resource.
*/
public function show(int $id)
{
return response()->json(
Kategori::with('items.produk.foto')->find($id)
);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, int $id)
{
$validated = $request->validate([
'nama' => 'required|string|max:100',
],
[
'nama' => 'Nama Kategori harus diisi.'
]);
$Kategori = Kategori::findOrFail($id);
$Kategori->update($validated);
return response()->json([
'message' => 'Kategori berhasil diupdate'
],200);
}
/**
* Remove the specified resource from storage.
*/
public function destroy(int $id)
{
Kategori::findOrFail($id)->delete();
return response()->json([
'message' => 'Kategori berhasil dihapus'
], 204);
}
}

View File

@ -17,7 +17,7 @@ class ProdukController extends Controller
public function index()
{
return response()->json(
Produk::withCount('items')->with('foto')->get()
Produk::withCount('items')->with('foto', 'kategori')->get()
);
}
@ -28,16 +28,16 @@ class ProdukController extends Controller
{
$validated = $request->validate([
'nama' => 'required|string|max:100',
'kategori' => 'required|in:cincin,gelang,kalung,anting',
'id_kategori' => 'required|exists:users,id',
'berat' => 'required|numeric',
'kadar' => 'required|integer',
'harga_per_gram' => 'required|numeric',
'harga_jual' => 'required|numeric',
'id_user' => 'nullable|exists:users,id', // untuk mengambil foto sementara
'id_user' => 'nullable|exists:users,id',
],
[
'nama.required' => 'Nama produk harus diisi.',
'kategori.in' => 'Kategori harus salah satu dari cincin, gelang, kalung, atau anting.',
'id_kategori' => 'Kategori tidak valid.',
'berat.required' => 'Berat harus diisi.',
'kadar.required' => 'Kadar harus diisi',
'harga_per_gram.required' => 'Harga per gram harus diisi',
@ -49,7 +49,7 @@ class ProdukController extends Controller
// Create produk
$produk = Produk::create([
'nama' => $validated['nama'],
'kategori' => $validated['kategori'],
'id_kategori' => $validated['id_kategori'],
'berat' => $validated['berat'],
'kadar' => $validated['kadar'],
'harga_per_gram' => $validated['harga_per_gram'],
@ -92,7 +92,7 @@ class ProdukController extends Controller
*/
public function show(int $id)
{
$produk = Produk::with('foto', 'items')->findOrFail($id);
$produk = Produk::with('foto', 'items', 'kategori')->findOrFail($id);
return response()->json($produk);
}
@ -103,7 +103,7 @@ class ProdukController extends Controller
{
$validated = $request->validate([
'nama' => 'required|string|max:100',
'kategori' => 'required|in:cincin,gelang,kalung,anting',
'id_kategori' => 'required|exists:kategoris,id',
'berat' => 'required|numeric',
'kadar' => 'required|integer',
'harga_per_gram' => 'required|numeric',
@ -113,7 +113,7 @@ class ProdukController extends Controller
],
[
'nama.required' => 'Nama produk harus diisi.',
'kategori.in' => 'Kategori harus salah satu dari cincin, gelang, kalung, atau anting.',
'id_kategori' => 'Kategori tidak valid.',
'berat.required' => 'Berat harus diisi.',
'kadar.required' => 'Kadar harus diisi',
'harga_per_gram.required' => 'Harga per gram harus diisi',

View File

@ -19,10 +19,21 @@ class TransaksiController extends Controller
$query->limit((int)$limit);
}
$transaksi = $query->get();
$transaksi = Transaksi::with(['kasir', 'sales', 'items.item.produk'])->latest()->limit(100)->get();
return response()->json($transaksi);
// Mapping agar sesuai dengan kebutuhan frontend
$mapped = $transaksi->map(function ($trx) {
return [
'id' => $trx->id,
'tanggal' => $trx->created_at->format('d/m/Y'),
'kode' => 'TRX-' . str_pad($trx->id, 6, '0', STR_PAD_LEFT),
'pendapatan'=> $trx->total_harga,
];
});
return response()->json($mapped);
}
// Detail transaksi by ID
public function show($id)
{

View File

@ -15,6 +15,8 @@ class Foto extends Model
'url',
];
protected $hidden = ['created_at', 'updated_at', 'deleted_at'];
public function produk()
{
return $this->belongsTo(Produk::class, 'id_produk');

View File

@ -10,4 +10,6 @@ class FotoSementara extends Model
'id_user',
'url',
];
protected $hidden = ['created_at', 'updated_at', 'deleted_at'];
}

View File

@ -16,6 +16,8 @@ class Item extends Model
'is_sold',
];
protected $hidden = ['created_at', 'updated_at', 'deleted_at'];
public function produk()
{
return $this->belongsTo(Produk::class, 'id_produk');

View File

@ -16,6 +16,8 @@ class ItemTransaksi extends Model
'harga_deal'
];
protected $hidden = ['created_at', 'updated_at', 'deleted_at'];
public function transaksi()
{
return $this->belongsTo(Transaksi::class, 'id_transaksi');

22
app/Models/Kategori.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Kategori extends Model
{
/** @use HasFactory<\Database\Factories\KategoriFactory> */
use HasFactory, SoftDeletes;
protected $fillable = ['nama'];
protected $hidden = ['created_at', 'updated_at', 'deleted_at'];
public function produks()
{
return $this->hasMany(Produk::class, 'id_kategori');
}
}

View File

@ -15,6 +15,7 @@ class Nampan extends Model
];
protected $appends = ['berat_total'];
protected $hidden = ['created_at', 'updated_at', 'deleted_at'];
public function items()
{

View File

@ -12,13 +12,15 @@ class Produk extends Model
protected $fillable = [
'nama',
'kategori',
'id_kategori',
'berat',
'kadar',
'harga_per_gram',
'harga_jual',
];
protected $hidden = ['created_at', 'updated_at', 'deleted_at'];
public function items()
{
return $this->hasMany(Item::class, 'id_produk');
@ -28,4 +30,9 @@ class Produk extends Model
{
return $this->hasMany(Foto::class, 'id_produk');
}
public function kategori()
{
return $this->belongsTo(Kategori::class, 'id_kategori');
}
}

View File

@ -16,6 +16,8 @@ class Sales extends Model
'alamat'
];
protected $hidden = ['created_at', 'updated_at', 'deleted_at'];
public function transaksi()
{
return $this->hasMany(Transaksi::class, 'id_sales');

View File

@ -20,6 +20,8 @@ class Transaksi extends Model
'created_at',
];
protected $hidden = ['updated_at', 'deleted_at'];
public function kasir()
{
return $this->belongsTo(User::class, 'id_kasir');

View File

@ -0,0 +1,23 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Kategori>
*/
class KategoriFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'nama' => $this->faker->word(),
];
}
}

View File

@ -2,6 +2,7 @@
namespace Database\Factories;
use App\Models\Kategori;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
@ -18,9 +19,10 @@ class ProdukFactory extends Factory
{
$harga_per_gram = $this->faker->numberBetween(80, 120) * 10000;
$berat = $this->faker->randomFloat(2, 1, 10);
$kategoriList = Kategori::all()->pluck('id')->toArray();
return [
'nama' => $this->faker->words(3, true),
'kategori' => $this->faker->randomElement(['cincin', 'gelang', 'kalung', 'anting']),
'id_kategori' => $this->faker->randomElement($kategoriList),
'berat' => $berat,
'kadar' => $this->faker->numberBetween(10, 24),
'harga_per_gram' => $harga_per_gram,

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('kategoris', function (Blueprint $table) {
$table->id();
$table->string('nama', 100);
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('kategoris');
}
};

View File

@ -14,7 +14,7 @@ return new class extends Migration
Schema::create('produks', function (Blueprint $table) {
$table->id();
$table->string('nama', 100);
$table->enum('kategori', ['cincin', 'gelang', 'kalung', 'anting']);
$table->foreignId('id_kategori')->constrained('kategoris');
$table->float('berat');
$table->integer('kadar');
$table->double('harga_per_gram');

View File

@ -3,6 +3,7 @@
namespace Database\Seeders;
use App\Models\Item;
use App\Models\Kategori;
use App\Models\Nampan;
use App\Models\Produk;
use App\Models\Sales;
@ -36,6 +37,13 @@ class DatabaseSeeder extends Seeder
}
}
$kategoriList = ['cincin', 'gelang', 'kalung', 'anting'];
foreach ($kategoriList as $kategori) {
Kategori::factory()->create([
'nama' => $kategori
]);
}
Produk::factory(10)->create()->each(function ($produk) {
// setiap produk punya 1-3 foto
$jumlah_foto = rand(1, 3);

BIN
public/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

View File

@ -16,6 +16,7 @@
<InputField
v-model="hargaJual"
type="number"
placeholder="Masukkan Harga Jual"
/>
</div>
</div>
@ -53,10 +54,10 @@
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in pesanan" :key="index" class="hover:bg-gray-50">
<td class="border border-gray-200 p-2 text-center">{{ index + 1 }}</td>
<tr v-for="(item, index) in pesanan" :key="index" class="hover:bg-gray-50 text-center">
<td class="border border-gray-200 p-2">{{ index + 1 }}</td>
<td class="border border-gray-200 p-2">{{ item.kode }}</td>
<td class="border border-gray-200 p-2 text-center">{{ item.jumlah }}</td>
<td class="border border-gray-200 p-2">{{ item.jumlah }}</td>
<td class="border border-gray-200 p-2">Rp{{ item.harga.toLocaleString() }}</td>
<td class="border border-gray-200 p-2">Rp{{ (item.harga * item.jumlah).toLocaleString() }}</td>
</tr>
@ -73,7 +74,7 @@
import InputField from './InputField.vue'
const kodeItem = ref('')
const hargaJual = ref(0)
const hargaJual = ref(null)
const pesanan = ref([])
const tambahItem = () => {
@ -91,3 +92,4 @@ import InputField from './InputField.vue'
pesanan.value.reduce((sum, item) => sum + item.harga * item.jumlah, 0)
)
</script>

View File

@ -26,8 +26,8 @@
onMounted(async () => {
try {
const res = await axios.get("/api/transaksi") // GANTI URL SESUAI API
const res = await axios.get("/api/transaksi?limit=10") // GANTI URL SESUAI API
transaksi.value = res.data
} catch (err) {
console.error("Gagal fetch transaksi:", err)