feat: add prices relationship to ProductVariant model and update related services and UI for improved product pricing management
This commit is contained in:
parent
ab03d5f0b9
commit
256b13ad73
45
app/Models/ProductPrice.php
Normal file
45
app/Models/ProductPrice.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\PriceType;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
#[Guarded(['id'])]
|
||||||
|
#[Appends(['price_formatted', 'price_input'])]
|
||||||
|
class ProductPrice extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'type' => 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -42,6 +42,11 @@ public function cuttingResultPrices(): HasMany
|
|||||||
return $this->hasMany(CuttingResultPrice::class);
|
return $this->hasMany(CuttingResultPrice::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function prices(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(ProductPrice::class, 'variant_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function product(): BelongsTo
|
public function product(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Product::class);
|
return $this->belongsTo(Product::class);
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $ca
|
|||||||
->with([
|
->with([
|
||||||
'categories',
|
'categories',
|
||||||
'variants' => fn ($query) => $query
|
'variants' => fn ($query) => $query
|
||||||
->with('media')
|
->with(['media', 'prices' => fn ($query) => $query->orderBy('type')])
|
||||||
->orderBy('created_at'),
|
->orderBy('created_at'),
|
||||||
])
|
])
|
||||||
->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
|
->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Enums\PriceType;
|
||||||
|
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('product_prices', function (Blueprint $table) {
|
||||||
|
$table->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');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -2,6 +2,7 @@
|
|||||||
import { Link } from '@inertiajs/vue3';
|
import { Link } from '@inertiajs/vue3';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import DataTableToolbar from '@/components/data-table/DataTableToolbar.vue';
|
import DataTableToolbar from '@/components/data-table/DataTableToolbar.vue';
|
||||||
|
import { formatRupiah } from '@/lib/rupiah';
|
||||||
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
|
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@ -103,6 +104,11 @@ function rowNumber(index: number): number {
|
|||||||
{{ product.variants.reduce((acc, v) => acc + v.stock, 0) }}
|
{{ product.variants.reduce((acc, v) => acc + v.stock, 0) }}
|
||||||
</strong>
|
</strong>
|
||||||
</span>
|
</span>
|
||||||
|
<span>
|
||||||
|
Total harga <strong class="text-primary"> Rp
|
||||||
|
{{ formatRupiah(product.variants.reduce((acc, v) => acc + (v.prices?.reduce((s, p) => s + p.price, 0) ?? 0), 0)) }}
|
||||||
|
</strong>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -154,7 +160,7 @@ function rowNumber(index: number): number {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span v-else class="text-xs text-muted-foreground">Belum ada harga cutting</span>
|
<span v-else class="text-xs text-muted-foreground">Belum ada harga</span>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
|||||||
@ -11,13 +11,12 @@ export type CategoryOption = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type ProductPriceItem = {
|
export type ProductPriceItem = {
|
||||||
|
id: number;
|
||||||
|
variant_id: number;
|
||||||
type: string;
|
type: string;
|
||||||
type_label: string;
|
|
||||||
price: number;
|
price: number;
|
||||||
price_formatted: string;
|
price_formatted: string;
|
||||||
price_input: string;
|
price_input: string;
|
||||||
cost_per_unit?: number;
|
|
||||||
cost_per_unit_formatted?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProductCategoryItem = {
|
export type ProductCategoryItem = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user