feat: update media handling to use 'images' collection and improve path generation
- Refactored CustomPathGenerator to handle S3 keys and default paths more effectively. - Changed media collection references from 'photos' to 'images' across various services. - Updated methods to retrieve media URLs using the new path generation logic. - Enhanced transaction-related components to display associated images.
This commit is contained in:
parent
8377c25173
commit
e9faa6a322
@ -9,6 +9,16 @@ class CustomPathGenerator implements PathGenerator
|
||||
{
|
||||
public function getPath(Media $media): string
|
||||
{
|
||||
$s3Key = $media->getCustomProperty('s3_key');
|
||||
|
||||
if ($s3Key) {
|
||||
return dirname($s3Key).'/';
|
||||
}
|
||||
|
||||
if (str_contains($media->file_name, '/')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$model = $media->model;
|
||||
|
||||
if ($model && method_exists($model, 'getMediaPath')) {
|
||||
@ -20,20 +30,44 @@ public function getPath(Media $media): string
|
||||
|
||||
public function getPathForConversions(Media $media): string
|
||||
{
|
||||
return $this->getPath($media).'conversions/';
|
||||
$s3Key = $media->getCustomProperty('s3_key');
|
||||
$dir = $s3Key ? dirname($s3Key).'/' : $this->defaultPath($media);
|
||||
|
||||
return $dir.'conversions/';
|
||||
}
|
||||
|
||||
public function getPathForResponsiveImages(Media $media): string
|
||||
{
|
||||
return $this->getPath($media).'responsive/';
|
||||
$s3Key = $media->getCustomProperty('s3_key');
|
||||
$dir = $s3Key ? dirname($s3Key).'/' : $this->defaultPath($media);
|
||||
|
||||
return $dir.'responsive/';
|
||||
}
|
||||
|
||||
private function defaultPath(Media $media): string
|
||||
{
|
||||
$module = strtolower(class_basename($media->model_type));
|
||||
$date = $media->created_at->format('Y/m/d');
|
||||
$id = $media->id;
|
||||
$moduleMap = [
|
||||
'UserProfile' => 'user-profile',
|
||||
'Attendance' => 'attendance',
|
||||
'SystemConfiguration' => 'setting',
|
||||
'HomepageConfiguration' => 'homepage',
|
||||
'ProductVariant' => 'product',
|
||||
'Cutting' => 'cutting',
|
||||
'RawMaterialPrice' => 'raw-material',
|
||||
'CashTransaction' => 'cash',
|
||||
'Expense' => 'expense',
|
||||
'Order' => 'order',
|
||||
'Restock' => 'restock',
|
||||
'Purchase' => 'purchase',
|
||||
'OwnerVerificationRequest' => 'owner_verification_request',
|
||||
];
|
||||
|
||||
return "{$module}/{$date}/{$id}/";
|
||||
$modelClass = class_basename($media->model_type);
|
||||
$module = $moduleMap[$modelClass] ?? strtolower($modelClass);
|
||||
$collection = $media->collection_name;
|
||||
$date = $media->created_at->format('Y-m-d');
|
||||
$id = $media->model_id;
|
||||
|
||||
return "{$module}/{$collection}/{$date}/{$id}/";
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,10 +55,10 @@ public function rawMaterial(): BelongsTo
|
||||
|
||||
public function getPhotoUrlAttribute(): ?string
|
||||
{
|
||||
$media = $this->getFirstMedia('photos');
|
||||
$media = $this->getFirstMedia('images');
|
||||
|
||||
return $media
|
||||
? app(S3PresignedService::class)->getTemporaryUrl($media->file_name)
|
||||
? app(S3PresignedService::class)->getTemporaryUrl($media->getPath())
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ public function deposit(array $data): CashTransaction
|
||||
));
|
||||
|
||||
if (array_key_exists('receipt_key', $data)) {
|
||||
$this->syncReceipt($transaction, $data['receipt_key'] ?? null, 'receipts', 'cash_transaction_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
$this->syncReceipt($transaction, $data['receipt_key'] ?? null, 'photos', 'cash_transaction_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
}
|
||||
|
||||
NotificationService::notify(
|
||||
@ -78,7 +78,7 @@ public function withdrawal(array $data): CashTransaction
|
||||
));
|
||||
|
||||
if (array_key_exists('receipt_key', $data)) {
|
||||
$this->syncReceipt($transaction, $data['receipt_key'] ?? null, 'receipts', 'cash_transaction_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
$this->syncReceipt($transaction, $data['receipt_key'] ?? null, 'photos', 'cash_transaction_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
}
|
||||
|
||||
NotificationService::notify(
|
||||
@ -123,7 +123,7 @@ public function update(CashTransaction $transaction, array $data): CashTransacti
|
||||
]);
|
||||
|
||||
if (array_key_exists('receipt_key', $data)) {
|
||||
$this->syncReceipt($transaction, $data['receipt_key'] ?? null, 'receipts', 'cash_transaction_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
$this->syncReceipt($transaction, $data['receipt_key'] ?? null, 'photos', 'cash_transaction_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
@ -163,12 +163,12 @@ public function destroy(CashTransaction $transaction): bool
|
||||
|
||||
$cashAccount->update(['balance' => $newBalance]);
|
||||
|
||||
$media = $transaction->getFirstMedia('receipts');
|
||||
$media = $transaction->getFirstMedia('photos');
|
||||
if ($media) {
|
||||
Cache::forget("cash_transaction_receipt_{$media->id}");
|
||||
}
|
||||
|
||||
$transaction->clearMediaCollection('receipts');
|
||||
$transaction->clearMediaCollection('photos');
|
||||
|
||||
$deleted = $transaction->delete();
|
||||
|
||||
@ -187,7 +187,7 @@ public function destroy(CashTransaction $transaction): bool
|
||||
|
||||
private function formatTransaction(CashTransaction $transaction): array
|
||||
{
|
||||
$media = $transaction->getFirstMedia('receipts');
|
||||
$media = $transaction->getFirstMedia('photos');
|
||||
|
||||
if (! $media) {
|
||||
return $transaction->toArray() + [
|
||||
@ -196,11 +196,7 @@ private function formatTransaction(CashTransaction $transaction): array
|
||||
];
|
||||
}
|
||||
|
||||
$s3Key = $media->file_name;
|
||||
|
||||
if (str_starts_with($s3Key, '/') || ! str_contains($s3Key, '/')) {
|
||||
$s3Key = $media->getPath();
|
||||
}
|
||||
$s3Key = $media->getCustomProperty('s3_key') ?? $media->getPath();
|
||||
|
||||
return $transaction->toArray() + [
|
||||
'receipt_key' => $s3Key,
|
||||
|
||||
@ -53,7 +53,7 @@ public function store(array $data): Expense
|
||||
]);
|
||||
|
||||
if (array_key_exists('receipt_key', $data)) {
|
||||
$this->syncReceipt($expense, $data['receipt_key'] ?? null, 'receipts', 'expense_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
$this->syncReceipt($expense, $data['receipt_key'] ?? null, 'photos', 'expense_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
}
|
||||
|
||||
return $expense;
|
||||
@ -100,7 +100,7 @@ public function update(Expense $expense, array $data): Expense
|
||||
]);
|
||||
|
||||
if (array_key_exists('receipt_key', $data)) {
|
||||
$this->syncReceipt($expense, $data['receipt_key'] ?? null, 'receipts', 'expense_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
$this->syncReceipt($expense, $data['receipt_key'] ?? null, 'photos', 'expense_receipt', $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||
}
|
||||
|
||||
return $expense;
|
||||
@ -125,12 +125,12 @@ public function destroy(Expense $expense): bool
|
||||
type: CashTransactionType::DEPOSIT,
|
||||
);
|
||||
|
||||
$media = $expense->getFirstMedia('receipts');
|
||||
$media = $expense->getFirstMedia('photos');
|
||||
if ($media) {
|
||||
Cache::forget("expense_receipt_{$media->id}");
|
||||
}
|
||||
|
||||
$expense->clearMediaCollection('receipts');
|
||||
$expense->clearMediaCollection('photos');
|
||||
|
||||
$deleted = $expense->delete();
|
||||
|
||||
@ -149,7 +149,7 @@ public function destroy(Expense $expense): bool
|
||||
|
||||
private function formatExpense(Expense $expense): array
|
||||
{
|
||||
$media = $expense->getFirstMedia('receipts');
|
||||
$media = $expense->getFirstMedia('photos');
|
||||
|
||||
if (! $media) {
|
||||
return $expense->toArray() + [
|
||||
@ -158,11 +158,7 @@ private function formatExpense(Expense $expense): array
|
||||
];
|
||||
}
|
||||
|
||||
$s3Key = $media->file_name;
|
||||
|
||||
if (str_starts_with($s3Key, '/') || ! str_contains($s3Key, '/')) {
|
||||
$s3Key = $media->getPath();
|
||||
}
|
||||
$s3Key = $media->getCustomProperty('s3_key') ?? $media->getPath();
|
||||
|
||||
$cacheKey = "expense_receipt_{$media->id}";
|
||||
$receiptUrl = Cache::remember($cacheKey, now()->addMinutes(55), function () use ($s3Key) {
|
||||
|
||||
@ -168,7 +168,7 @@ public function checkIn(array $data): Attendance
|
||||
]);
|
||||
|
||||
if (! empty($data['photo'])) {
|
||||
$this->registerMediaFromBase64($attendance, $data['photo'], 'check-in', 'attendances');
|
||||
$this->registerMediaFromBase64($attendance, $data['photo'], 'checkin', 'attendances');
|
||||
}
|
||||
|
||||
NotificationService::notify(
|
||||
@ -190,7 +190,7 @@ public function checkOut(Attendance $attendance, array $data): Attendance
|
||||
]);
|
||||
|
||||
if (! empty($data['photo'])) {
|
||||
$this->registerMediaFromBase64($attendance, $data['photo'], 'check-out', 'attendances');
|
||||
$this->registerMediaFromBase64($attendance, $data['photo'], 'checkout', 'attendances');
|
||||
}
|
||||
|
||||
NotificationService::notify(
|
||||
@ -303,15 +303,15 @@ private function formatAttendance(Attendance $attendance): array
|
||||
$toArray['work_duration_minutes'] = $checkIn->diffInMinutes($end);
|
||||
}
|
||||
|
||||
$checkInMedia = $attendance->getFirstMedia('check-in');
|
||||
$checkOutMedia = $attendance->getFirstMedia('check-out');
|
||||
$checkInMedia = $attendance->getFirstMedia('checkin');
|
||||
$checkOutMedia = $attendance->getFirstMedia('checkout');
|
||||
|
||||
$toArray['check_in_photo'] = $checkInMedia
|
||||
? Cache::remember("attendance_check_in_{$checkInMedia->id}", now()->addMinutes(55), fn () => $this->s3Service->getTemporaryUrl($checkInMedia->file_name))
|
||||
? Cache::remember("attendance_check_in_{$checkInMedia->id}", now()->addMinutes(55), fn () => $this->s3Service->getTemporaryUrl($checkInMedia->getPath()))
|
||||
: null;
|
||||
|
||||
$toArray['check_out_photo'] = $checkOutMedia
|
||||
? Cache::remember("attendance_check_out_{$checkOutMedia->id}", now()->addMinutes(55), fn () => $this->s3Service->getTemporaryUrl($checkOutMedia->file_name))
|
||||
? Cache::remember("attendance_check_out_{$checkOutMedia->id}", now()->addMinutes(55), fn () => $this->s3Service->getTemporaryUrl($checkOutMedia->getPath()))
|
||||
: null;
|
||||
|
||||
return $toArray;
|
||||
|
||||
@ -42,16 +42,16 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
->paginate($perPage);
|
||||
|
||||
$paginator->getCollection()->each(function (Cutting $cutting) {
|
||||
$cuttingMedia = $cutting->getFirstMedia('photos');
|
||||
$cuttingMedia = $cutting->getFirstMedia('images');
|
||||
$cutting->photo_url = $cuttingMedia
|
||||
? $this->s3Service->getTemporaryUrl($cuttingMedia->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($cuttingMedia->getPath())
|
||||
: null;
|
||||
|
||||
$cutting->cuttingMaterials->each(function (CuttingMaterial $material) {
|
||||
$media = $material->rawMaterialPrice?->getFirstMedia('photos');
|
||||
$media = $material->rawMaterialPrice?->getFirstMedia('images');
|
||||
if ($material->rawMaterialPrice) {
|
||||
$material->rawMaterialPrice->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->getPath())
|
||||
: null;
|
||||
}
|
||||
});
|
||||
@ -71,7 +71,7 @@ public function getForEdit(Cutting $cutting): array
|
||||
$result = $cutting->cuttingResults->first();
|
||||
|
||||
$materials = $cutting->cuttingMaterials->map(function (CuttingMaterial $material) {
|
||||
$media = $material->rawMaterialPrice?->getFirstMedia('photos');
|
||||
$media = $material->rawMaterialPrice?->getFirstMedia('images');
|
||||
|
||||
return [
|
||||
'id' => $material->id,
|
||||
@ -81,7 +81,7 @@ public function getForEdit(Cutting $cutting): array
|
||||
'combination_id' => $material->combination_id,
|
||||
'variant' => $material->rawMaterialPrice?->variant,
|
||||
'photo_url' => $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->getPath())
|
||||
: null,
|
||||
];
|
||||
});
|
||||
@ -99,10 +99,10 @@ public function getForEdit(Cutting $cutting): array
|
||||
];
|
||||
});
|
||||
|
||||
$cuttingMedia = $cutting->getFirstMedia('photos');
|
||||
$photoKey = $cuttingMedia?->file_name;
|
||||
$cuttingMedia = $cutting->getFirstMedia('images');
|
||||
$photoKey = $cuttingMedia?->getCustomProperty('s3_key') ?? $cuttingMedia?->file_name;
|
||||
$photoUrl = $cuttingMedia
|
||||
? $this->s3Service->getTemporaryUrl($cuttingMedia->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($cuttingMedia->getPath())
|
||||
: null;
|
||||
|
||||
return [
|
||||
@ -213,7 +213,7 @@ public function store(array $data): Cutting
|
||||
$this->registerMedia(
|
||||
model: $cutting,
|
||||
s3Key: $data['photo_key'],
|
||||
collectionName: 'photos',
|
||||
collectionName: 'images',
|
||||
orderColumn: 1,
|
||||
);
|
||||
}
|
||||
@ -337,7 +337,7 @@ public function destroy(Cutting $cutting): bool
|
||||
}
|
||||
}
|
||||
|
||||
$cutting->clearMediaCollection('photos');
|
||||
$cutting->clearMediaCollection('images');
|
||||
$cutting->cuttingResults()->delete();
|
||||
$cutting->cuttingMaterials()->delete();
|
||||
$cutting->cuttingMaterialCombinations()->delete();
|
||||
|
||||
@ -47,7 +47,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
$paginator->getCollection()->each(function (Purchase $purchase) {
|
||||
$purchaseMedia = $purchase->getFirstMedia('photos');
|
||||
$purchase->photo_url = $purchaseMedia
|
||||
? $this->s3Service->getTemporaryUrl($purchaseMedia->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($purchaseMedia->getPath())
|
||||
: null;
|
||||
|
||||
$purchase->purchaseItems->each(function (PurchaseItem $item) {
|
||||
@ -55,9 +55,9 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
return;
|
||||
}
|
||||
|
||||
$media = $item->rawMaterialPrice->getMedia('photos');
|
||||
$media = $item->rawMaterialPrice->getMedia('images');
|
||||
$item->rawMaterialPrice->photo_url = $media->first()
|
||||
? $this->s3Service->getTemporaryUrl($media->first()->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->first()->getPath())
|
||||
: null;
|
||||
});
|
||||
});
|
||||
@ -78,9 +78,9 @@ public function getForCreate(): array
|
||||
->get()
|
||||
->each(function (RawMaterial $rawMaterial) {
|
||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||
$media = $price->getFirstMedia('photos');
|
||||
$media = $price->getFirstMedia('images');
|
||||
$price->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->getPath())
|
||||
: null;
|
||||
});
|
||||
}),
|
||||
@ -103,15 +103,15 @@ public function getForEdit(Purchase $purchase): array
|
||||
return null;
|
||||
}
|
||||
|
||||
$media = $item->rawMaterialPrice->getFirstMedia('photos');
|
||||
$media = $item->rawMaterialPrice->getFirstMedia('images');
|
||||
|
||||
return [
|
||||
'id' => $item->rawMaterialPrice->id,
|
||||
'variant' => $item->rawMaterialPrice->variant,
|
||||
'price' => $item->unit_price,
|
||||
'stock' => $item->quantity,
|
||||
'photo_key' => $media?->file_name,
|
||||
'photo_url' => $media ? $this->s3Service->getTemporaryUrl($media->file_name) : null,
|
||||
'photo_key' => $media?->getCustomProperty('s3_key') ?? $media?->file_name,
|
||||
'photo_url' => $media ? $this->s3Service->getTemporaryUrl($media->getPath()) : null,
|
||||
];
|
||||
})->filter()->values();
|
||||
|
||||
@ -129,9 +129,9 @@ public function getForEdit(Purchase $purchase): array
|
||||
->exists();
|
||||
|
||||
$purchaseMedia = $purchase->getFirstMedia('photos');
|
||||
$purchasePhotoKey = $purchaseMedia?->file_name;
|
||||
$purchasePhotoKey = $purchaseMedia?->getCustomProperty('s3_key') ?? $purchaseMedia?->file_name;
|
||||
$purchasePhotoUrl = $purchaseMedia
|
||||
? $this->s3Service->getTemporaryUrl($purchaseMedia->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($purchaseMedia->getPath())
|
||||
: null;
|
||||
|
||||
return [
|
||||
@ -267,7 +267,7 @@ private function storeNew(array $data): Purchase
|
||||
$this->registerMedia(
|
||||
model: $priceModel,
|
||||
s3Key: $variantData['photo_key'],
|
||||
collectionName: 'photos',
|
||||
collectionName: 'images',
|
||||
orderColumn: 1,
|
||||
);
|
||||
}
|
||||
@ -412,11 +412,12 @@ public function update(Purchase $purchase, array $data): Purchase
|
||||
]);
|
||||
}
|
||||
|
||||
if (! empty($v['photo_key']) && $price->getFirstMedia('photos')?->file_name !== $v['photo_key']) {
|
||||
if (! empty($v['photo_key']) && $price->getFirstMedia('images')?->getCustomProperty('s3_key') !== $v['photo_key']) {
|
||||
$price->clearMediaCollection('images');
|
||||
$this->registerMedia(
|
||||
model: $price,
|
||||
s3Key: $v['photo_key'],
|
||||
collectionName: 'photos',
|
||||
collectionName: 'images',
|
||||
orderColumn: 1,
|
||||
);
|
||||
}
|
||||
|
||||
@ -49,9 +49,9 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
return;
|
||||
}
|
||||
|
||||
$media = $item->productVariant->getFirstMedia('photos');
|
||||
$media = $item->productVariant->getFirstMedia('images');
|
||||
$item->productVariant->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->getPath())
|
||||
: null;
|
||||
});
|
||||
});
|
||||
|
||||
@ -74,14 +74,19 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
$order->channel_label = $order->channel->label();
|
||||
$order->price_type_label = $order->price_type->label();
|
||||
|
||||
$orderMedia = $order->getFirstMedia('photos');
|
||||
$order->photo_url = $orderMedia
|
||||
? $this->s3Service->getTemporaryUrl($orderMedia->getPath())
|
||||
: null;
|
||||
|
||||
$order->orderItems->each(function (OrderItem $item) {
|
||||
if (! $item->productVariant) {
|
||||
return;
|
||||
}
|
||||
|
||||
$media = $item->productVariant->getFirstMedia('photos');
|
||||
$media = $item->productVariant->getFirstMedia('images');
|
||||
$item->productVariant->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->getPath())
|
||||
: null;
|
||||
});
|
||||
|
||||
|
||||
@ -57,8 +57,8 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
|
||||
$paginator->getCollection()->each(function ($product) {
|
||||
$product->productVariants->each(function ($variant) {
|
||||
$media = $variant->getMedia('photos');
|
||||
$variant->photo_urls = $media->map(fn($m) => $this->s3Service->getTemporaryUrl($m->file_name))->toArray();
|
||||
$media = $variant->getMedia('images');
|
||||
$variant->photo_urls = $media->map(fn($m) => $this->s3Service->getTemporaryUrl($m->getPath()))->toArray();
|
||||
});
|
||||
});
|
||||
|
||||
@ -160,9 +160,9 @@ public function getForEdit(Product $product): array
|
||||
]);
|
||||
|
||||
$variants = $product->productVariants->map(function (ProductVariant $variant) {
|
||||
$media = $variant->getMedia('photos');
|
||||
$photoKeys = $media->pluck('file_name')->toArray();
|
||||
$photoUrls = $media->map(fn($m) => $this->s3Service->getTemporaryUrl($m->file_name))->toArray();
|
||||
$media = $variant->getMedia('images');
|
||||
$photoKeys = $media->map(fn($m) => $m->getCustomProperty('s3_key') ?? $m->file_name)->toArray();
|
||||
$photoUrls = $media->map(fn($m) => $this->s3Service->getTemporaryUrl($m->getPath()))->toArray();
|
||||
|
||||
return [
|
||||
'id' => $variant->id,
|
||||
@ -222,7 +222,7 @@ public function update(Product $product, array $data): Product
|
||||
->whereNotIn('id', $existingVariantIds)
|
||||
->each(function (ProductVariant $variant) {
|
||||
$variant->productPrices()->delete();
|
||||
$variant->clearMediaCollection('photos');
|
||||
$variant->clearMediaCollection('images');
|
||||
$variant->delete();
|
||||
});
|
||||
|
||||
@ -379,14 +379,7 @@ public function update(Product $product, array $data): Product
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compare existing photo keys vs new ones
|
||||
$existingKeys = $variant->getMedia('photos')->pluck('file_name')->sort()->values()->toArray();
|
||||
$newKeys = collect($variantData['photo_keys'])->sort()->values()->toArray();
|
||||
|
||||
if ($existingKeys !== $newKeys) {
|
||||
$variant->clearMediaCollection('photos');
|
||||
$this->variantService->registerPhotos($variant, $variantData['photo_keys']);
|
||||
}
|
||||
$this->variantService->syncPhotos($variant, $variantData['photo_keys']);
|
||||
}
|
||||
|
||||
return $product;
|
||||
@ -409,7 +402,7 @@ public function destroy(Product $product): bool
|
||||
$result = DB::transaction(function () use ($product) {
|
||||
$product->productVariants->each(function (ProductVariant $variant) {
|
||||
$variant->productPrices()->delete();
|
||||
$variant->clearMediaCollection('photos');
|
||||
$variant->clearMediaCollection('images');
|
||||
$variant->delete();
|
||||
});
|
||||
|
||||
|
||||
@ -37,9 +37,9 @@ public function getForRestock(): array
|
||||
->get()
|
||||
->each(function (Product $product) {
|
||||
$product->productVariants->each(function (ProductVariant $variant) {
|
||||
$media = $variant->getFirstMedia('photos');
|
||||
$media = $variant->getFirstMedia('images');
|
||||
$variant->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->getPath())
|
||||
: null;
|
||||
|
||||
$capitalPrice = $variant->productPrices
|
||||
@ -66,9 +66,9 @@ public function getForTransaction(): array
|
||||
->get()
|
||||
->each(function (Product $product) {
|
||||
$product->productVariants->each(function (ProductVariant $variant) {
|
||||
$media = $variant->getFirstMedia('photos');
|
||||
$media = $variant->getFirstMedia('images');
|
||||
$variant->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->getPath())
|
||||
: null;
|
||||
|
||||
$prices = $variant->productPrices->mapWithKeys(fn ($p) => [$p->type->value => $p->price]);
|
||||
@ -84,9 +84,9 @@ public function getForEdit(ProductVariant $variant): array
|
||||
'media',
|
||||
]);
|
||||
|
||||
$media = $variant->getMedia('photos');
|
||||
$photoKeys = $media->pluck('file_name')->toArray();
|
||||
$photoUrls = $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->file_name))->toArray();
|
||||
$media = $variant->getMedia('images');
|
||||
$photoKeys = $media->map(fn ($m) => $m->getCustomProperty('s3_key') ?? $m->file_name)->toArray();
|
||||
$photoUrls = $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->getPath()))->toArray();
|
||||
|
||||
return [
|
||||
'id' => $variant->id,
|
||||
@ -136,8 +136,7 @@ public function update(ProductVariant $variant, array $data): ProductVariant
|
||||
);
|
||||
|
||||
if (! empty($data['photo_keys']) && is_array($data['photo_keys'])) {
|
||||
$variant->clearMediaCollection('photos');
|
||||
$this->registerPhotos($variant, $data['photo_keys']);
|
||||
$this->syncPhotos($variant, $data['photo_keys']);
|
||||
}
|
||||
});
|
||||
|
||||
@ -157,7 +156,7 @@ public function destroy(Product $product, ProductVariant $variant): bool
|
||||
|
||||
$result = DB::transaction(function () use ($variant) {
|
||||
$variant->productPrices()->delete();
|
||||
$variant->clearMediaCollection('photos');
|
||||
$variant->clearMediaCollection('images');
|
||||
|
||||
return $variant->delete();
|
||||
});
|
||||
@ -172,25 +171,6 @@ public function destroy(Product $product, ProductVariant $variant): bool
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function registerPhotos(ProductVariant $variant, array $photoKeys): void
|
||||
{
|
||||
foreach ($photoKeys as $order => $s3Key) {
|
||||
$this->registerMedia(
|
||||
model: $variant,
|
||||
s3Key: $s3Key,
|
||||
collectionName: 'photos',
|
||||
orderColumn: $order + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getTemporaryUrls(ProductVariant $variant): array
|
||||
{
|
||||
$media = $variant->getMedia('photos');
|
||||
|
||||
return $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->file_name))->toArray();
|
||||
}
|
||||
|
||||
public function transferStock(ProductVariant $variant, array $data): ProductVariant
|
||||
{
|
||||
$quantity = (int) $data['quantity'];
|
||||
|
||||
@ -39,9 +39,9 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
|
||||
$paginator->getCollection()->each(function ($rawMaterial) {
|
||||
$rawMaterial->rawMaterialPrices->each(function ($price) {
|
||||
$media = $price->getMedia('photos');
|
||||
$media = $price->getMedia('images');
|
||||
$price->photo_url = $media->first()
|
||||
? $this->s3Service->getTemporaryUrl($media->first()->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->first()->getPath())
|
||||
: null;
|
||||
});
|
||||
});
|
||||
@ -92,19 +92,17 @@ public function getForEdit(RawMaterial $rawMaterial): array
|
||||
]);
|
||||
|
||||
$variants = $rawMaterial->rawMaterialPrices->map(function (RawMaterialPrice $price) {
|
||||
$media = $price->getMedia('photos');
|
||||
$photoKey = $media->first()?->file_name;
|
||||
$photoUrl = $media->first()
|
||||
? $this->s3Service->getTemporaryUrl($media->first()->file_name)
|
||||
: null;
|
||||
$media = $price->getMedia('images');
|
||||
$photoKeys = $media->map(fn ($m) => $m->getCustomProperty('s3_key') ?? $m->file_name)->toArray();
|
||||
$photoUrls = $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->getPath()))->toArray();
|
||||
|
||||
return [
|
||||
'id' => $price->id,
|
||||
'variant' => $price->variant,
|
||||
'price' => $price->price,
|
||||
'stock' => $price->stock,
|
||||
'photo_key' => $photoKey,
|
||||
'photo_url' => $photoUrl,
|
||||
'photo_key' => $photoKeys[0] ?? null,
|
||||
'photo_url' => $photoUrls[0] ?? null,
|
||||
];
|
||||
});
|
||||
|
||||
@ -134,7 +132,7 @@ public function update(RawMaterial $rawMaterial, array $data): RawMaterial
|
||||
$rawMaterial->rawMaterialPrices()
|
||||
->whereNotIn('id', $existingVariantIds)
|
||||
->each(function (RawMaterialPrice $price) {
|
||||
$price->clearMediaCollection('photos');
|
||||
$price->clearMediaCollection('images');
|
||||
$price->delete();
|
||||
});
|
||||
|
||||
@ -184,9 +182,9 @@ public function update(RawMaterial $rawMaterial, array $data): RawMaterial
|
||||
]);
|
||||
|
||||
if (isset($variantData['photo_key'])) {
|
||||
$existingKey = $priceModel->getMedia('photos')->first()?->file_name;
|
||||
$existingKey = $priceModel->getMedia('images')->first()?->getCustomProperty('s3_key');
|
||||
if ($existingKey !== $variantData['photo_key']) {
|
||||
$priceModel->clearMediaCollection('photos');
|
||||
$priceModel->clearMediaCollection('images');
|
||||
if ($variantData['photo_key']) {
|
||||
$this->registerPhoto($priceModel, $variantData['photo_key']);
|
||||
}
|
||||
@ -202,7 +200,7 @@ public function destroy(RawMaterial $rawMaterial): bool
|
||||
{
|
||||
return DB::transaction(function () use ($rawMaterial) {
|
||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||
$price->clearMediaCollection('photos');
|
||||
$price->clearMediaCollection('images');
|
||||
$price->delete();
|
||||
});
|
||||
|
||||
@ -216,14 +214,4 @@ public function toggleStatus(RawMaterial $rawMaterial): void
|
||||
'is_active' => ! $rawMaterial->is_active,
|
||||
]);
|
||||
}
|
||||
|
||||
private function registerPhoto(RawMaterialPrice $price, string $s3Key): void
|
||||
{
|
||||
$this->registerMedia(
|
||||
model: $price,
|
||||
s3Key: $s3Key,
|
||||
collectionName: 'photos',
|
||||
orderColumn: 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,9 +30,9 @@ public function getForCutting(): array
|
||||
->get()
|
||||
->each(function (RawMaterial $rawMaterial) {
|
||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||
$media = $price->getFirstMedia('photos');
|
||||
$media = $price->getFirstMedia('images');
|
||||
$price->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
? $this->s3Service->getTemporaryUrl($media->getPath())
|
||||
: null;
|
||||
});
|
||||
})
|
||||
@ -43,11 +43,9 @@ public function getForEdit(RawMaterialPrice $variant): array
|
||||
{
|
||||
$variant->load('media');
|
||||
|
||||
$media = $variant->getMedia('photos');
|
||||
$photoKey = $media->first()?->file_name;
|
||||
$photoUrl = $media->first()
|
||||
? $this->s3Service->getTemporaryUrl($media->first()->file_name)
|
||||
: null;
|
||||
$media = $variant->getMedia('images');
|
||||
$photoKeys = $media->map(fn ($m) => $m->getCustomProperty('s3_key') ?? $m->file_name)->toArray();
|
||||
$photoUrls = $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->getPath()))->toArray();
|
||||
|
||||
return [
|
||||
'id' => $variant->id,
|
||||
@ -55,8 +53,8 @@ public function getForEdit(RawMaterialPrice $variant): array
|
||||
'variant' => $variant->variant,
|
||||
'price' => $variant->price,
|
||||
'stock' => $variant->stock,
|
||||
'photo_key' => $photoKey,
|
||||
'photo_url' => $photoUrl,
|
||||
'photo_key' => $photoKeys[0] ?? null,
|
||||
'photo_url' => $photoUrls[0] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
@ -70,11 +68,11 @@ public function update(RawMaterialPrice $variant, array $data): RawMaterialPrice
|
||||
]);
|
||||
|
||||
if (array_key_exists('photo_key', $data)) {
|
||||
$existingKey = $variant->getMedia('photos')->first()?->file_name;
|
||||
$existingKey = $variant->getMedia('images')->first()?->getCustomProperty('s3_key');
|
||||
$newKey = $data['photo_key'];
|
||||
|
||||
if ($existingKey !== $newKey) {
|
||||
$variant->clearMediaCollection('photos');
|
||||
$variant->clearMediaCollection('images');
|
||||
if ($newKey) {
|
||||
$this->registerPhoto($variant, $newKey);
|
||||
}
|
||||
@ -95,7 +93,7 @@ public function update(RawMaterialPrice $variant, array $data): RawMaterialPrice
|
||||
public function destroy(RawMaterial $rawMaterial, RawMaterialPrice $variant): bool
|
||||
{
|
||||
$result = DB::transaction(function () use ($variant) {
|
||||
$variant->clearMediaCollection('photos');
|
||||
$variant->clearMediaCollection('images');
|
||||
|
||||
return $variant->delete();
|
||||
});
|
||||
@ -110,13 +108,4 @@ public function destroy(RawMaterial $rawMaterial, RawMaterialPrice $variant): bo
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function registerPhoto(RawMaterialPrice $variant, string $s3Key): void
|
||||
{
|
||||
$this->registerMedia(
|
||||
model: $variant,
|
||||
s3Key: $s3Key,
|
||||
collectionName: 'photos',
|
||||
orderColumn: 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Services\Concerns;
|
||||
|
||||
use App\Services\S3PresignedService;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@ -66,21 +67,21 @@ private function registerMedia(
|
||||
?int $orderColumn = null,
|
||||
?string $name = null,
|
||||
): void {
|
||||
$defaultName = pathinfo($s3Key, PATHINFO_FILENAME);
|
||||
$fileName = pathinfo($s3Key, PATHINFO_BASENAME);
|
||||
|
||||
Media::create([
|
||||
'model_type' => $model->getMorphClass(),
|
||||
'model_id' => $model->id,
|
||||
'uuid' => Str::uuid(),
|
||||
'collection_name' => $collectionName,
|
||||
'name' => $name ?? $defaultName,
|
||||
'file_name' => $s3Key,
|
||||
'name' => $name ?? pathinfo($s3Key, PATHINFO_FILENAME),
|
||||
'file_name' => $fileName,
|
||||
'mime_type' => $mimeType ?? 'image/jpeg',
|
||||
'disk' => 's3',
|
||||
'conversions_disk' => 's3',
|
||||
'size' => $fileSize ?? 0,
|
||||
'manipulations' => [],
|
||||
'custom_properties' => [],
|
||||
'custom_properties' => ['s3_key' => $s3Key],
|
||||
'generated_conversions' => $generatedConversions,
|
||||
'responsive_images' => [],
|
||||
'order_column' => $orderColumn ?? 1,
|
||||
@ -93,7 +94,7 @@ private function syncPhoto(Model $model, array $data, string $collectionName = '
|
||||
return;
|
||||
}
|
||||
|
||||
$currentKey = $model->getFirstMedia($collectionName)?->file_name;
|
||||
$currentKey = $model->getFirstMedia($collectionName)?->getCustomProperty('s3_key');
|
||||
|
||||
if ($data['photo_key'] === $currentKey) {
|
||||
return;
|
||||
@ -114,11 +115,7 @@ private function syncPhoto(Model $model, array $data, string $collectionName = '
|
||||
private function syncReceipt(Model $model, ?string $newKey, string $collectionName = 'receipts', string $cachePrefix = 'receipt', ?int $fileSize = null, ?string $fileMimeType = null): void
|
||||
{
|
||||
$currentMedia = $model->getFirstMedia($collectionName);
|
||||
$currentKey = $currentMedia?->file_name;
|
||||
|
||||
if ($currentMedia && ! str_contains($currentKey, '/')) {
|
||||
$currentKey = $currentMedia->getPath();
|
||||
}
|
||||
$currentKey = $currentMedia?->getCustomProperty('s3_key');
|
||||
|
||||
if ($newKey === $currentKey) {
|
||||
return;
|
||||
@ -141,4 +138,53 @@ private function syncReceipt(Model $model, ?string $newKey, string $collectionNa
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function registerPhoto(Model $model, string $s3Key, string $collectionName = 'images'): void
|
||||
{
|
||||
$this->registerMedia(
|
||||
model: $model,
|
||||
s3Key: $s3Key,
|
||||
collectionName: $collectionName,
|
||||
orderColumn: 1,
|
||||
);
|
||||
}
|
||||
|
||||
public function registerPhotos(Model $model, array $photoKeys, string $collectionName = 'images'): void
|
||||
{
|
||||
foreach ($photoKeys as $order => $s3Key) {
|
||||
$this->registerMedia(
|
||||
model: $model,
|
||||
s3Key: $s3Key,
|
||||
collectionName: $collectionName,
|
||||
orderColumn: $order + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function syncPhotos(Model $model, array $photoKeys, string $collectionName = 'images'): void
|
||||
{
|
||||
$existingMedia = $model->getMedia($collectionName);
|
||||
$existingKeys = $existingMedia
|
||||
->map(fn (Media $m) => $m->getCustomProperty('s3_key') ?? $m->file_name)
|
||||
->toArray();
|
||||
|
||||
foreach ($existingMedia as $media) {
|
||||
$key = $media->getCustomProperty('s3_key') ?? $media->file_name;
|
||||
|
||||
if (! in_array($key, $photoKeys)) {
|
||||
$media->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$newKeys = array_values(array_diff($photoKeys, $existingKeys));
|
||||
|
||||
$this->registerPhotos($model, $newKeys, $collectionName);
|
||||
}
|
||||
|
||||
public function getTemporaryUrls(Model $model, string $collectionName = 'images'): array
|
||||
{
|
||||
$media = $model->getMedia($collectionName);
|
||||
|
||||
return $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->getPath()))->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ export type Transaction = {
|
||||
nego_price: number | null;
|
||||
total_amount: number;
|
||||
notes: string | null;
|
||||
photo_url: string | null;
|
||||
created_at: string;
|
||||
created_by: {
|
||||
id: number;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { CheckCircle, ChevronDown, Pencil, Printer, Send, Trash2, XCircle } from 'lucide-react';
|
||||
import { ImagePreviewButton } from '@/components/dialogs';
|
||||
import { RowActions } from '@/components/data-display';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@ -195,6 +196,16 @@ export function TransactionCardRow({
|
||||
{formatCurrency(transaction.cogs)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{transaction.photo_url && (
|
||||
<div className="mt-2">
|
||||
<ImagePreviewButton
|
||||
srcs={[transaction.photo_url]}
|
||||
title="Foto Pesanan"
|
||||
className="h-16 w-16"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user