feat: add total price calculations for raw materials and products in analysis components

This commit is contained in:
Yoga Pangestu 2026-08-15 20:16:49 +07:00
parent 25a316ccf0
commit ef136bd1e7
3 changed files with 19 additions and 3 deletions

View File

@ -8,6 +8,7 @@
use App\Enums\OrderStatus; use App\Enums\OrderStatus;
use App\Enums\PaymentType; use App\Enums\PaymentType;
use App\Enums\PayrollStatus; use App\Enums\PayrollStatus;
use App\Enums\PriceType;
use App\Enums\RawMaterialUnit; use App\Enums\RawMaterialUnit;
use App\Enums\Role; use App\Enums\Role;
use App\Models\Attendance; use App\Models\Attendance;
@ -18,6 +19,7 @@
use App\Models\LeaveRequest; use App\Models\LeaveRequest;
use App\Models\Order; use App\Models\Order;
use App\Models\Payroll; use App\Models\Payroll;
use App\Models\ProductPrice;
use App\Models\ProductVariant; use App\Models\ProductVariant;
use App\Models\Purchase; use App\Models\Purchase;
use App\Models\RawMaterialPrice; use App\Models\RawMaterialPrice;
@ -207,10 +209,11 @@ public function getRawMaterialStock(): array
{ {
$items = RawMaterialPrice::query() $items = RawMaterialPrice::query()
->join('raw_materials', 'raw_material_prices.raw_material_id', '=', 'raw_materials.id') ->join('raw_materials', 'raw_material_prices.raw_material_id', '=', 'raw_materials.id')
->select('raw_material_prices.stock', 'raw_materials.unit') ->select('raw_material_prices.stock', 'raw_material_prices.price', 'raw_materials.unit')
->get(); ->get();
$totalQty = $items->sum('stock'); $totalQty = $items->sum('stock');
$totalPrice = $items->sum(fn ($i) => $i->stock * $i->price);
$byUnit = [ $byUnit = [
'yard' => $items->filter(fn ($i) => $i->unit === RawMaterialUnit::YARD->value)->sum('stock'), 'yard' => $items->filter(fn ($i) => $i->unit === RawMaterialUnit::YARD->value)->sum('stock'),
@ -220,6 +223,7 @@ public function getRawMaterialStock(): array
return [ return [
'total_stock' => $totalQty, 'total_stock' => $totalQty,
'total_price' => $totalPrice,
'by_unit' => $byUnit, 'by_unit' => $byUnit,
]; ];
} }
@ -227,15 +231,21 @@ public function getRawMaterialStock(): array
public function getProductStock(): array public function getProductStock(): array
{ {
$variants = ProductVariant::query() $variants = ProductVariant::query()
->select('stock', 'reject_stock', 'retail_stock') ->leftJoin('product_prices', function ($join) {
$join->on('product_variants.id', '=', 'product_prices.variant_id')
->where('product_prices.type', '=', PriceType::RETAIL->value);
})
->select('product_variants.stock', 'product_variants.reject_stock', 'product_variants.retail_stock', 'product_prices.price')
->get(); ->get();
$totalStock = $variants->sum('stock'); $totalStock = $variants->sum('stock');
$totalRejectStock = $variants->sum('reject_stock'); $totalRejectStock = $variants->sum('reject_stock');
$totalRetailStock = $variants->sum('retail_stock'); $totalRetailStock = $variants->sum('retail_stock');
$totalPrice = $variants->sum(fn ($v) => ($v->stock + $v->reject_stock + $v->retail_stock) * ($v->price ?? 0));
return [ return [
'total_stock' => $totalStock + $totalRejectStock + $totalRetailStock, 'total_stock' => $totalStock + $totalRejectStock + $totalRetailStock,
'total_price' => $totalPrice,
'by_type' => [ 'by_type' => [
'stock' => $totalStock, 'stock' => $totalStock,
'reject_stock' => $totalRejectStock, 'reject_stock' => $totalRejectStock,

View File

@ -31,7 +31,7 @@ export function StatCard({ title, icon: Icon, mainLabel, mainValue, subLabel, de
{subLabel && <p className="text-xs text-muted-foreground">{subLabel}</p>} {subLabel && <p className="text-xs text-muted-foreground">{subLabel}</p>}
{description && <p className="mt-1 text-[10px] text-muted-foreground italic">{description}</p>} {description && <p className="mt-1 text-[10px] text-muted-foreground italic">{description}</p>}
{items.length > 0 && ( {items.length > 0 && (
<div className={cn('mt-3 grid gap-2', cols === 2 && 'grid-cols-2', cols === 3 && 'grid-cols-3', cols === 4 && 'grid-cols-4')}> <div className={cn('mt-3 grid gap-2', cols === 2 && 'grid-cols-2', cols === 3 && 'grid-cols-2 sm:grid-cols-3', cols === 4 && 'grid-cols-2 sm:grid-cols-4')}>
{items.map((item, index) => ( {items.map((item, index) => (
<div key={index}> <div key={index}>
<p className="text-xs text-muted-foreground">{item.label}</p> <p className="text-xs text-muted-foreground">{item.label}</p>

View File

@ -67,6 +67,7 @@ type AnalysisProps = {
}; };
rawMaterialStock: { rawMaterialStock: {
total_stock: number; total_stock: number;
total_price: number;
by_unit: { by_unit: {
yard: number; yard: number;
meter: number; meter: number;
@ -75,6 +76,7 @@ type AnalysisProps = {
}; };
productStock: { productStock: {
total_stock: number; total_stock: number;
total_price: number;
by_type: { by_type: {
stock?: number; stock?: number;
reject_stock?: number; reject_stock?: number;
@ -622,7 +624,9 @@ export default function Analysis({
{ label: 'Yard', value: rawMaterialStock.by_unit?.yard?.toLocaleString('id-ID') ?? '0' }, { label: 'Yard', value: rawMaterialStock.by_unit?.yard?.toLocaleString('id-ID') ?? '0' },
{ label: 'Meter', value: rawMaterialStock.by_unit?.meter?.toLocaleString('id-ID') ?? '0' }, { label: 'Meter', value: rawMaterialStock.by_unit?.meter?.toLocaleString('id-ID') ?? '0' },
{ label: 'Kg', value: rawMaterialStock.by_unit?.kilogram?.toLocaleString('id-ID') ?? '0' }, { label: 'Kg', value: rawMaterialStock.by_unit?.kilogram?.toLocaleString('id-ID') ?? '0' },
{ label: 'Total Harga', value: `Rp${formatRupiah(rawMaterialStock.total_price)}` },
]} ]}
cols={4}
/> />
)} )}
@ -637,7 +641,9 @@ export default function Analysis({
{ label: 'Bagus', value: (productStock.by_type?.stock ?? 0).toLocaleString('id-ID') }, { label: 'Bagus', value: (productStock.by_type?.stock ?? 0).toLocaleString('id-ID') },
{ label: 'Reject', value: (productStock.by_type?.reject_stock ?? 0).toLocaleString('id-ID') }, { label: 'Reject', value: (productStock.by_type?.reject_stock ?? 0).toLocaleString('id-ID') },
{ label: 'Ecer', value: (productStock.by_type?.retail_stock ?? 0).toLocaleString('id-ID') }, { label: 'Ecer', value: (productStock.by_type?.retail_stock ?? 0).toLocaleString('id-ID') },
{ label: 'Total Harga', value: `Rp${formatRupiah(productStock.total_price)}` },
]} ]}
cols={4}
/> />
)} )}
</div> </div>