From b70a40af4df1680d97dc5b6c946f61e6f244a8d7 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Wed, 5 Aug 2026 20:26:58 +0700 Subject: [PATCH] feat: implement sorting for lines in purchase and restock create/edit components; enhance user experience --- app/Models/Product.php | 2 +- app/Models/ProductVariant.php | 3 +++ app/Models/RawMaterialPrice.php | 3 +++ app/Models/Scopes/ProductVariantScope.php | 15 +++++++++++++++ app/Models/Scopes/RawMaterialPriceScope.php | 15 +++++++++++++++ app/Services/Admin/Manage/PurchaseService.php | 6 +++++- app/Services/Admin/Manage/RestockService.php | 10 ++++++++-- .../js/pages/admin/manage/purchase/create.tsx | 2 +- resources/js/pages/admin/manage/purchase/edit.tsx | 2 +- .../js/pages/admin/manage/restock/create.tsx | 2 +- resources/js/pages/admin/manage/restock/edit.tsx | 2 +- 11 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 app/Models/Scopes/ProductVariantScope.php create mode 100644 app/Models/Scopes/RawMaterialPriceScope.php diff --git a/app/Models/Product.php b/app/Models/Product.php index d6be07b..5f3d78e 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -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(), ); } diff --git a/app/Models/ProductVariant.php b/app/Models/ProductVariant.php index 97f10b7..ab81321 100644 --- a/app/Models/ProductVariant.php +++ b/app/Models/ProductVariant.php @@ -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; diff --git a/app/Models/RawMaterialPrice.php b/app/Models/RawMaterialPrice.php index 9522431..33bed38 100644 --- a/app/Models/RawMaterialPrice.php +++ b/app/Models/RawMaterialPrice.php @@ -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; diff --git a/app/Models/Scopes/ProductVariantScope.php b/app/Models/Scopes/ProductVariantScope.php new file mode 100644 index 0000000..b04a749 --- /dev/null +++ b/app/Models/Scopes/ProductVariantScope.php @@ -0,0 +1,15 @@ +orderBy('name'); + } +} diff --git a/app/Models/Scopes/RawMaterialPriceScope.php b/app/Models/Scopes/RawMaterialPriceScope.php new file mode 100644 index 0000000..1bb91ca --- /dev/null +++ b/app/Models/Scopes/RawMaterialPriceScope.php @@ -0,0 +1,15 @@ +orderBy('variant'); + } +} diff --git a/app/Services/Admin/Manage/PurchaseService.php b/app/Services/Admin/Manage/PurchaseService.php index 804bef7..c4f5e5c 100644 --- a/app/Services/Admin/Manage/PurchaseService.php +++ b/app/Services/Admin/Manage/PurchaseService.php @@ -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', ]); diff --git a/app/Services/Admin/Manage/RestockService.php b/app/Services/Admin/Manage/RestockService.php index 3a3c14b..c945876 100644 --- a/app/Services/Admin/Manage/RestockService.php +++ b/app/Services/Admin/Manage/RestockService.php @@ -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'); diff --git a/resources/js/pages/admin/manage/purchase/create.tsx b/resources/js/pages/admin/manage/purchase/create.tsx index 42cfaf4..bda4e4b 100644 --- a/resources/js/pages/admin/manage/purchase/create.tsx +++ b/resources/js/pages/admin/manage/purchase/create.tsx @@ -360,7 +360,7 @@ export default function PurchaseCreate({ data }: Props) { } } - return lines; + return lines.sort((a, b) => a.title.localeCompare(b.title)); } return variants diff --git a/resources/js/pages/admin/manage/purchase/edit.tsx b/resources/js/pages/admin/manage/purchase/edit.tsx index a1006f7..6c6be2f 100644 --- a/resources/js/pages/admin/manage/purchase/edit.tsx +++ b/resources/js/pages/admin/manage/purchase/edit.tsx @@ -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 diff --git a/resources/js/pages/admin/manage/restock/create.tsx b/resources/js/pages/admin/manage/restock/create.tsx index 3d05434..5fbd143 100644 --- a/resources/js/pages/admin/manage/restock/create.tsx +++ b/resources/js/pages/admin/manage/restock/create.tsx @@ -188,7 +188,7 @@ return 0; } } - return lines; + return lines.sort((a, b) => a.title.localeCompare(b.title)); })(); function formatQuantity(value: number): string { diff --git a/resources/js/pages/admin/manage/restock/edit.tsx b/resources/js/pages/admin/manage/restock/edit.tsx index 6e18e21..0d12591 100644 --- a/resources/js/pages/admin/manage/restock/edit.tsx +++ b/resources/js/pages/admin/manage/restock/edit.tsx @@ -162,7 +162,7 @@ return 0; } } - return lines; + return lines.sort((a, b) => a.title.localeCompare(b.title)); })(); function formatQuantity(value: number): string {