feat: enhance notification system with new NotificationService methods and integrate notifications for various actions in services
This commit is contained in:
parent
f6503ace2b
commit
9ab2b0505c
@ -10,6 +10,7 @@
|
||||
use App\Models\PayrollAdjustment;
|
||||
use App\Models\PayrollPeriod;
|
||||
use App\Models\User;
|
||||
use App\Services\NotificationService;
|
||||
use App\Settings\HRSettings;
|
||||
use Carbon\CarbonInterface;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@ -131,11 +132,21 @@ private function handleLate(
|
||||
'attendance_id' => $attendance->id,
|
||||
'type' => PayrollAdjustmentType::DEDUCTION,
|
||||
'amount' => $hrSettings->late_penalty_amount,
|
||||
'description' => 'Denda keterlambatan '.$date->format('d/m/Y').' - '.$lateMinutes.' menit',
|
||||
'description' => 'Denda keterlambatan '.$date->translatedFormat('l, d F Y').' - '.$lateMinutes.' menit',
|
||||
]);
|
||||
|
||||
$this->recalculatePayroll($payroll);
|
||||
});
|
||||
|
||||
$employeeUser = $payroll->employee->user ?? null;
|
||||
if ($employeeUser) {
|
||||
NotificationService::notifyUsers(
|
||||
[$employeeUser],
|
||||
'Denda Keterlambatan',
|
||||
'Anda terkena denda keterlambatan sebesar Rp '.number_format($hrSettings->late_penalty_amount, 0, ',', '.')." pada {$date->translatedFormat('l, d F Y')} ({$lateMinutes} menit).",
|
||||
route('admin.finance.payroll-periods.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleAbsent(
|
||||
@ -149,7 +160,7 @@ private function handleAbsent(
|
||||
return;
|
||||
}
|
||||
|
||||
$description = 'Denda ketidakhadiran '.$date->format('d/m/Y');
|
||||
$description = 'Denda ketidakhadiran '.$date->translatedFormat('l, d F Y');
|
||||
|
||||
$existing = PayrollAdjustment::where('payroll_id', $payroll->id)
|
||||
->where('type', PayrollAdjustmentType::DEDUCTION)
|
||||
@ -172,6 +183,16 @@ private function handleAbsent(
|
||||
|
||||
$this->recalculatePayroll($payroll);
|
||||
});
|
||||
|
||||
$employeeUser = $employee->user ?? null;
|
||||
if ($employeeUser) {
|
||||
NotificationService::notifyUsers(
|
||||
[$employeeUser],
|
||||
'Denda Ketidakhadiran',
|
||||
'Anda terkena denda ketidakhadiran sebesar Rp '.number_format($hrSettings->absent_penalty_amount, 0, ',', '.')." pada {$date->translatedFormat('l, d F Y')}.",
|
||||
route('admin.finance.payroll-periods.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function recalculatePayroll(Payroll $payroll): void
|
||||
|
||||
@ -6,13 +6,12 @@
|
||||
use App\Models\Attendance;
|
||||
use App\Models\LeaveRequest;
|
||||
use App\Models\User;
|
||||
use App\Notifications\WebPushNotification;
|
||||
use App\Services\NotificationService;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class SendAttendanceReminderJob implements ShouldQueue
|
||||
{
|
||||
@ -25,7 +24,7 @@ public function handle(): void
|
||||
$today = now()->toDateString();
|
||||
|
||||
$users = User::query()
|
||||
->select(['id', 'name'])
|
||||
->select(['id'])
|
||||
->active()
|
||||
->whereHas('roles', function ($q) {
|
||||
$q->whereHas('permissions', fn($pq) => $pq->where('name', Permission::ATTENDANCES_CREATE->value));
|
||||
@ -33,11 +32,11 @@ public function handle(): void
|
||||
->whereHas('employee')
|
||||
->get();
|
||||
|
||||
foreach ($users as $user) {
|
||||
$eligibleUsers = $users->filter(function (User $user) use ($today) {
|
||||
$employee = $user->employee;
|
||||
|
||||
if (! $employee) {
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
||||
$hasAttendedToday = Attendance::where('employee_id', $employee->id)
|
||||
@ -45,7 +44,7 @@ public function handle(): void
|
||||
->exists();
|
||||
|
||||
if ($hasAttendedToday) {
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
||||
$isOnLeave = LeaveRequest::approved()
|
||||
@ -54,19 +53,18 @@ public function handle(): void
|
||||
->where('end_date', '>=', $today)
|
||||
->exists();
|
||||
|
||||
if ($isOnLeave) {
|
||||
continue;
|
||||
}
|
||||
return ! $isOnLeave;
|
||||
});
|
||||
|
||||
try {
|
||||
$user->notify(new WebPushNotification(
|
||||
title: 'Reminder Presensi',
|
||||
body: 'Selamat pagi! Jangan lupa untuk melakukan presensi masuk hari ini.',
|
||||
url: route('admin.hr.attendances.index'),
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
Log::error("Gagal mengirim reminder presensi ke user {$user->id}: {$e->getMessage()}");
|
||||
}
|
||||
if ($eligibleUsers->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationService::notifyUsers(
|
||||
$eligibleUsers,
|
||||
'Reminder Presensi',
|
||||
'Selamat pagi! Jangan lupa untuk melakukan presensi masuk hari ini.',
|
||||
route('admin.hr.attendances.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ public function pay(Payroll $payroll): Payroll
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
|
||||
title: 'Gaji Dibayar',
|
||||
body: "Gaji karyawan {$payroll->employee->name} sebesar {$payroll->formatted_amount} telah dibayar".' oleh '.auth()->user()->full_name.'.',
|
||||
body: "Gaji {$employeeUser->full_name} sebesar {$payroll->formatted_amount} telah dibayar oleh " . auth()->user()->full_name . '.',
|
||||
url: route('admin.finance.payroll-periods.index'),
|
||||
additionalUser: $employeeUser,
|
||||
);
|
||||
@ -178,7 +178,7 @@ public function cancel(Payroll $payroll): Payroll
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
|
||||
title: 'Gaji Dibatalkan',
|
||||
body: "Gaji karyawan {$payroll->employee->name} sebesar {$payroll->formatted_amount} telah dibatalkan".' oleh '.auth()->user()->full_name.'.',
|
||||
body: "Gaji {$employeeUser->full_name} sebesar {$payroll->formatted_amount} telah dibatalkan".' oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.finance.payroll-periods.index'),
|
||||
additionalUser: $employeeUser,
|
||||
);
|
||||
|
||||
@ -2,12 +2,14 @@
|
||||
|
||||
namespace App\Services\Admin\Manage;
|
||||
|
||||
use App\Enums\Role;
|
||||
use App\Models\Cutting;
|
||||
use App\Models\CuttingMaterial;
|
||||
use App\Models\CuttingMaterialCombination;
|
||||
use App\Models\CuttingResult;
|
||||
use App\Models\RawMaterialPrice;
|
||||
use App\Services\Concerns\RegistersMedia;
|
||||
use App\Services\NotificationService;
|
||||
use App\Services\S3PresignedService;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -61,7 +63,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
return $paginator;
|
||||
}
|
||||
|
||||
public function getMaterials(Cutting $cutting): \Illuminate\Support\Collection
|
||||
public function getMaterials(Cutting $cutting): Collection
|
||||
{
|
||||
return $cutting->cuttingMaterials()
|
||||
->select(['id', 'cutting_id', 'raw_material_price_id', 'material_usage', 'material_result', 'combination_id'])
|
||||
@ -85,7 +87,7 @@ public function getMaterials(Cutting $cutting): \Illuminate\Support\Collection
|
||||
});
|
||||
}
|
||||
|
||||
public function getCombinations(Cutting $cutting): \Illuminate\Support\Collection
|
||||
public function getCombinations(Cutting $cutting): Collection
|
||||
{
|
||||
return $cutting->cuttingMaterialCombinations()
|
||||
->select(['id', 'cutting_id', 'material_result'])
|
||||
@ -248,7 +250,7 @@ public function getForEdit(Cutting $cutting): array
|
||||
|
||||
public function store(array $data): Cutting
|
||||
{
|
||||
return DB::transaction(function () use ($data) {
|
||||
$cutting = DB::transaction(function () use ($data) {
|
||||
foreach ($data['materials'] as $materialData) {
|
||||
$usage = (int) ($materialData['material_usage'] ?? 0);
|
||||
if ($usage <= 0) {
|
||||
@ -346,11 +348,20 @@ public function store(array $data): Cutting
|
||||
|
||||
return $cutting;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_BAHAN_BAKU],
|
||||
title: 'Cutting Baru',
|
||||
body: 'Cutting berhasil ditambahkan oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.cuttings.index'),
|
||||
);
|
||||
|
||||
return $cutting;
|
||||
}
|
||||
|
||||
public function update(Cutting $cutting, array $data): Cutting
|
||||
{
|
||||
return DB::transaction(function () use ($cutting, $data) {
|
||||
$cutting = DB::transaction(function () use ($cutting, $data) {
|
||||
$cutting->load(['cuttingMaterials.rawMaterialPrice']);
|
||||
|
||||
foreach ($cutting->cuttingMaterials as $oldMaterial) {
|
||||
@ -450,11 +461,20 @@ public function update(Cutting $cutting, array $data): Cutting
|
||||
|
||||
return $cutting;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_BAHAN_BAKU],
|
||||
title: 'Cutting Diperbarui',
|
||||
body: 'Cutting berhasil diperbarui oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.cuttings.index'),
|
||||
);
|
||||
|
||||
return $cutting;
|
||||
}
|
||||
|
||||
public function destroy(Cutting $cutting): bool
|
||||
{
|
||||
return DB::transaction(function () use ($cutting) {
|
||||
$result = DB::transaction(function () use ($cutting) {
|
||||
$cutting->load('cuttingMaterials.rawMaterialPrice');
|
||||
|
||||
foreach ($cutting->cuttingMaterials as $material) {
|
||||
@ -470,5 +490,14 @@ public function destroy(Cutting $cutting): bool
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_BAHAN_BAKU],
|
||||
title: 'Cutting Dihapus',
|
||||
body: 'Cutting berhasil dihapus oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.cuttings.index'),
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,7 +340,7 @@ private function storeNew(array $data): Purchase
|
||||
|
||||
public function update(Purchase $purchase, array $data): Purchase
|
||||
{
|
||||
return DB::transaction(function () use ($purchase, $data) {
|
||||
$purchase = DB::transaction(function () use ($purchase, $data) {
|
||||
$purchase->load('purchaseItems.rawMaterialPrice.rawMaterial');
|
||||
|
||||
$oldItems = $purchase->purchaseItems;
|
||||
@ -478,11 +478,20 @@ public function update(Purchase $purchase, array $data): Purchase
|
||||
|
||||
return $purchase;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_BAHAN_BAKU],
|
||||
title: 'Belanja Diperbarui',
|
||||
body: 'Belanja bahan baku sebesar '.$purchase->formatted_total.' berhasil diperbarui oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.purchases.index'),
|
||||
);
|
||||
|
||||
return $purchase;
|
||||
}
|
||||
|
||||
public function destroy(Purchase $purchase): bool
|
||||
{
|
||||
return DB::transaction(function () use ($purchase) {
|
||||
$result = DB::transaction(function () use ($purchase) {
|
||||
$purchase->load('purchaseItems.rawMaterialPrice');
|
||||
|
||||
// Remove the stock the purchase added, keep the variants.
|
||||
@ -497,5 +506,14 @@ public function destroy(Purchase $purchase): bool
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_BAHAN_BAKU],
|
||||
title: 'Belanja Dihapus',
|
||||
body: 'Belanja bahan baku berhasil dihapus oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.purchases.index'),
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ public function store(array $data): Restock
|
||||
|
||||
public function update(Restock $restock, array $data): Restock
|
||||
{
|
||||
return DB::transaction(function () use ($restock, $data) {
|
||||
$restock = DB::transaction(function () use ($restock, $data) {
|
||||
$restock->load('restockItems');
|
||||
|
||||
$restock->restockItems->each(function (RestockItem $item) use ($restock) {
|
||||
@ -138,11 +138,20 @@ public function update(Restock $restock, array $data): Restock
|
||||
|
||||
return $restock;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
|
||||
title: 'Restock Diperbarui',
|
||||
body: 'Restock berhasil diperbarui oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.restocks.index'),
|
||||
);
|
||||
|
||||
return $restock;
|
||||
}
|
||||
|
||||
public function destroy(Restock $restock): bool
|
||||
{
|
||||
return DB::transaction(function () use ($restock) {
|
||||
$result = DB::transaction(function () use ($restock) {
|
||||
$restock->load('restockItems');
|
||||
|
||||
$restock->restockItems->each(function (RestockItem $item) use ($restock) {
|
||||
@ -154,6 +163,15 @@ public function destroy(Restock $restock): bool
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
|
||||
title: 'Restock Dihapus',
|
||||
body: 'Restock berhasil dihapus oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.restocks.index'),
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function buildItemRows(array $items, string $stockType, $now, int &$total): array
|
||||
|
||||
@ -94,6 +94,44 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
return $paginator;
|
||||
}
|
||||
|
||||
public function getForEdit(Order $order): array
|
||||
{
|
||||
$order->load([
|
||||
'orderItems:id,order_id,product_variant_id,stock_quality,quantity,unit_price',
|
||||
]);
|
||||
|
||||
$stockType = $order->orderItems->first()?->stock_quality?->value ?? 'good';
|
||||
|
||||
$orderMedia = $order->getFirstMedia('photos');
|
||||
|
||||
return [
|
||||
'id' => $order->id,
|
||||
'order_number' => $order->order_number,
|
||||
'stock_type' => $stockType,
|
||||
'channel' => $order->channel->value,
|
||||
'price_type' => $order->price_type->value,
|
||||
'payment_type' => $order->payment_type->value,
|
||||
'customer_id' => $order->customer_id,
|
||||
'marketing_id' => $order->marketing_id,
|
||||
'discount' => $order->discount,
|
||||
'nego_price' => $order->nego_price,
|
||||
'is_completed' => $order->status === OrderStatus::COMPLETED,
|
||||
'tiktok_order_id' => $order->tiktok_order_id,
|
||||
'shopee_order_id' => $order->shopee_order_id,
|
||||
'notes' => $order->notes,
|
||||
'photo_key' => $orderMedia?->getCustomProperty('s3_key') ?? $orderMedia?->file_name,
|
||||
'photo_url' => $orderMedia
|
||||
? $this->s3Service->getTemporaryUrl($orderMedia->getPath())
|
||||
: null,
|
||||
'items' => $order->orderItems->map(fn (OrderItem $item) => [
|
||||
'id' => $item->id,
|
||||
'product_variant_id' => $item->product_variant_id,
|
||||
'quantity' => $item->quantity,
|
||||
'unit_price' => $item->unit_price,
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
public function getItems(Order $order): \Illuminate\Support\Collection
|
||||
{
|
||||
return $order->orderItems()
|
||||
@ -224,7 +262,7 @@ public function store(array $data): Order
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
|
||||
title: 'Transaksi Baru',
|
||||
body: 'Transaksi '.$order->order_number.' sebesar Rp '.number_format($totalAmount, 0, ',', '.').' berhasil dicatat oleh '.auth()->user()->full_name.'.',
|
||||
body: 'Transaksi '.$order->order_number.' sebesar Rp '.$order->formatted_total_amount.' berhasil dicatat oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.transactions.index'),
|
||||
);
|
||||
|
||||
@ -234,7 +272,7 @@ public function store(array $data): Order
|
||||
|
||||
public function update(Order $order, array $data): Order
|
||||
{
|
||||
return DB::transaction(function () use ($order, $data) {
|
||||
$order = DB::transaction(function () use ($order, $data) {
|
||||
$order->load('orderItems');
|
||||
|
||||
$oldStockType = $order->orderItems->first()?->stock_type?->value ?? ProductStockQuality::GOOD->value;
|
||||
@ -296,11 +334,20 @@ public function update(Order $order, array $data): Order
|
||||
|
||||
return $order;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
|
||||
title: 'Transaksi Diperbarui',
|
||||
body: 'Transaksi '.$order->order_number.' sebesar '.$order->formatted_total_amount.' berhasil diperbarui oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.transactions.index'),
|
||||
);
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
public function destroy(Order $order): bool
|
||||
{
|
||||
return DB::transaction(function () use ($order) {
|
||||
$result = DB::transaction(function () use ($order) {
|
||||
$order->load('orderItems');
|
||||
|
||||
$stockType = $order->orderItems->first()?->stock_type?->value ?? ProductStockQuality::GOOD->value;
|
||||
@ -314,6 +361,15 @@ public function destroy(Order $order): bool
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
|
||||
title: 'Transaksi Dihapus',
|
||||
body: 'Transaksi '.$order->order_number.' berhasil dihapus oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.manage.transactions.index'),
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function updateStatus(Order $order, string $status): Order
|
||||
|
||||
@ -439,6 +439,15 @@ public function toggleStatus(Product $product): void
|
||||
$product->update([
|
||||
'status' => $product->status->value === 'active' ? 'inactive' : 'active',
|
||||
]);
|
||||
|
||||
$status = $product->status->value === 'active' ? 'diaktifkan' : 'dinonaktifkan';
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
|
||||
title: 'Status Produk Diubah',
|
||||
body: "Produk \"{$product->name}\" berhasil {$status}".' oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.master.products.index'),
|
||||
);
|
||||
}
|
||||
|
||||
public function toggleFeatured(Product $product): void
|
||||
@ -448,6 +457,15 @@ public function toggleFeatured(Product $product): void
|
||||
$product->update([
|
||||
'is_featured' => ! $product->is_featured,
|
||||
]);
|
||||
|
||||
$status = $product->is_featured ? 'ditandai sebagai unggulan' : 'dihapus dari unggulan';
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
|
||||
title: 'Status Unggulan Produk Diubah',
|
||||
body: "Produk \"{$product->name}\" berhasil {$status}".' oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.master.products.index'),
|
||||
);
|
||||
}
|
||||
|
||||
public function approve(Product $product): void
|
||||
@ -457,7 +475,7 @@ public function approve(Product $product): void
|
||||
]);
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER],
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
|
||||
title: 'Produk Disetujui',
|
||||
body: "Produk \"{$product->name}\" telah disetujui oleh ".auth()->user()->full_name.'.',
|
||||
url: route('admin.master.products.index'),
|
||||
@ -473,7 +491,7 @@ public function reject(Product $product, string $reason = ''): void
|
||||
]);
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER],
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
|
||||
title: 'Produk Ditolak',
|
||||
body: "Produk \"{$product->name}\" telah ditolak oleh ".auth()->user()->full_name.'.',
|
||||
url: route('admin.master.products.index'),
|
||||
@ -489,7 +507,7 @@ public function resubmit(Product $product): void
|
||||
]);
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER],
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_TOKO],
|
||||
title: 'Produk Diajukan Ulang',
|
||||
body: "Produk \"{$product->name}\" telah diajukan ulang oleh ".auth()->user()->full_name.'.',
|
||||
url: route('admin.master.products.index'),
|
||||
|
||||
@ -2,9 +2,11 @@
|
||||
|
||||
namespace App\Services\Admin\Master\RawMaterial;
|
||||
|
||||
use App\Enums\Role;
|
||||
use App\Models\RawMaterial;
|
||||
use App\Models\RawMaterialPrice;
|
||||
use App\Services\Concerns\RegistersMedia;
|
||||
use App\Services\NotificationService;
|
||||
use App\Services\S3PresignedService;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -71,7 +73,7 @@ public function getVariants(RawMaterial $rawMaterial): Collection
|
||||
|
||||
public function store(array $data): RawMaterial
|
||||
{
|
||||
return DB::transaction(function () use ($data) {
|
||||
$rawMaterial = DB::transaction(function () use ($data) {
|
||||
$rawMaterial = RawMaterial::create([
|
||||
'name' => $data['name'],
|
||||
'unit' => $data['unit'],
|
||||
@ -103,6 +105,15 @@ public function store(array $data): RawMaterial
|
||||
|
||||
return $rawMaterial;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
|
||||
title: 'Bahan Baku Baru',
|
||||
body: "Bahan baku \"{$rawMaterial->name}\" berhasil ditambahkan".' oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.master.raw-materials.index'),
|
||||
);
|
||||
|
||||
return $rawMaterial;
|
||||
}
|
||||
|
||||
public function getForEdit(RawMaterial $rawMaterial): array
|
||||
@ -137,7 +148,7 @@ public function getForEdit(RawMaterial $rawMaterial): array
|
||||
|
||||
public function update(RawMaterial $rawMaterial, array $data): RawMaterial
|
||||
{
|
||||
return DB::transaction(function () use ($rawMaterial, $data) {
|
||||
$rawMaterial = DB::transaction(function () use ($rawMaterial, $data) {
|
||||
$rawMaterial->update([
|
||||
'name' => $data['name'],
|
||||
'unit' => $data['unit'],
|
||||
@ -214,17 +225,35 @@ public function update(RawMaterial $rawMaterial, array $data): RawMaterial
|
||||
|
||||
return $rawMaterial;
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
|
||||
title: 'Bahan Baku Diperbarui',
|
||||
body: "Bahan baku \"{$rawMaterial->name}\" berhasil diperbarui".' oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.master.raw-materials.index'),
|
||||
);
|
||||
|
||||
return $rawMaterial;
|
||||
}
|
||||
|
||||
public function destroy(RawMaterial $rawMaterial): bool
|
||||
{
|
||||
return DB::transaction(function () use ($rawMaterial) {
|
||||
$result = DB::transaction(function () use ($rawMaterial) {
|
||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||
$price->delete();
|
||||
});
|
||||
|
||||
return $rawMaterial->delete();
|
||||
});
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
|
||||
title: 'Bahan Baku Dihapus',
|
||||
body: "Bahan baku \"{$rawMaterial->name}\" berhasil dihapus".' oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.master.raw-materials.index'),
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function toggleStatus(RawMaterial $rawMaterial): void
|
||||
@ -232,5 +261,14 @@ public function toggleStatus(RawMaterial $rawMaterial): void
|
||||
$rawMaterial->update([
|
||||
'is_active' => ! $rawMaterial->is_active,
|
||||
]);
|
||||
|
||||
$status = $rawMaterial->is_active ? 'diaktifkan' : 'dinonaktifkan';
|
||||
|
||||
NotificationService::notify(
|
||||
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
|
||||
title: 'Status Bahan Baku Diubah',
|
||||
body: "Bahan baku \"{$rawMaterial->name}\" berhasil {$status}".' oleh '.auth()->user()->full_name.'.',
|
||||
url: route('admin.master.raw-materials.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
use App\Enums\Role;
|
||||
use App\Models\User;
|
||||
use App\Notifications\WebPushNotification;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class NotificationService
|
||||
@ -12,32 +13,52 @@ class NotificationService
|
||||
/**
|
||||
* @param array<Role> $roles
|
||||
*/
|
||||
public static function notify(array $roles, string $title, string $body, string $url, ?User $additionalUser = null): void
|
||||
public static function notify(array $roles, string $title, string $body, string $url, ?User $additionalUser = null, ?User $except = null): void
|
||||
{
|
||||
$roleLabels = array_map(fn (Role $role) => $role->label(), $roles);
|
||||
$except ??= auth()->user();
|
||||
|
||||
$roleValues = array_map(fn (Role $role) => $role->value, $roles);
|
||||
|
||||
$users = User::query()
|
||||
->select(['id'])
|
||||
->where('is_active', true)
|
||||
->whereHas('roles', fn ($q) => $q->whereIn('name', $roleLabels))
|
||||
->where('id', '!=', $except?->id)
|
||||
->whereHas('roles', fn ($q) => $q->whereIn('name', $roleValues))
|
||||
->get();
|
||||
|
||||
if ($additionalUser && ! $users->contains('id', $additionalUser->id)) {
|
||||
if ($additionalUser && $additionalUser->id !== $except?->id && ! $users->contains('id', $additionalUser->id)) {
|
||||
$users->push($additionalUser);
|
||||
}
|
||||
|
||||
$users->each(function (User $user) use ($title, $body, $url) {
|
||||
try {
|
||||
$user->notifications()->create([
|
||||
'title' => $title,
|
||||
'body' => $body,
|
||||
'url' => $url,
|
||||
]);
|
||||
|
||||
$user->notify(new WebPushNotification($title, $body));
|
||||
} catch (\Exception $e) {
|
||||
Log::error("Gagal mengirim notifikasi ke user {$user->id}: {$e->getMessage()}");
|
||||
}
|
||||
self::sendNotification($user, $title, $body, $url);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, User>|array<int, User> $users
|
||||
*/
|
||||
public static function notifyUsers(Collection|array $users, string $title, string $body, string $url): void
|
||||
{
|
||||
$users = $users instanceof Collection ? $users : collect($users);
|
||||
|
||||
$users->each(function (User $user) use ($title, $body, $url) {
|
||||
self::sendNotification($user, $title, $body, $url);
|
||||
});
|
||||
}
|
||||
|
||||
private static function sendNotification(User $user, string $title, string $body, string $url): void
|
||||
{
|
||||
try {
|
||||
$user->notifications()->create([
|
||||
'title' => $title,
|
||||
'body' => $body,
|
||||
'url' => $url,
|
||||
]);
|
||||
|
||||
$user->notify(new WebPushNotification($title, $body));
|
||||
} catch (\Exception $e) {
|
||||
Log::error("Gagal mengirim notifikasi ke user {$user->id}: {$e->getMessage()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user