diff --git a/app/Models/ProductPrice.php b/app/Models/ProductPrice.php
new file mode 100644
index 0000000..d3cfdf2
--- /dev/null
+++ b/app/Models/ProductPrice.php
@@ -0,0 +1,45 @@
+ PriceType::class,
+ 'price' => 'integer',
+ ];
+ }
+
+ public function variant(): BelongsTo
+ {
+ return $this->belongsTo(ProductVariant::class, 'variant_id');
+ }
+
+ public function priceFormatted(): Attribute
+ {
+ return Attribute::make(
+ get: fn () => 'Rp '.number_format($this->price, 0, ',', '.'),
+ );
+ }
+
+ public function priceInput(): Attribute
+ {
+ return Attribute::make(
+ get: fn () => (string) $this->price,
+ );
+ }
+}
diff --git a/app/Models/ProductVariant.php b/app/Models/ProductVariant.php
index 1b25121..7d34270 100644
--- a/app/Models/ProductVariant.php
+++ b/app/Models/ProductVariant.php
@@ -42,6 +42,11 @@ public function cuttingResultPrices(): HasMany
return $this->hasMany(CuttingResultPrice::class);
}
+ public function prices(): HasMany
+ {
+ return $this->hasMany(ProductPrice::class, 'variant_id');
+ }
+
public function product(): BelongsTo
{
return $this->belongsTo(Product::class);
diff --git a/app/Services/Master/ProductService.php b/app/Services/Master/ProductService.php
index 7047cc3..351b5cb 100644
--- a/app/Services/Master/ProductService.php
+++ b/app/Services/Master/ProductService.php
@@ -27,7 +27,7 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $ca
->with([
'categories',
'variants' => fn ($query) => $query
- ->with('media')
+ ->with(['media', 'prices' => fn ($query) => $query->orderBy('type')])
->orderBy('created_at'),
])
->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
diff --git a/database/migrations/2026_06_20_235900_create_product_prices_table.php b/database/migrations/2026_06_20_235900_create_product_prices_table.php
new file mode 100644
index 0000000..632db6b
--- /dev/null
+++ b/database/migrations/2026_06_20_235900_create_product_prices_table.php
@@ -0,0 +1,33 @@
+id();
+
+ $table->foreignId('variant_id')->constrained('product_variants')->cascadeOnDelete();
+
+ $table->enum('type', array_column(PriceType::cases(), 'value'));
+ $table->unsignedInteger('price');
+
+ $table->timestamp('created_at')->useCurrent();
+ $table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate();
+ $table->softDeletes();
+
+ $table->unique(['variant_id', 'type']);
+ $table->index('variant_id');
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::dropIfExists('product_prices');
+ }
+};
diff --git a/resources/js/pages/admin/master/products/table/ProductGroupedTable.vue b/resources/js/pages/admin/master/products/table/ProductGroupedTable.vue
index ca932cf..dbd04f1 100644
--- a/resources/js/pages/admin/master/products/table/ProductGroupedTable.vue
+++ b/resources/js/pages/admin/master/products/table/ProductGroupedTable.vue
@@ -2,6 +2,7 @@
import { Link } from '@inertiajs/vue3';
import { computed } from 'vue';
import DataTableToolbar from '@/components/data-table/DataTableToolbar.vue';
+import { formatRupiah } from '@/lib/rupiah';
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
@@ -103,6 +104,11 @@ function rowNumber(index: number): number {
{{ product.variants.reduce((acc, v) => acc + v.stock, 0) }}
+
+ Total harga Rp
+ {{ formatRupiah(product.variants.reduce((acc, v) => acc + (v.prices?.reduce((s, p) => s + p.price, 0) ?? 0), 0)) }}
+
+
@@ -154,7 +160,7 @@ function rowNumber(index: number): number {
- Belum ada harga cutting
+ Belum ada harga
diff --git a/resources/js/types/product.ts b/resources/js/types/product.ts
index b7dc596..24b9f92 100644
--- a/resources/js/types/product.ts
+++ b/resources/js/types/product.ts
@@ -11,13 +11,12 @@ export type CategoryOption = {
};
export type ProductPriceItem = {
+ id: number;
+ variant_id: number;
type: string;
- type_label: string;
price: number;
price_formatted: string;
price_input: string;
- cost_per_unit?: number;
- cost_per_unit_formatted?: string;
};
export type ProductCategoryItem = {