Compare commits

..

No commits in common. "a29e6af43085371170485b4536df4db1f998c7b0" and "2e578cd9766459bb414eaed34167dc1e58b4853a" have entirely different histories.

16 changed files with 716 additions and 702 deletions

View File

@ -95,8 +95,6 @@ function () use ($cashAccount, $validated, $user): CashTransaction {
'Gagal melakukan setoran kas', 'Gagal melakukan setoran kas',
); );
$this->cacheForget('finance:default_account');
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
'💰 Setoran Kas', '💰 Setoran Kas',
"Setoran kas baru {$transaction->amount_formatted} dengan keterangan: {$transaction->description} oleh {$user->profile?->full_name}.", "Setoran kas baru {$transaction->amount_formatted} dengan keterangan: {$transaction->description} oleh {$user->profile?->full_name}.",
@ -140,8 +138,6 @@ function () use ($cashAccount, $validated, $user): CashTransaction {
'Gagal melakukan tarik kas', 'Gagal melakukan tarik kas',
); );
$this->cacheForget('finance:default_account');
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
'🏦 Tarik Kas', '🏦 Tarik Kas',
"Tarik kas {$transaction->amount_formatted} dengan keterangan: {$transaction->description} oleh {$user->profile?->full_name}.", "Tarik kas {$transaction->amount_formatted} dengan keterangan: {$transaction->description} oleh {$user->profile?->full_name}.",
@ -159,7 +155,7 @@ public function recordOutgoing(
User $user, User $user,
?CashAccount $cashAccount = null, ?CashAccount $cashAccount = null,
): CashTransaction { ): CashTransaction {
$transaction = $this->runInTransaction( return $this->runInTransaction(
function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction { function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
$account = CashAccount::query()->lockForUpdate()->findOrFail( $account = CashAccount::query()->lockForUpdate()->findOrFail(
($cashAccount ?? $this->getDefaultAccount())->id, ($cashAccount ?? $this->getDefaultAccount())->id,
@ -191,10 +187,6 @@ function () use ($reference, $amount, $description, $user, $cashAccount): CashTr
}, },
'Gagal mencatat transaksi keluar kas', 'Gagal mencatat transaksi keluar kas',
); );
$this->cacheForget('finance:default_account');
return $transaction;
} }
public function recordIncoming( public function recordIncoming(
@ -204,7 +196,7 @@ public function recordIncoming(
User $user, User $user,
?CashAccount $cashAccount = null, ?CashAccount $cashAccount = null,
): CashTransaction { ): CashTransaction {
$transaction = $this->runInTransaction( return $this->runInTransaction(
function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction { function () use ($reference, $amount, $description, $user, $cashAccount): CashTransaction {
$account = CashAccount::query()->lockForUpdate()->findOrFail( $account = CashAccount::query()->lockForUpdate()->findOrFail(
($cashAccount ?? $this->getDefaultAccount())->id, ($cashAccount ?? $this->getDefaultAccount())->id,
@ -230,10 +222,6 @@ function () use ($reference, $amount, $description, $user, $cashAccount): CashTr
}, },
'Gagal mencatat transaksi masuk kas', 'Gagal mencatat transaksi masuk kas',
); );
$this->cacheForget('finance:default_account');
return $transaction;
} }
public function updateDeposit(CashTransaction $transaction, array $validated, User $user): void public function updateDeposit(CashTransaction $transaction, array $validated, User $user): void
@ -262,8 +250,6 @@ function () use ($transaction, $validated): void {
'Gagal memperbarui setoran kas', 'Gagal memperbarui setoran kas',
); );
$this->cacheForget('finance:default_account');
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
'✏️ Transaksi Kas Diperbarui', '✏️ Transaksi Kas Diperbarui',
"Transaksi kas dengan keterangan {$transaction->description} diperbarui menjadi senilai {$transaction->amount_formatted} oleh {$user->profile?->full_name}.", "Transaksi kas dengan keterangan {$transaction->description} diperbarui menjadi senilai {$transaction->amount_formatted} oleh {$user->profile?->full_name}.",
@ -283,6 +269,7 @@ function () use ($transaction): void {
$account = $transaction->cashAccount; $account = $transaction->cashAccount;
$transaction->clearMediaCollection('photos');
$transaction->delete(); $transaction->delete();
$this->recalculateBalances($account); $this->recalculateBalances($account);
@ -296,8 +283,6 @@ function () use ($transaction): void {
'Gagal menghapus transaksi kas', 'Gagal menghapus transaksi kas',
); );
$this->cacheForget('finance:default_account');
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
'🗑️ Transaksi Kas Dihapus', '🗑️ Transaksi Kas Dihapus',
"Transaksi kas senilai {$amountFormatted} dengan keterangan {$description} telah dihapus oleh {$user->profile?->full_name}.", "Transaksi kas senilai {$amountFormatted} dengan keterangan {$description} telah dihapus oleh {$user->profile?->full_name}.",
@ -332,8 +317,6 @@ function () use ($transaction, $amount, $description): void {
}, },
'Gagal memperbarui transaksi kas referensi', 'Gagal memperbarui transaksi kas referensi',
); );
$this->cacheForget('finance:default_account');
} }
public function deleteReferencedTransaction(CashTransaction $transaction): void public function deleteReferencedTransaction(CashTransaction $transaction): void
@ -355,8 +338,6 @@ function () use ($transaction): void {
}, },
'Gagal menghapus transaksi kas referensi', 'Gagal menghapus transaksi kas referensi',
); );
$this->cacheForget('finance:default_account');
} }
private function recalculateBalances(CashAccount $cashAccount): void private function recalculateBalances(CashAccount $cashAccount): void

