feat: implement sorting for lines in purchase and restock create/edit components; enhance user experience

This commit is contained in:
Yoga Pangestu 2026-08-05 20:26:58 +07:00
parent 6546e1e3eb
commit b70a40af4d
11 changed files with 54 additions and 8 deletions

View File

@ -39,7 +39,7 @@ protected function formattedName(): Attribute
protected function statusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->status->label(),
get: fn () => $this->status?->label(),
);
}

View File

@ -2,8 +2,10 @@
namespace App\Models;
use App\Models\Scopes\ProductVariantScope;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -15,6 +17,7 @@
#[Appends(['formatted_name'])]
#[Guarded(['id'])]
#[ScopedBy([ProductVariantScope::class])]
class ProductVariant extends Model implements HasMedia
{
use HasFactory, InteractsWithMedia, SoftDeletes;

View File

@ -2,9 +2,11 @@
namespace App\Models;
use App\Models\Scopes\RawMaterialPriceScope;
use App\Services\S3PresignedService;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -16,6 +18,7 @@
#[Appends(['formatted_price'])]
#[Guarded(['id'])]
#[ScopedBy([RawMaterialPriceScope::class])]
class RawMaterialPrice extends Model implements HasMedia
{
use HasFactory, InteractsWithMedia, SoftDeletes;

View File

@ -0,0 +1,15 @@
<?php
namespace App\Models\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class ProductVariantScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->orderBy('name');
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Models\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class RawMaterialPriceScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->orderBy('variant');
}
}

View File

@ -29,7 +29,9 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
'supplier:id,name',
'createdBy:id',
'createdBy.userProfile:id,user_id,full_name',
'purchaseItems:id,purchase_id,raw_material_price_id,quantity,unit_price,subtotal',
'purchaseItems' => fn ($q) => $q
->select('id', 'purchase_id', 'raw_material_price_id', 'quantity', 'unit_price', 'subtotal')
->orderByRaw('(SELECT variant FROM raw_material_prices WHERE raw_material_prices.id = purchase_items.raw_material_price_id)'),
'purchaseItems.rawMaterialPrice:id,raw_material_id,variant,price,stock',
'purchaseItems.rawMaterialPrice.rawMaterial:id,name,unit',
])
@ -86,6 +88,8 @@ public function getForCreate(): array
public function getForEdit(Purchase $purchase): array
{
$purchase->load([
'purchaseItems' => fn ($q) => $q
->orderByRaw('(SELECT variant FROM raw_material_prices WHERE raw_material_prices.id = purchase_items.raw_material_price_id)'),
'purchaseItems.rawMaterialPrice.rawMaterial',
'supplier',
]);

View File

@ -30,7 +30,9 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
->with([
'createdBy:id',
'createdBy.userProfile:id,user_id,full_name',
'restockItems:id,restock_id,product_variant_id,quantity,unit_price,subtotal',
'restockItems' => fn ($q) => $q
->select('id', 'restock_id', 'product_variant_id', 'quantity', 'unit_price', 'subtotal')
->orderByRaw('(SELECT name FROM product_variants WHERE product_variants.id = restock_items.product_variant_id)'),
'restockItems.productVariant:id,product_id,name,stock,reject_stock,retail_stock',
'restockItems.productVariant.product:id,name',
])
@ -89,7 +91,11 @@ public function getForCreate(): array
public function getForEdit(Restock $restock): array
{
$restock->load('restockItems.productVariant.product');
$restock->load([
'restockItems' => fn ($q) => $q
->orderByRaw('(SELECT name FROM product_variants WHERE product_variants.id = restock_items.product_variant_id)'),
'restockItems.productVariant.product',
]);
$media = $restock->getFirstMedia('photos');

View File

@ -360,7 +360,7 @@ export default function PurchaseCreate({ data }: Props) {
}
}
return lines;
return lines.sort((a, b) => a.title.localeCompare(b.title));
}
return variants

View File

@ -301,7 +301,7 @@ export default function PurchaseEdit({ purchase, data }: Props) {
}
}
return lines;
return lines.sort((a, b) => a.title.localeCompare(b.title));
}
return variants

View File

@ -188,7 +188,7 @@ return 0;
}
}
return lines;
return lines.sort((a, b) => a.title.localeCompare(b.title));
})();
function formatQuantity(value: number): string {

View File

@ -162,7 +162,7 @@ return 0;
}
}
return lines;
return lines.sort((a, b) => a.title.localeCompare(b.title));
})();
function formatQuantity(value: number): string {