refactor: rename create/delete methods to store/destroy across multiple services; add transaction handling for cash and stock adjustments
This commit is contained in:
parent
1c19e6c690
commit
46af27e537
@ -43,7 +43,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
->paginate($perPage);
|
||||
}
|
||||
|
||||
public function create(array $data): EmployeeAdvance
|
||||
public function store(array $data): EmployeeAdvance
|
||||
{
|
||||
$employee = auth()->user()->employee;
|
||||
|
||||
@ -123,7 +123,7 @@ public function update(EmployeeAdvance $employeeAdvance, array $data): EmployeeA
|
||||
return $employeeAdvance;
|
||||
}
|
||||
|
||||
public function delete(EmployeeAdvance $employeeAdvance): bool
|
||||
public function destroy(EmployeeAdvance $employeeAdvance): bool
|
||||
{
|
||||
return DB::transaction(function () use ($employeeAdvance) {
|
||||
if ($employeeAdvance->status === EmployeeAdvanceStatus::APPROVED && $employeeAdvance->cash_transaction_id) {
|
||||
|
||||
@ -75,7 +75,7 @@ private function formatExpense(Expense $expense): array
|
||||
];
|
||||
}
|
||||
|
||||
public function create(array $data): Expense
|
||||
public function store(array $data): Expense
|
||||
{
|
||||
$expense = DB::transaction(function () use ($data) {
|
||||
$cashTransaction = $this->debitCash(
|
||||
@ -173,7 +173,7 @@ public function update(Expense $expense, array $data): Expense
|
||||
return $expense;
|
||||
}
|
||||
|
||||
public function delete(Expense $expense): bool
|
||||
public function destroy(Expense $expense): bool
|
||||
{
|
||||
return DB::transaction(function () use ($expense) {
|
||||
$this->creditCash(
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
class PayrollAdjustmentService
|
||||
{
|
||||
public function create(Payroll $payroll, array $data): PayrollAdjustment
|
||||
public function store(Payroll $payroll, array $data): PayrollAdjustment
|
||||
{
|
||||
if ($payroll->status !== PayrollStatus::UNPAID) {
|
||||
throw ValidationException::withMessages([
|
||||
@ -35,7 +35,7 @@ public function create(Payroll $payroll, array $data): PayrollAdjustment
|
||||
});
|
||||
}
|
||||
|
||||
public function delete(PayrollAdjustment $adjustment): bool
|
||||
public function destroy(PayrollAdjustment $adjustment): bool
|
||||
{
|
||||
$payroll = $adjustment->payroll;
|
||||
|
||||
|
||||
@ -23,6 +23,16 @@ private function canViewAll(): bool
|
||||
return auth()->user()->hasAnyRole(['developer', 'owner', 'direktur', 'admin-toko']);
|
||||
}
|
||||
|
||||
public function getCurrentOrCreate(): PayrollPeriod
|
||||
{
|
||||
$now = now();
|
||||
|
||||
return PayrollPeriod::firstOrCreate(
|
||||
['year' => $now->year, 'month' => $now->month],
|
||||
['status' => PayrollPeriodStatus::OPEN]
|
||||
);
|
||||
}
|
||||
|
||||
public function getAll(array $filters = []): Collection
|
||||
{
|
||||
return PayrollPeriod::select(['id', 'year', 'month', 'status', 'closed_at', 'created_at'])
|
||||
|
||||
@ -9,9 +9,11 @@
|
||||
use App\Services\Concerns\RegistersMedia;
|
||||
use App\Services\NotificationService;
|
||||
use App\Services\S3PresignedService;
|
||||
use App\Settings\HRSettings;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class AttendanceService
|
||||
{
|
||||
@ -21,6 +23,32 @@ public function __construct(
|
||||
private S3PresignedService $s3Service,
|
||||
) {}
|
||||
|
||||
public function getIndexData(int $year, int $month): array
|
||||
{
|
||||
$user = auth()->user();
|
||||
$isAdmin = $user->hasAnyRole(['developer', 'owner']);
|
||||
$hrSettings = app(HRSettings::class);
|
||||
|
||||
$employeeId = $isAdmin ? null : $user->employee?->id;
|
||||
|
||||
return [
|
||||
'attendances' => $this->getByMonth($year, $month, $employeeId),
|
||||
'leaves' => $this->getLeavesByMonth($year, $month, $employeeId),
|
||||
'employees' => $isAdmin ? $this->getAllEmployees() : [],
|
||||
'todayAttendance' => $isAdmin ? null : $this->getToday(),
|
||||
'currentYear' => $year,
|
||||
'currentMonth' => $month,
|
||||
'monthStats' => $this->getMonthStats($year, $month, $employeeId),
|
||||
'hrSettings' => [
|
||||
'scheduled_check_in_time' => $hrSettings->scheduled_check_in_time,
|
||||
'scheduled_check_out_time' => $hrSettings->scheduled_check_out_time,
|
||||
],
|
||||
'isOnLeave' => $isAdmin ? false : $this->isOnLeave($user),
|
||||
'canCheckIn' => $isAdmin ? false : $user->employee !== null,
|
||||
'isAdmin' => $isAdmin,
|
||||
];
|
||||
}
|
||||
|
||||
public function getAll(): Collection
|
||||
{
|
||||
return Attendance::with(['employee.user.userProfile', 'media'])
|
||||
@ -217,7 +245,9 @@ public function checkIn(array $data): Attendance
|
||||
$employee = auth()->user()->employee;
|
||||
|
||||
if (! $employee) {
|
||||
throw new \Exception('Anda tidak terdaftar sebagai karyawan.');
|
||||
throw ValidationException::withMessages([
|
||||
'employee' => 'Anda tidak terdaftar sebagai karyawan.',
|
||||
]);
|
||||
}
|
||||
|
||||
$today = now()->toDateString();
|
||||
@ -227,7 +257,9 @@ public function checkIn(array $data): Attendance
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
throw new \Exception('Anda sudah melakukan presensi hari ini.');
|
||||
throw ValidationException::withMessages([
|
||||
'attendance' => 'Anda sudah melakukan presensi hari ini.',
|
||||
]);
|
||||
}
|
||||
|
||||
$attendance = Attendance::create([
|
||||
|
||||
@ -66,7 +66,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
->paginate($perPage);
|
||||
}
|
||||
|
||||
public function create(array $data): User
|
||||
public function store(array $data): User
|
||||
{
|
||||
return DB::transaction(function () use ($data) {
|
||||
$user = User::create([
|
||||
@ -132,7 +132,7 @@ public function update(User $user, array $data): User
|
||||
return $user->fresh(['userProfile', 'employee']);
|
||||
}
|
||||
|
||||
public function delete(User $user): bool
|
||||
public function destroy(User $user): bool
|
||||
{
|
||||
return DB::transaction(function () use ($user) {
|
||||
$user->employee()->delete();
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class LeaveRequestService
|
||||
{
|
||||
@ -43,13 +44,15 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
->paginate($perPage);
|
||||
}
|
||||
|
||||
public function create(array $data): LeaveRequest
|
||||
public function store(array $data): LeaveRequest
|
||||
{
|
||||
$leaveRequest = DB::transaction(function () use ($data) {
|
||||
$employee = auth()->user()->employee;
|
||||
|
||||
if (! $employee) {
|
||||
throw new \Exception('Anda tidak terdaftar sebagai karyawan.');
|
||||
throw ValidationException::withMessages([
|
||||
'employee' => 'Anda tidak terdaftar sebagai karyawan.',
|
||||
]);
|
||||
}
|
||||
|
||||
$startDate = new Carbon($data['start_date']);
|
||||
@ -95,7 +98,7 @@ public function update(LeaveRequest $leaveRequest, array $data): LeaveRequest
|
||||
});
|
||||
}
|
||||
|
||||
public function delete(LeaveRequest $leaveRequest): bool
|
||||
public function destroy(LeaveRequest $leaveRequest): bool
|
||||
{
|
||||
return $leaveRequest->delete();
|
||||
}
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
use App\Models\CuttingMaterial;
|
||||
use App\Models\CuttingMaterialCombination;
|
||||
use App\Models\CuttingResult;
|
||||
use App\Models\RawMaterial;
|
||||
use App\Models\RawMaterialPrice;
|
||||
use App\Services\Admin\Master\RawMaterial\RawMaterialService;
|
||||
use App\Services\Concerns\RegistersMedia;
|
||||
use App\Services\S3PresignedService;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
@ -20,6 +20,7 @@ class CuttingService
|
||||
|
||||
public function __construct(
|
||||
private S3PresignedService $s3Service,
|
||||
private RawMaterialService $rawMaterialService,
|
||||
) {}
|
||||
|
||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
||||
@ -64,22 +65,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
public function getForCreate(): array
|
||||
{
|
||||
return [
|
||||
'rawMaterials' => RawMaterial::query()
|
||||
->select(['id', 'name', 'unit', 'is_active'])
|
||||
->with([
|
||||
'rawMaterialPrices:id,raw_material_id,variant,price,stock',
|
||||
])
|
||||
->active()
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->each(function (RawMaterial $rawMaterial) {
|
||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||
$media = $price->getFirstMedia('photos');
|
||||
$price->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
: null;
|
||||
});
|
||||
}),
|
||||
'rawMaterials' => $this->rawMaterialService->getVariantsForCutting(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -334,12 +334,6 @@ public function update(Purchase $purchase, array $data): Purchase
|
||||
}
|
||||
});
|
||||
|
||||
$oldMaterial = $oldItems
|
||||
->map(fn (PurchaseItem $item) => $item->rawMaterialPrice?->rawMaterial)
|
||||
->filter()
|
||||
->unique(fn (RawMaterial $material) => $material->id)
|
||||
->first();
|
||||
|
||||
$oldMaterial = $oldItems
|
||||
->map(fn (PurchaseItem $item) => $item->rawMaterialPrice?->rawMaterial)
|
||||
->filter()
|
||||
|
||||
@ -22,7 +22,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
->paginate($perPage);
|
||||
}
|
||||
|
||||
public function create(array $data): Category
|
||||
public function store(array $data): Category
|
||||
{
|
||||
return Category::create($data);
|
||||
}
|
||||
@ -34,7 +34,7 @@ public function update(Category $category, array $data): Category
|
||||
return $category;
|
||||
}
|
||||
|
||||
public function delete(Category $category): bool
|
||||
public function destroy(Category $category): bool
|
||||
{
|
||||
return $category->delete();
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
->paginate($perPage);
|
||||
}
|
||||
|
||||
public function create(array $data): Customer
|
||||
public function store(array $data): Customer
|
||||
{
|
||||
return Customer::create($data);
|
||||
}
|
||||
@ -34,7 +34,7 @@ public function update(Customer $customer, array $data): Customer
|
||||
return $customer;
|
||||
}
|
||||
|
||||
public function delete(Customer $customer): bool
|
||||
public function destroy(Customer $customer): bool
|
||||
{
|
||||
return $customer->delete();
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
return $paginator;
|
||||
}
|
||||
|
||||
public function create(array $data): RawMaterial
|
||||
public function store(array $data): RawMaterial
|
||||
{
|
||||
return DB::transaction(function () use ($data) {
|
||||
$rawMaterial = RawMaterial::create([
|
||||
@ -220,7 +220,7 @@ public function update(RawMaterial $rawMaterial, array $data): RawMaterial
|
||||
});
|
||||
}
|
||||
|
||||
public function delete(RawMaterial $rawMaterial): bool
|
||||
public function destroy(RawMaterial $rawMaterial): bool
|
||||
{
|
||||
return DB::transaction(function () use ($rawMaterial) {
|
||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||
@ -239,6 +239,26 @@ public function toggleStatus(RawMaterial $rawMaterial): void
|
||||
]);
|
||||
}
|
||||
|
||||
public function getVariantsForCutting(): array
|
||||
{
|
||||
return RawMaterial::query()
|
||||
->select(['id', 'name', 'unit', 'is_active'])
|
||||
->with([
|
||||
'rawMaterialPrices:id,raw_material_id,variant,price,stock',
|
||||
])
|
||||
->active()
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->each(function (RawMaterial $rawMaterial) {
|
||||
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
||||
$media = $price->getFirstMedia('photos');
|
||||
$price->photo_url = $media
|
||||
? $this->s3Service->getTemporaryUrl($media->file_name)
|
||||
: null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private function registerPhoto(RawMaterialPrice $price, string $s3Key): void
|
||||
{
|
||||
$this->registerMedia(
|
||||
|
||||
@ -22,7 +22,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
||||
->paginate($perPage);
|
||||
}
|
||||
|
||||
public function create(array $data): Supplier
|
||||
public function store(array $data): Supplier
|
||||
{
|
||||
return Supplier::create($data);
|
||||
}
|
||||
@ -34,7 +34,7 @@ public function update(Supplier $supplier, array $data): Supplier
|
||||
return $supplier;
|
||||
}
|
||||
|
||||
public function delete(Supplier $supplier): bool
|
||||
public function destroy(Supplier $supplier): bool
|
||||
{
|
||||
return $supplier->delete();
|
||||
}
|
||||
|
||||
@ -10,26 +10,17 @@
|
||||
|
||||
class RoleService
|
||||
{
|
||||
public function getAll(): Collection
|
||||
{
|
||||
return Role::withCount('permissions')->get();
|
||||
}
|
||||
|
||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
||||
{
|
||||
return Role::query()
|
||||
->select(['id', 'name'])
|
||||
->withCount('permissions')
|
||||
->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%"))
|
||||
->orderBy($sort, $direction)
|
||||
->paginate($perPage);
|
||||
}
|
||||
|
||||
public function getById(int $id): Role
|
||||
{
|
||||
return Role::with('permissions')->findOrFail($id);
|
||||
}
|
||||
|
||||
public function create(array $data): Role
|
||||
public function store(array $data): Role
|
||||
{
|
||||
return DB::transaction(function () use ($data) {
|
||||
$role = Role::create(['name' => $data['name']]);
|
||||
@ -49,7 +40,7 @@ public function update(Role $role, array $data): Role
|
||||
return $role->fresh('permissions');
|
||||
}
|
||||
|
||||
public function delete(Role $role): bool
|
||||
public function destroy(Role $role): bool
|
||||
{
|
||||
return $role->delete();
|
||||
}
|
||||
@ -61,4 +52,22 @@ public function getPermissionsByModule(): array
|
||||
->map(fn ($group) => $group->pluck('name')->map(fn ($name) => explode('.', $name, 2)[1])->values()->toArray())
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function getForEmployee(): Collection
|
||||
{
|
||||
$query = Role::where('name', '!=', 'Developer');
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->hasAnyRole(['admin-toko', 'direktur'])) {
|
||||
$query->where('name', '!=', 'admin-bahan-baku');
|
||||
}
|
||||
|
||||
if (! $user->hasAnyRole(['developer', 'owner', 'direktur', 'admin-toko'])) {
|
||||
$userRoles = $user->roles->pluck('name');
|
||||
$query->whereIn('name', $userRoles);
|
||||
}
|
||||
|
||||
return $query->get(['id', 'name']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
use App\Enums\CashTransactionType;
|
||||
use App\Models\CashAccount;
|
||||
use App\Models\CashTransaction;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
trait HandlesCashTransactions
|
||||
@ -16,41 +17,45 @@ private function getCashAccount(): CashAccount
|
||||
|
||||
private function creditCash(int $amount, string $description, CashTransactionType $type = CashTransactionType::DEPOSIT): CashTransaction
|
||||
{
|
||||
$cashAccount = $this->getCashAccount();
|
||||
$newBalance = $cashAccount->balance + $amount;
|
||||
return DB::transaction(function () use ($amount, $description, $type) {
|
||||
$cashAccount = $this->getCashAccount();
|
||||
$newBalance = $cashAccount->balance + $amount;
|
||||
|
||||
$cashAccount->update(['balance' => $newBalance]);
|
||||
$cashAccount->update(['balance' => $newBalance]);
|
||||
|
||||
return CashTransaction::create([
|
||||
'cash_account_id' => $cashAccount->id,
|
||||
'created_by_id' => auth()->id(),
|
||||
'amount' => $amount,
|
||||
'balance_after' => $newBalance,
|
||||
'type' => $type,
|
||||
'description' => $description,
|
||||
]);
|
||||
return CashTransaction::create([
|
||||
'cash_account_id' => $cashAccount->id,
|
||||
'created_by_id' => auth()->id(),
|
||||
'amount' => $amount,
|
||||
'balance_after' => $newBalance,
|
||||
'type' => $type,
|
||||
'description' => $description,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
private function debitCash(int $amount, string $description, CashTransactionType $type = CashTransactionType::EXPENSE): CashTransaction
|
||||
{
|
||||
$cashAccount = $this->getCashAccount();
|
||||
return DB::transaction(function () use ($amount, $description, $type) {
|
||||
$cashAccount = $this->getCashAccount();
|
||||
|
||||
if ($cashAccount->balance < $amount) {
|
||||
throw ValidationException::withMessages([
|
||||
'amount' => 'Saldo tidak mencukupi.',
|
||||
if ($cashAccount->balance < $amount) {
|
||||
throw ValidationException::withMessages([
|
||||
'amount' => 'Saldo tidak mencukupi.',
|
||||
]);
|
||||
}
|
||||
|
||||
$newBalance = $cashAccount->balance - $amount;
|
||||
$cashAccount->update(['balance' => $newBalance]);
|
||||
|
||||
return CashTransaction::create([
|
||||
'cash_account_id' => $cashAccount->id,
|
||||
'created_by_id' => auth()->id(),
|
||||
'amount' => $amount,
|
||||
'balance_after' => $newBalance,
|
||||
'type' => $type,
|
||||
'description' => $description,
|
||||
]);
|
||||
}
|
||||
|
||||
$newBalance = $cashAccount->balance - $amount;
|
||||
$cashAccount->update(['balance' => $newBalance]);
|
||||
|
||||
return CashTransaction::create([
|
||||
'cash_account_id' => $cashAccount->id,
|
||||
'created_by_id' => auth()->id(),
|
||||
'amount' => $amount,
|
||||
'balance_after' => $newBalance,
|
||||
'type' => $type,
|
||||
'description' => $description,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
use App\Enums\ProductStockQuality;
|
||||
use App\Models\ProductVariant;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
trait HasStockAdjustment
|
||||
@ -48,13 +49,10 @@ private function adjustVariantStock(int $variantId, int $quantity, int $sign, st
|
||||
|
||||
private function applyStock(array $items, string $stockType, int $sign): void
|
||||
{
|
||||
foreach ($items as $item) {
|
||||
$this->adjustVariantStock($item['product_variant_id'], $item['quantity'], $sign, $stockType);
|
||||
}
|
||||
}
|
||||
|
||||
private function reverseStock(array $items, string $stockType, int $sign): void
|
||||
{
|
||||
$this->applyStock($items, $stockType, -$sign);
|
||||
DB::transaction(function () use ($items, $stockType, $sign) {
|
||||
foreach ($items as $item) {
|
||||
$this->adjustVariantStock($item['product_variant_id'], $item['quantity'], $sign, $stockType);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,15 +49,13 @@ public function getRevenueSummary(): array
|
||||
->selectRaw('COUNT(*) as total_orders')
|
||||
->selectRaw('COALESCE(SUM(total_amount), 0) as total_revenue')
|
||||
->selectRaw('COALESCE(SUM(discount), 0) as total_discount')
|
||||
->selectRaw('COALESCE(SUM(total_amount), 0) - COALESCE(SUM(total_amount), 0) as total_marketplace_fees')
|
||||
->selectRaw('COALESCE(SUM(discount), 0) as total_deduction')
|
||||
->first();
|
||||
|
||||
return [
|
||||
'total_revenue' => (int) $stats->total_revenue,
|
||||
'total_discount' => (int) $stats->total_discount,
|
||||
'total_marketplace_fees' => (int) $stats->total_marketplace_fees,
|
||||
'total_deduction' => (int) $stats->total_deduction,
|
||||
'total_marketplace_fees' => 0,
|
||||
'total_deduction' => (int) $stats->total_discount,
|
||||
'total_orders' => (int) $stats->total_orders,
|
||||
'avg_order' => $stats->total_orders > 0 ? (int) ($stats->total_revenue / $stats->total_orders) : 0,
|
||||
];
|
||||
|
||||
@ -4,12 +4,14 @@
|
||||
|
||||
use App\Models\User;
|
||||
use App\Notifications\WebPushNotification;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class NotificationService
|
||||
{
|
||||
public static function notify(array $roles, string $title, string $body, string $url, ?User $additionalUser = null): void
|
||||
{
|
||||
$users = User::query()
|
||||
->select(['id'])
|
||||
->where('is_active', true)
|
||||
->whereHas('roles', fn ($q) => $q->whereIn('name', $roles))
|
||||
->get();
|
||||
@ -19,13 +21,17 @@ public static function notify(array $roles, string $title, string $body, string
|
||||
}
|
||||
|
||||
$users->each(function (User $user) use ($title, $body, $url) {
|
||||
$user->notifications()->create([
|
||||
'title' => $title,
|
||||
'body' => $body,
|
||||
'url' => $url,
|
||||
]);
|
||||
try {
|
||||
$user->notifications()->create([
|
||||
'title' => $title,
|
||||
'body' => $body,
|
||||
'url' => $url,
|
||||
]);
|
||||
|
||||
$user->notify(new WebPushNotification($title, $body));
|
||||
$user->notify(new WebPushNotification($title, $body));
|
||||
} catch (\Exception $e) {
|
||||
Log::error("Gagal mengirim notifikasi ke user {$user->id}: {$e->getMessage()}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,31 +144,33 @@ public function recordTransfer(
|
||||
int $toBefore,
|
||||
string $description = 'Transfer stok',
|
||||
): void {
|
||||
$userId = auth()->id();
|
||||
DB::transaction(function () use ($model, $quantity, $fromQuality, $toQuality, $fromBefore, $toBefore, $description) {
|
||||
$userId = auth()->id();
|
||||
|
||||
StockMutation::create([
|
||||
'user_id' => $userId,
|
||||
'stockable_type' => get_class($model),
|
||||
'stockable_id' => $model->id,
|
||||
'type' => 'out',
|
||||
'quantity' => -$quantity,
|
||||
'stock_before' => $fromBefore,
|
||||
'stock_after' => $fromBefore - $quantity,
|
||||
'stock_quality' => $fromQuality,
|
||||
'description' => $description,
|
||||
]);
|
||||
StockMutation::create([
|
||||
'user_id' => $userId,
|
||||
'stockable_type' => get_class($model),
|
||||
'stockable_id' => $model->id,
|
||||
'type' => 'out',
|
||||
'quantity' => -$quantity,
|
||||
'stock_before' => $fromBefore,
|
||||
'stock_after' => $fromBefore - $quantity,
|
||||
'stock_quality' => $fromQuality,
|
||||
'description' => $description,
|
||||
]);
|
||||
|
||||
StockMutation::create([
|
||||
'user_id' => $userId,
|
||||
'stockable_type' => get_class($model),
|
||||
'stockable_id' => $model->id,
|
||||
'type' => 'in',
|
||||
'quantity' => $quantity,
|
||||
'stock_before' => $toBefore,
|
||||
'stock_after' => $toBefore + $quantity,
|
||||
'stock_quality' => $toQuality,
|
||||
'description' => $description,
|
||||
]);
|
||||
StockMutation::create([
|
||||
'user_id' => $userId,
|
||||
'stockable_type' => get_class($model),
|
||||
'stockable_id' => $model->id,
|
||||
'type' => 'in',
|
||||
'quantity' => $quantity,
|
||||
'stock_before' => $toBefore,
|
||||
'stock_after' => $toBefore + $quantity,
|
||||
'stock_quality' => $toQuality,
|
||||
'description' => $description,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function paginated(Model $model, int $perPage = 20): LengthAwarePaginator
|
||||
|
||||
Loading…
Reference in New Issue
Block a user