View File

@ -133,6 +133,7 @@ function () use ($expense): void {
$this->cashService->deleteReferencedTransaction($expense->cashTransaction); $this->cashService->deleteReferencedTransaction($expense->cashTransaction);
} }
$expense->clearMediaCollection('photos');
$expense->delete(); $expense->delete();
}, },
'Gagal menghapus pengeluaran', 'Gagal menghapus pengeluaran',

View File

@ -172,6 +172,8 @@ public function delete(Attendance $attendance, User $user): void
$this->runInTransaction( $this->runInTransaction(
function () use ($attendance): void { function () use ($attendance): void {
$attendance->clearMediaCollection('checkin');
$attendance->clearMediaCollection('checkout');
$attendance->delete(); $attendance->delete();
}, },
'Gagal menghapus presensi', 'Gagal menghapus presensi',

View File

@ -128,7 +128,6 @@ function () use ($validated): User {
'Gagal membuat karyawan', 'Gagal membuat karyawan',
); );
$this->cacheForget('system:assignable_roles');
$this->cacheForgetByPattern('hr:employees:*'); $this->cacheForgetByPattern('hr:employees:*');
$this->notifyOwner( $this->notifyOwner(
@ -190,7 +189,6 @@ function () use ($validated, $user, $employee): void {
'Gagal memperbarui karyawan', 'Gagal memperbarui karyawan',
); );
$this->cacheForget('system:assignable_roles');
$this->cacheForgetByPattern('hr:employees:*'); $this->cacheForgetByPattern('hr:employees:*');
$this->notifyOwner( $this->notifyOwner(
@ -215,7 +213,6 @@ function () use ($user, $validated): void {
'Gagal memperbarui status karyawan', 'Gagal memperbarui status karyawan',
); );
$this->cacheForget('system:assignable_roles');
$this->cacheForgetByPattern('hr:employees:*'); $this->cacheForgetByPattern('hr:employees:*');
$statusLabel = $validated['is_active'] ? 'aktif' : 'nonaktif'; $statusLabel = $validated['is_active'] ? 'aktif' : 'nonaktif';
@ -240,7 +237,6 @@ function () use ($user): void {
'Gagal mereset kata sandi karyawan', 'Gagal mereset kata sandi karyawan',
); );
$this->cacheForget('system:assignable_roles');
$this->cacheForgetByPattern('hr:employees:*'); $this->cacheForgetByPattern('hr:employees:*');
$this->notifyOwner( $this->notifyOwner(
@ -263,7 +259,6 @@ function () use ($user): void {
'Gagal menghapus karyawan', 'Gagal menghapus karyawan',
); );
$this->cacheForget('system:assignable_roles');
$this->cacheForgetByPattern('hr:employees:*'); $this->cacheForgetByPattern('hr:employees:*');
$this->notifyOwner( $this->notifyOwner(

View File

@ -680,6 +680,7 @@ function () use ($cutting): void {
$cutting->materials()->delete(); $cutting->materials()->delete();
$cutting->results()->delete(); $cutting->results()->delete();
$cutting->clearMediaCollection('images');
$cutting->delete(); $cutting->delete();
}, },
'Gagal menghapus proses cutting', 'Gagal menghapus proses cutting',

View File

@ -716,6 +716,7 @@ private function rejectCreate(OwnerVerificationRequest $verificationRequest): vo
$this->runInTransaction( $this->runInTransaction(
function () use ($purchase): void { function () use ($purchase): void {
$purchase->clearMediaCollection('photos');
$purchase->items()->delete(); $purchase->items()->delete();
$purchase->delete(); $purchase->delete();
}, },
@ -733,6 +734,7 @@ function () use ($purchase): void {
$this->decrementStock($item); $this->decrementStock($item);
} }
$purchase->clearMediaCollection('photos');
$purchase->items()->delete(); $purchase->items()->delete();
$purchase->delete(); $purchase->delete();
}, },

View File

@ -573,6 +573,7 @@ private function rejectCreate(OwnerVerificationRequest $verificationRequest): vo
$this->runInTransaction( $this->runInTransaction(
function () use ($restock): void { function () use ($restock): void {
$restock->clearMediaCollection('photos');
$restock->items()->delete(); $restock->items()->delete();
$restock->delete(); $restock->delete();
}, },
@ -592,6 +593,7 @@ function () use ($restock): void {
$this->decrementStock($item, $stockType); $this->decrementStock($item, $stockType);
} }
$restock->clearMediaCollection('photos');
$restock->items()->delete(); $restock->items()->delete();
$restock->delete(); $restock->delete();
}, },

View File

@ -156,7 +156,9 @@ public function submitVerification(
} }
$this->cacheForgetByPattern('manage:stocks:*'); $this->cacheForgetByPattern('manage:stocks:*');
$this->cacheForgetByPattern('prices:*'); if ($isOwner) {
$this->cacheForgetByPattern('prices:*');
}
} }
public function approveVerification( public function approveVerification(

View File

@ -254,7 +254,6 @@ function () use ($validated, $product, $user, $isOwner): void {
); );
$this->cacheForgetByPattern('master:products:*'); $this->cacheForgetByPattern('master:products:*');
$this->cacheForgetByPattern('prices:*');
$this->cacheForget('homepage:page_data'); $this->cacheForget('homepage:page_data');
if ($isOwner) { if ($isOwner) {
@ -329,7 +328,6 @@ public function delete(Product $product, User $user): void
$name = $product->name; $name = $product->name;
$this->applyDeleteSubject($product); $this->applyDeleteSubject($product);
$this->cacheForgetByPattern('master:products:*'); $this->cacheForgetByPattern('master:products:*');
$this->cacheForgetByPattern('prices:*');
$this->cacheForget('homepage:page_data'); $this->cacheForget('homepage:page_data');
$this->notifyOwner( $this->notifyOwner(
@ -437,7 +435,6 @@ public function applyVerificationRequest(OwnerVerificationRequest $verificationR
}; };
$this->cacheForgetByPattern('master:products:*'); $this->cacheForgetByPattern('master:products:*');
$this->cacheForgetByPattern('prices:*');
} }
public function rejectVerificationRequest(OwnerVerificationRequest $verificationRequest): void public function rejectVerificationRequest(OwnerVerificationRequest $verificationRequest): void
@ -452,7 +449,6 @@ public function rejectVerificationRequest(OwnerVerificationRequest $verification
}; };
$this->cacheForgetByPattern('master:products:*'); $this->cacheForgetByPattern('master:products:*');
$this->cacheForgetByPattern('prices:*');
$this->cacheForget('homepage:page_data'); $this->cacheForget('homepage:page_data');
} }
@ -523,6 +519,7 @@ private function applyPayloadToProduct(
->whereNotIn('id', $submittedVariantIds) ->whereNotIn('id', $submittedVariantIds)
->get() ->get()
->each(function (ProductVariant $variant): void { ->each(function (ProductVariant $variant): void {
$variant->clearMediaCollection('images');
$variant->delete(); $variant->delete();
}); });
@ -589,6 +586,9 @@ private function applyDeleteSubject(Product $product): void
{ {
$this->runInTransaction( $this->runInTransaction(
function () use ($product): void { function () use ($product): void {
$product->variants()->each(function (ProductVariant $variant): void {
$variant->clearMediaCollection('images');
});
$product->variants()->delete(); $product->variants()->delete();
$product->categories()->detach(); $product->categories()->detach();
$product->delete(); $product->delete();
@ -656,6 +656,9 @@ private function rejectCreate(OwnerVerificationRequest $verificationRequest): vo
$this->runInTransaction( $this->runInTransaction(
function () use ($product): void { function () use ($product): void {
$product->variants()->each(function (ProductVariant $variant): void {
$variant->clearMediaCollection('images');
});
$product->variants()->delete(); $product->variants()->delete();
$product->categories()->detach(); $product->categories()->detach();
$product->delete(); $product->delete();

View File

@ -37,24 +37,6 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $st
->with('media') ->with('media')
->when($tableQuery['search'] !== '', function ($query) use ($tableQuery): void { ->when($tableQuery['search'] !== '', function ($query) use ($tableQuery): void {
$query->where('variant', 'like', "%{$tableQuery['search']}%"); $query->where('variant', 'like', "%{$tableQuery['search']}%");
})
->when($stockStatus === 'out_of_stock', fn ($q) => $q->where('stock', '<=', 0))
->when($stockStatus === 'low_stock', function ($q): void {
$q->where('stock', '>', 0)
->where(function ($q): void {
$q->orWhere(function ($q): void {
$q->whereHas('rawMaterial', fn ($q) => $q->where('unit', RawMaterialUnit::YARD->value))
->where('stock', '<', 20);
})
->orWhere(function ($q): void {
$q->whereHas('rawMaterial', fn ($q) => $q->where('unit', RawMaterialUnit::METER->value))
->where('stock', '<', 10);
})
->orWhere(function ($q): void {
$q->whereHas('rawMaterial', fn ($q) => $q->where('unit', RawMaterialUnit::KILOGRAM->value))
->where('stock', '<', 5);
});
});
}), }),
]) ])
->when(($tableQuery['search_id'] ?? '') !== '', function (Builder $query) use ($tableQuery): void { ->when(($tableQuery['search_id'] ?? '') !== '', function (Builder $query) use ($tableQuery): void {
@ -70,15 +52,21 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $st
$query->whereHas('prices', fn (Builder $priceQuery) => $priceQuery->where('stock', '<=', 0)); $query->whereHas('prices', fn (Builder $priceQuery) => $priceQuery->where('stock', '<=', 0));
}) })
->when($stockStatus === 'low_stock', function (Builder $query): void { ->when($stockStatus === 'low_stock', function (Builder $query): void {
$query->where(function (Builder $query): void { $minStock = [
$query->where('unit', RawMaterialUnit::YARD->value) RawMaterialUnit::YARD->value => 20,
->whereHas('prices', fn (Builder $q) => $q->where('stock', '>', 0)->where('stock', '<', 20)); RawMaterialUnit::METER->value => 10,
})->orWhere(function (Builder $query): void { RawMaterialUnit::KILOGRAM->value => 5,
$query->where('unit', RawMaterialUnit::METER->value) ];
->whereHas('prices', fn (Builder $q) => $q->where('stock', '>', 0)->where('stock', '<', 10));
})->orWhere(function (Builder $query): void { $query->whereHas('prices', function (Builder $priceQuery) use ($minStock): void {
$query->where('unit', RawMaterialUnit::KILOGRAM->value) $priceQuery->where('stock', '>', 0)->where(function (Builder $priceQuery) use ($minStock): void {
->whereHas('prices', fn (Builder $q) => $q->where('stock', '>', 0)->where('stock', '<', 5)); foreach (RawMaterialUnit::cases() as $unit) {
$priceQuery->orWhere(function (Builder $priceQuery) use ($unit, $minStock): void {
$priceQuery->whereHas('rawMaterial', fn (Builder $rawMaterialQuery) => $rawMaterialQuery->where('unit', $unit->value))
->where('stock', '<', $minStock[$unit->value]);
});
}
});
}); });
}); });
@ -286,6 +274,9 @@ private function applyDeleteSubject(RawMaterial $rawMaterial): void
{ {
$this->runInTransaction( $this->runInTransaction(
function () use ($rawMaterial): void { function () use ($rawMaterial): void {
$rawMaterial->prices()->each(function (RawMaterialPrice $price): void {
$price->clearMediaCollection('images');
});
$rawMaterial->prices()->delete(); $rawMaterial->prices()->delete();
$rawMaterial->delete(); $rawMaterial->delete();
}, },
@ -337,6 +328,7 @@ private function applyPayloadToRawMaterial(
->whereNotIn('id', $submittedPriceIds) ->whereNotIn('id', $submittedPriceIds)
->get() ->get()
->each(function (RawMaterialPrice $price): void { ->each(function (RawMaterialPrice $price): void {
$price->clearMediaCollection('images');
$price->delete(); $price->delete();
}); });
@ -382,6 +374,9 @@ private function rejectCreate(OwnerVerificationRequest $verificationRequest): vo
$this->runInTransaction( $this->runInTransaction(
function () use ($rawMaterial): void { function () use ($rawMaterial): void {
$rawMaterial->prices()->each(function (RawMaterialPrice $price): void {
$price->clearMediaCollection('images');
});
$rawMaterial->prices()->delete(); $rawMaterial->prices()->delete();
$rawMaterial->delete(); $rawMaterial->delete();
}, },

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
use App\Models\Category; use App\Models\Category;
use App\Models\Product; use App\Models\Product;
use App\Models\SystemConfiguration; use App\Models\SystemConfiguration;
use App\Services\Concerns\CachesQuery;
use App\Services\Manage\CuttingResultPriceResolver; use App\Services\Manage\CuttingResultPriceResolver;
use App\Services\System\Setting\HomepageSettingService; use App\Services\System\Setting\HomepageSettingService;
use App\Settings\SocialMediaSettings; use App\Settings\SocialMediaSettings;
@ -14,6 +15,8 @@
class HomepageService class HomepageService
{ {
use CachesQuery;
public function __construct( public function __construct(
private readonly CuttingResultPriceResolver $cuttingResultPriceResolver, private readonly CuttingResultPriceResolver $cuttingResultPriceResolver,
private readonly HomepageSettingService $homepageSettingService, private readonly HomepageSettingService $homepageSettingService,
@ -21,30 +24,32 @@ public function __construct(
public function pageData(): array public function pageData(): array
{ {
$categories = Category::getActiveWithProducts(); return $this->cacheRemember('homepage:page_data', 900, function () {
$products = $this->getProducts(); $categories = Category::getActiveWithProducts();
$products = $this->getProducts();
$configuration = SystemConfiguration::instance(); $configuration = SystemConfiguration::instance();
$logo = MediaPresenter::first($configuration, 'logo'); $logo = MediaPresenter::first($configuration, 'logo');
$logoUrl = $logo['url'] ?? null; $logoUrl = $logo['url'] ?? null;
$settings = app(SystemSettings::class); $settings = app(SystemSettings::class);
$socialSettings = app(SocialMediaSettings::class); $socialSettings = app(SocialMediaSettings::class);
return [ return [
'categories' => $categories, 'categories' => $categories,
'products' => $products, 'products' => $products,
'appName' => $settings->app_name ?? 'DST Collection', 'appName' => $settings->app_name ?? 'DST Collection',
'aboutApp' => $settings->about_app ?? '', 'aboutApp' => $settings->about_app ?? '',
'contactEmail' => $settings->email ?? '', 'contactEmail' => $settings->email ?? '',
'contactPhone' => $settings->phone ?? '', 'contactPhone' => $settings->phone ?? '',
'contactAddress' => $settings->address ?? '', 'contactAddress' => $settings->address ?? '',
'logoUrl' => $logoUrl, 'logoUrl' => $logoUrl,
'instagramUrl' => $socialSettings->instagram_url ?? null, 'instagramUrl' => $socialSettings->instagram_url ?? null,
'facebookUrl' => $socialSettings->facebook_url ?? null, 'facebookUrl' => $socialSettings->facebook_url ?? null,
'tiktokUrl' => $socialSettings->tiktok_url ?? null, 'tiktokUrl' => $socialSettings->tiktok_url ?? null,
'homepage' => $this->homepageSettingService->homepageData(), 'homepage' => $this->homepageSettingService->homepageData(),
]; ];
});
} }
private function getProducts(): array private function getProducts(): array

View File

@ -87,8 +87,6 @@ public function create(array $validated): void
]); ]);
} }
$this->cacheForget('system:permissions');
$this->cacheForget('system:assignable_roles');
$this->cacheForgetByPattern('system:roles:*'); $this->cacheForgetByPattern('system:roles:*');
} }
@ -116,8 +114,6 @@ public function update(Role $role, array $validated): void
]); ]);
} }
$this->cacheForget('system:permissions');
$this->cacheForget('system:assignable_roles');
$this->cacheForgetByPattern('system:roles:*'); $this->cacheForgetByPattern('system:roles:*');
} }
@ -125,8 +121,6 @@ public function delete(Role $role): void
{ {
$role->delete(); $role->delete();
$this->cacheForget('system:permissions');
$this->cacheForget('system:assignable_roles');
$this->cacheForgetByPattern('system:roles:*'); $this->cacheForgetByPattern('system:roles:*');
} }

View File

@ -16,7 +16,7 @@
*/ */
'ssr' => [ 'ssr' => [
'enabled' => false, 'enabled' => true,
'url' => 'http://127.0.0.1:13714', 'url' => 'http://127.0.0.1:13714',
// 'bundle' => base_path('bootstrap/ssr/ssr.mjs'), // 'bundle' => base_path('bootstrap/ssr/ssr.mjs'),

View File

@ -5,26 +5,24 @@ import { Toaster } from '@/components/ui/sonner';
import { useFlashToast } from '@/composables/useFlashToast'; import { useFlashToast } from '@/composables/useFlashToast';
import { restoreConnection } from '@/lib/thermal-printer/stable-transport'; import { restoreConnection } from '@/lib/thermal-printer/stable-transport';
if (typeof window !== 'undefined') { if ('serviceWorker' in navigator) {
if ('serviceWorker' in navigator) { navigator.serviceWorker
navigator.serviceWorker .register('/sw.js', { scope: '/' })
.register('/sw.js', { scope: '/' }) .then((reg) => {
.then((reg) => { console.log('[SW] Registered:', reg.scope);
console.log('[SW] Registered:', reg.scope); })
}) .catch((err) => {
.catch((err) => { console.error('[SW] Registration failed:', err);
console.error('[SW] Registration failed:', err); });
});
}
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
(window as any).deferredPwaPrompt = e;
});
void restoreConnection();
} }
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
(window as any).deferredPwaPrompt = e;
});
void restoreConnection();
const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
createInertiaApp({ createInertiaApp({

View File

@ -529,11 +529,11 @@ const productBarData = computed<ProductData[]>(() => {
function applyFilters() { function applyFilters() {
router.get( router.get(
admin.analysis.url(), admin.analysis.url({
{
start_date: startDate.value, start_date: startDate.value,
end_date: endDate.value, end_date: endDate.value,
}, }),
{},
{ {
preserveState: true, preserveState: true,
preserveScroll: true, preserveScroll: true,