Compare commits
10 Commits
3cb5b46aab
...
6546e1e3eb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6546e1e3eb | ||
|
|
3e9776696d | ||
|
|
0a688f1028 | ||
|
|
a8a7ed4c69 | ||
|
|
4517eeb7ee | ||
|
|
81f8135273 | ||
|
|
318afca796 | ||
|
|
d90d2261ac | ||
|
|
8970c47a4a | ||
|
|
5961a60585 |
957
AGENTS.md
Normal file
957
AGENTS.md
Normal file
@ -0,0 +1,957 @@
|
|||||||
|
# AGENTS.md - Session Notes
|
||||||
|
|
||||||
|
## Status: In Progress
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Relasi Dua Arah - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
| Model | Relasi Baru | Tipe | Inverse |
|
||||||
|
|-------|------------|------|---------|
|
||||||
|
| Cutting | submittedBy() | belongsTo(User, 'submitted_by_id') | User.submittedCuttings() |
|
||||||
|
| CashTransaction | employeeAdvances() | hasMany(EmployeeAdvance) | EmployeeAdvance.cashTransaction() |
|
||||||
|
| CashTransaction | payrolls() | hasMany(Payroll) | Payroll.cashTransaction() |
|
||||||
|
| Attendance | payrollAdjustments() | hasMany(PayrollAdjustment) | PayrollAdjustment.attendance() |
|
||||||
|
| User | cuttingMaterials() | hasMany(CuttingMaterial) | CuttingMaterial.user() |
|
||||||
|
| User | cuttingMaterialCombinations() | hasMany(CuttingMaterialCombination) | CuttingMaterialCombination.user() |
|
||||||
|
| User | cuttingResults() | hasMany(CuttingResult) | CuttingResult.user() |
|
||||||
|
| User | pushSubscriptions() | hasMany(PushSubscription) | PushSubscription.user() |
|
||||||
|
|
||||||
|
### File diubah untuk relasi:
|
||||||
|
- app/Models/Cutting.php - tambah submittedBy()
|
||||||
|
- app/Models/CashTransaction.php - tambah employeeAdvances(), payrolls(), import HasMany
|
||||||
|
- app/Models/Attendance.php - tambah payrollAdjustments(), import HasMany
|
||||||
|
- app/Models/User.php - tambah 4 relasi
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Casting - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
| Model | Kolom | Cast | Keterangan |
|
||||||
|
|-------|-------|------|------------|
|
||||||
|
| Cutting | sewing_cost | integer | tambah ke casts existing |
|
||||||
|
| Cutting | other_cost | integer | tambah ke casts existing |
|
||||||
|
| OwnerVerificationRequest | payload | array | tambah ke casts existing |
|
||||||
|
| Order | marketplace_settings_snapshot | array | tambah ke casts existing |
|
||||||
|
| ProductVariant | stock | integer | casts() baru dibuat |
|
||||||
|
| ProductVariant | reject_stock | integer | casts() baru dibuat |
|
||||||
|
| ProductVariant | retail_stock | integer | casts() baru dibuat |
|
||||||
|
| PayrollPeriod | year | integer | tambah ke casts existing |
|
||||||
|
| PayrollPeriod | month | integer | tambah ke casts existing |
|
||||||
|
|
||||||
|
### File diubah untuk casting:
|
||||||
|
- app/Models/Cutting.php
|
||||||
|
- app/Models/OwnerVerificationRequest.php
|
||||||
|
- app/Models/Order.php
|
||||||
|
- app/Models/ProductVariant.php
|
||||||
|
- app/Models/PayrollPeriod.php
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Scope (Ordered by Abjad) - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### Model yang DITAMBAH scope-nya:
|
||||||
|
| Model | Scope Baru | Enum |
|
||||||
|
|-------|-----------|------|
|
||||||
|
| Cutting | cancelled(), completed(), inProgress() | CuttingStatus |
|
||||||
|
| RawMaterial | kg(), meter(), yard() | RawMaterialUnit |
|
||||||
|
|
||||||
|
### Model yang SUDAH LENGKAP scopes:
|
||||||
|
| Model | Scopes (abjad) |
|
||||||
|
|-------|---------------|
|
||||||
|
| CashTransaction | deposit, expenseType, transfer, withdrawal |
|
||||||
|
| Employee | contract, fullTime, internship, partTime, resigned |
|
||||||
|
| EmployeeAdvance | approved, cancelled, paid, pending, rejected |
|
||||||
|
| LeaveRequest | approved, cancelled, pending, rejected |
|
||||||
|
| Order | cancelled, cash, completed, pending, processing, qris, refunded, retail, shopee, store, tiktok, transfer, wholesale |
|
||||||
|
| OrderItem | good, reject |
|
||||||
|
| Payroll | cancelled, paid, unpaid |
|
||||||
|
| PayrollAdjustment | bonus, deduction |
|
||||||
|
| PayrollPeriod | closed, open |
|
||||||
|
| Product | active, draft, inactive |
|
||||||
|
| ProductPrice | retail, wholesale |
|
||||||
|
| Restock | good, reject |
|
||||||
|
| StokOpname | cancelled, completed, draft, inProgress, verified |
|
||||||
|
| StokOpnameItem | good, reject |
|
||||||
|
| UserProfile | female, hasPhoneNumber, male |
|
||||||
|
| User | active |
|
||||||
|
|
||||||
|
### Model yang TIDAK punya enum (tidak perlu scope):
|
||||||
|
AppNotification, CashAccount, Category, Customer, Expense, CuttingMaterial, CuttingMaterialCombination, CuttingResult, OwnerVerificationRequest, ProductCategory, ProductVariant, Purchase, PurchaseItem, RawMaterialPrice, Rejection, RestockItem, RetailStockHistory, StockMutation, Supplier, SystemConfiguration, HomepageConfiguration, PushSubscription
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Reorganisasi Model - Semua model diubah urutannya menjadi:
|
||||||
|
**casts → scopes (abjad) → relations (abjad)**
|
||||||
|
|
||||||
|
### Semua 41 model sudah di-reorganize di sesi ini.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Relasi Dua Arah - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### AppNotification
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### Attendance
|
||||||
|
- belongsTo Employee (employee_id)
|
||||||
|
- hasMany PayrollAdjustment
|
||||||
|
|
||||||
|
### CashAccount
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
- hasMany CashTransaction
|
||||||
|
|
||||||
|
### CashTransaction
|
||||||
|
- belongsTo CashAccount (cash_account_id)
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
- hasMany EmployeeAdvance
|
||||||
|
- hasMany Payroll
|
||||||
|
- hasOne Expense
|
||||||
|
- hasOne Order
|
||||||
|
- morphTo Reference (reference_id, reference_type)
|
||||||
|
|
||||||
|
### Category
|
||||||
|
- belongsToMany Product (via product_categories)
|
||||||
|
|
||||||
|
### Cutting
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
- belongsTo User (submitted_by_id)
|
||||||
|
- hasMany CuttingMaterialCombination
|
||||||
|
- hasMany CuttingMaterial
|
||||||
|
- hasMany CuttingResult
|
||||||
|
|
||||||
|
### CuttingMaterial
|
||||||
|
- belongsTo CuttingMaterialCombination (combination_id)
|
||||||
|
- belongsTo Cutting (cutting_id)
|
||||||
|
- belongsTo RawMaterialPrice (raw_material_price_id)
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### CuttingMaterialCombination
|
||||||
|
- belongsTo Cutting (cutting_id)
|
||||||
|
- hasMany CuttingMaterial (combination_id)
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### CuttingResult
|
||||||
|
- belongsTo Cutting (cutting_id)
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### Customer
|
||||||
|
- hasMany Order (customer_id)
|
||||||
|
|
||||||
|
### Employee
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
- hasMany Attendance
|
||||||
|
- hasMany EmployeeAdvance
|
||||||
|
- hasMany LeaveRequest
|
||||||
|
- hasMany Payroll
|
||||||
|
|
||||||
|
### EmployeeAdvance
|
||||||
|
- belongsTo CashTransaction (cash_transaction_id)
|
||||||
|
- belongsTo Employee (employee_id)
|
||||||
|
- belongsTo User (paid_by_id)
|
||||||
|
- belongsTo CashTransaction (repayment_cash_transaction_id)
|
||||||
|
- belongsTo User (verified_by_id)
|
||||||
|
|
||||||
|
### Expense
|
||||||
|
- belongsTo CashTransaction (cash_transaction_id)
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
|
||||||
|
### LeaveRequest
|
||||||
|
- belongsTo Employee (employee_id)
|
||||||
|
- belongsTo User (verified_by_id)
|
||||||
|
|
||||||
|
### Order
|
||||||
|
- belongsTo CashTransaction (cash_transaction_id)
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
- belongsTo Customer (customer_id)
|
||||||
|
- belongsTo User (marketing_id)
|
||||||
|
- hasMany OrderItem (order_id)
|
||||||
|
|
||||||
|
### OrderItem
|
||||||
|
- belongsTo Order (order_id)
|
||||||
|
- belongsTo ProductVariant (product_variant_id)
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### OwnerVerificationRequest
|
||||||
|
- morphTo Subject (subject_id, subject_type)
|
||||||
|
- belongsTo User (submitted_by_id)
|
||||||
|
- belongsTo User (verified_by_id)
|
||||||
|
|
||||||
|
### Payroll
|
||||||
|
- belongsTo CashTransaction (cash_transaction_id)
|
||||||
|
- belongsTo Employee (employee_id)
|
||||||
|
- belongsTo User (paid_by_id)
|
||||||
|
- hasMany PayrollAdjustment (payroll_id)
|
||||||
|
- belongsTo PayrollPeriod (payroll_period_id)
|
||||||
|
|
||||||
|
### PayrollAdjustment
|
||||||
|
- belongsTo Attendance (attendance_id)
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
- belongsTo Payroll (payroll_id)
|
||||||
|
|
||||||
|
### PayrollPeriod
|
||||||
|
- belongsTo User (closed_by_id)
|
||||||
|
- hasMany Payroll (payroll_period_id)
|
||||||
|
|
||||||
|
### Product
|
||||||
|
- belongsToMany Category (via product_categories)
|
||||||
|
- hasMany ProductVariant (product_id)
|
||||||
|
|
||||||
|
### ProductCategory (Pivot)
|
||||||
|
- belongsTo Category (category_id)
|
||||||
|
- belongsTo Product (product_id)
|
||||||
|
|
||||||
|
### ProductPrice
|
||||||
|
- belongsTo ProductVariant (variant_id)
|
||||||
|
|
||||||
|
### ProductVariant
|
||||||
|
- belongsTo Product (product_id)
|
||||||
|
- hasMany OrderItem (product_variant_id)
|
||||||
|
- hasMany ProductPrice (variant_id)
|
||||||
|
- hasMany RestockItem (product_variant_id)
|
||||||
|
- hasMany RetailStockHistory (product_variant_id)
|
||||||
|
- hasMany StokOpnameItem (product_variant_id)
|
||||||
|
- hasMany StockMutation (stockable_id, polymorphic)
|
||||||
|
|
||||||
|
### Purchase
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
- hasMany PurchaseItem (purchase_id)
|
||||||
|
- belongsTo Supplier (supplier_id)
|
||||||
|
|
||||||
|
### PurchaseItem
|
||||||
|
- belongsTo Purchase (purchase_id)
|
||||||
|
- belongsTo RawMaterialPrice (raw_material_price_id)
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### PushSubscription
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### RawMaterial
|
||||||
|
- hasMany RawMaterialPrice (raw_material_id)
|
||||||
|
|
||||||
|
### RawMaterialPrice
|
||||||
|
- belongsTo RawMaterial (raw_material_id)
|
||||||
|
- hasMany CuttingMaterial (raw_material_price_id)
|
||||||
|
- hasMany PurchaseItem (raw_material_price_id)
|
||||||
|
|
||||||
|
### Rejection
|
||||||
|
- morphTo Rejectable (rejectable_id, rejectable_type)
|
||||||
|
- belongsTo User (rejected_by_id)
|
||||||
|
|
||||||
|
### Restock
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
- hasMany RestockItem (restock_id)
|
||||||
|
|
||||||
|
### RestockItem
|
||||||
|
- belongsTo ProductVariant (product_variant_id)
|
||||||
|
- belongsTo Restock (restock_id)
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### RetailStockHistory
|
||||||
|
- belongsTo ProductVariant (product_variant_id)
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### StockMutation
|
||||||
|
- morphTo Source (source_id, source_type)
|
||||||
|
- morphTo Stockable (stockable_id, stockable_type)
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
### StokOpname
|
||||||
|
- belongsTo User (created_by_id)
|
||||||
|
- hasMany StokOpnameItem (stok_opname_id)
|
||||||
|
- belongsTo User (verified_by_id)
|
||||||
|
|
||||||
|
### StokOpnameItem
|
||||||
|
- belongsTo ProductVariant (product_variant_id)
|
||||||
|
- belongsTo StokOpname (stok_opname_id)
|
||||||
|
|
||||||
|
### Supplier
|
||||||
|
- hasMany Purchase (supplier_id)
|
||||||
|
|
||||||
|
### User
|
||||||
|
- hasMany Attendance (user_id)
|
||||||
|
- hasMany CashAccount (created_by_id)
|
||||||
|
- hasMany CashTransaction (created_by_id)
|
||||||
|
- hasMany Cutting (created_by_id)
|
||||||
|
- hasMany Cutting (submitted_by_id)
|
||||||
|
- hasMany CuttingMaterialCombination (user_id)
|
||||||
|
- hasMany CuttingMaterial (user_id)
|
||||||
|
- hasMany CuttingResult (user_id)
|
||||||
|
- hasMany Expense (created_by_id)
|
||||||
|
- hasMany Order (created_by_id)
|
||||||
|
- hasMany Order (marketing_id)
|
||||||
|
- hasMany OrderItem (user_id)
|
||||||
|
- hasMany OwnerVerificationRequest (submitted_by_id)
|
||||||
|
- hasMany OwnerVerificationRequest (verified_by_id)
|
||||||
|
- hasMany Payroll (paid_by_id)
|
||||||
|
- hasMany PayrollAdjustment (created_by_id)
|
||||||
|
- hasMany PayrollPeriod (closed_by_id)
|
||||||
|
- hasMany Purchase (created_by_id)
|
||||||
|
- hasMany PurchaseItem (user_id)
|
||||||
|
- hasMany PushSubscription (user_id)
|
||||||
|
- hasMany Rejection (rejected_by_id)
|
||||||
|
- hasMany Restock (created_by_id)
|
||||||
|
- hasMany RestockItem (user_id)
|
||||||
|
- hasMany RetailStockHistory (user_id)
|
||||||
|
- hasMany StockMutation (user_id)
|
||||||
|
- hasMany StokOpname (created_by_id)
|
||||||
|
- hasMany StokOpname (verified_by_id)
|
||||||
|
- hasOne Employee (user_id)
|
||||||
|
- hasOne UserProfile (user_id)
|
||||||
|
|
||||||
|
### UserProfile
|
||||||
|
- belongsTo User (user_id)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Complete Casting Map
|
||||||
|
|
||||||
|
### Attendance
|
||||||
|
- attendance_date -> date:Y-m-d, check_in_at -> datetime, check_out_at -> datetime
|
||||||
|
- check_in_latitude -> decimal:7, check_in_longitude -> decimal:7
|
||||||
|
- check_out_latitude -> decimal:7, check_out_longitude -> decimal:7
|
||||||
|
- work_duration_minutes -> integer
|
||||||
|
|
||||||
|
### CashAccount
|
||||||
|
- balance -> integer
|
||||||
|
|
||||||
|
### CashTransaction
|
||||||
|
- type -> CashTransactionType enum, amount -> integer, balance_after -> integer
|
||||||
|
|
||||||
|
### Cutting
|
||||||
|
- status -> CuttingStatus enum, total_material_cost -> integer, cost_per_unit -> integer
|
||||||
|
- sewing_cost -> integer, other_cost -> integer
|
||||||
|
|
||||||
|
### CuttingMaterial
|
||||||
|
- material_usage -> integer, material_result -> integer
|
||||||
|
|
||||||
|
### CuttingMaterialCombination
|
||||||
|
- material_result -> integer
|
||||||
|
|
||||||
|
### CuttingResult
|
||||||
|
- cutting_result -> integer, sample -> integer, original_outside_sample -> integer
|
||||||
|
|
||||||
|
### Employee
|
||||||
|
- employment_status -> EmploymentStatus enum, base_salary -> integer
|
||||||
|
- join_date -> date:Y-m-d, resign_date -> date:Y-m-d
|
||||||
|
|
||||||
|
### EmployeeAdvance
|
||||||
|
- status -> EmployeeAdvanceStatus enum, amount -> integer, paid_amount -> integer
|
||||||
|
- due_date -> date:Y-m-d, verified_at -> datetime, paid_at -> datetime
|
||||||
|
|
||||||
|
### Order
|
||||||
|
- channel -> OrderChannel enum, price_type -> PriceType enum
|
||||||
|
- status -> OrderStatus enum, payment_type -> PaymentType enum
|
||||||
|
- is_affiliate -> boolean, subtotal -> integer, discount -> integer
|
||||||
|
- nego_price -> integer, total_amount -> integer, cogs -> integer
|
||||||
|
- marketplace_settings_snapshot -> array
|
||||||
|
|
||||||
|
### OrderItem
|
||||||
|
- stock_quality -> ProductStockQuality enum, quantity -> integer
|
||||||
|
- unit_price -> integer, subtotal -> integer
|
||||||
|
|
||||||
|
### OwnerVerificationRequest
|
||||||
|
- payload -> array, verified_at -> datetime
|
||||||
|
|
||||||
|
### Payroll
|
||||||
|
- status -> PayrollStatus enum, base_salary -> integer
|
||||||
|
- bonus_amount -> integer, deduction_amount -> integer
|
||||||
|
- total_amount -> integer, paid_at -> datetime
|
||||||
|
|
||||||
|
### PayrollAdjustment
|
||||||
|
- type -> PayrollAdjustmentType enum, amount -> integer
|
||||||
|
|
||||||
|
### PayrollPeriod
|
||||||
|
- status -> PayrollPeriodStatus enum, year -> integer
|
||||||
|
- month -> integer, closed_at -> datetime
|
||||||
|
|
||||||
|
### Product
|
||||||
|
- status -> ProductStatus enum
|
||||||
|
|
||||||
|
### ProductPrice
|
||||||
|
- type -> PriceType enum, price -> integer
|
||||||
|
|
||||||
|
### ProductVariant
|
||||||
|
- stock -> integer, reject_stock -> integer, retail_stock -> integer
|
||||||
|
|
||||||
|
### RawMaterial
|
||||||
|
- unit -> RawMaterialUnit enum, is_active -> boolean
|
||||||
|
|
||||||
|
### RawMaterialPrice
|
||||||
|
- price -> integer, stock -> integer
|
||||||
|
|
||||||
|
### User
|
||||||
|
- email_verified_at -> datetime, is_active -> boolean
|
||||||
|
- last_login_at -> datetime, password -> hashed
|
||||||
|
- two_factor_confirmed_at -> datetime
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Migration Foreign Keys
|
||||||
|
|
||||||
|
| Table | FK Column | References |
|
||||||
|
|-------|-----------|------------|
|
||||||
|
| user_profiles | user_id | users(id) |
|
||||||
|
| employees | user_id | users(id) |
|
||||||
|
| product_categories | product_id | products(id) |
|
||||||
|
| product_categories | category_id | categories(id) |
|
||||||
|
| product_variants | product_id | products(id) |
|
||||||
|
| raw_material_prices | raw_material_id | raw_materials(id) |
|
||||||
|
| cash_accounts | created_by_id | users(id) |
|
||||||
|
| cash_transactions | cash_account_id | cash_accounts(id) |
|
||||||
|
| cash_transactions | created_by_id | users(id) |
|
||||||
|
| expenses | cash_transaction_id | cash_transactions(id) |
|
||||||
|
| expenses | created_by_id | users(id) |
|
||||||
|
| employee_advances | paid_by_id | users(id) |
|
||||||
|
| employee_advances | employee_id | employees(id) |
|
||||||
|
| employee_advances | verified_by_id | users(id) |
|
||||||
|
| employee_advances | repayment_cash_transaction_id | cash_transactions(id) |
|
||||||
|
| employee_advances | cash_transaction_id | cash_transactions(id) |
|
||||||
|
| rejections | rejected_by_id | users(id) |
|
||||||
|
| attendances | employee_id | employees(id) |
|
||||||
|
| payroll_periods | closed_by_id | users(id) |
|
||||||
|
| payrolls | payroll_period_id | payroll_periods(id) |
|
||||||
|
| payrolls | employee_id | employees(id) |
|
||||||
|
| payrolls | cash_transaction_id | cash_transactions(id) |
|
||||||
|
| payrolls | paid_by_id | users(id) |
|
||||||
|
| payroll_adjustments | payroll_id | payrolls(id) |
|
||||||
|
| payroll_adjustments | attendance_id | attendances(id) |
|
||||||
|
| payroll_adjustments | created_by_id | users(id) |
|
||||||
|
| leave_requests | employee_id | employees(id) |
|
||||||
|
| leave_requests | verified_by_id | users(id) |
|
||||||
|
| purchases | supplier_id | suppliers(id) |
|
||||||
|
| purchases | created_by_id | users(id) |
|
||||||
|
| purchase_items | purchase_id | purchases(id) |
|
||||||
|
| purchase_items | user_id | users(id) |
|
||||||
|
| purchase_items | raw_material_price_id | raw_material_prices(id) |
|
||||||
|
| orders | customer_id | customers(id) |
|
||||||
|
| orders | marketing_id | users(id) |
|
||||||
|
| orders | cash_transaction_id | cash_transactions(id) |
|
||||||
|
| orders | created_by_id | users(id) |
|
||||||
|
| order_items | order_id | orders(id) |
|
||||||
|
| order_items | user_id | users(id) |
|
||||||
|
| order_items | product_variant_id | product_variants(id) |
|
||||||
|
| cuttings | created_by_id | users(id) |
|
||||||
|
| cuttings | submitted_by_id | users(id) |
|
||||||
|
| cutting_material_combinations | user_id | users(id) |
|
||||||
|
| cutting_material_combinations | cutting_id | cuttings(id) |
|
||||||
|
| cutting_materials | user_id | users(id) |
|
||||||
|
| cutting_materials | cutting_id | cuttings(id) |
|
||||||
|
| cutting_materials | raw_material_price_id | raw_material_prices(id) |
|
||||||
|
| cutting_materials | combination_id | cutting_material_combinations(id) |
|
||||||
|
| cutting_results | user_id | users(id) |
|
||||||
|
| cutting_results | cutting_id | cuttings(id) |
|
||||||
|
| product_prices | variant_id | product_variants(id) |
|
||||||
|
| owner_verification_requests | submitted_by_id | users(id) |
|
||||||
|
| owner_verification_requests | verified_by_id | users(id) |
|
||||||
|
| notifications | user_id | users(id) |
|
||||||
|
| employee_advance_payments | employee_advance_id | employee_advances(id) |
|
||||||
|
| employee_advance_payments | paid_by_id | users(id) |
|
||||||
|
| employee_advance_payments | cash_transaction_id | cash_transactions(id) |
|
||||||
|
| retail_stock_histories | product_variant_id | product_variants(id) |
|
||||||
|
| retail_stock_histories | user_id | users(id) |
|
||||||
|
| stok_opnames | created_by_id | users(id) |
|
||||||
|
| stok_opnames | verified_by_id | users(id) |
|
||||||
|
| stok_opname_items | stok_opname_id | stok_opnames(id) |
|
||||||
|
| stok_opname_items | product_variant_id | product_variants(id) |
|
||||||
|
| restocks | created_by_id | users(id) |
|
||||||
|
| restock_items | restock_id | restocks(id) |
|
||||||
|
| restock_items | user_id | users(id) |
|
||||||
|
| restock_items | product_variant_id | product_variants(id) |
|
||||||
|
| stock_mutations | user_id | users(id) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Accessor & Mutator - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### A. Currency Format (Get: `Rp X.XXX`)
|
||||||
|
| Model | Kolom |
|
||||||
|
|-------|-------|
|
||||||
|
| CashAccount | balance |
|
||||||
|
| CashTransaction | amount |
|
||||||
|
| Cutting | total_material_cost, cost_per_unit, sewing_cost, other_cost |
|
||||||
|
| Employee | base_salary |
|
||||||
|
| EmployeeAdvance | amount, paid_amount |
|
||||||
|
| Expense | amount |
|
||||||
|
| Order | subtotal, discount, nego_price, total_amount, cogs |
|
||||||
|
| OrderItem | unit_price, subtotal |
|
||||||
|
| Payroll | base_salary, bonus_amount, deduction_amount, total_amount |
|
||||||
|
| PayrollAdjustment | amount |
|
||||||
|
| ProductPrice | price |
|
||||||
|
| Purchase | subtotal, discount, shipping_cost, total |
|
||||||
|
| PurchaseItem | unit_price, subtotal |
|
||||||
|
| RawMaterialPrice | price |
|
||||||
|
| Restock | subtotal, total |
|
||||||
|
| RestockItem | unit_price, subtotal |
|
||||||
|
|
||||||
|
### B. Phone Format `0821 2121 2121` (Get/Set)
|
||||||
|
| Model | Kolom |
|
||||||
|
|-------|-------|
|
||||||
|
| UserProfile | phone_number |
|
||||||
|
| Customer | phone_number |
|
||||||
|
| Supplier | phone_number |
|
||||||
|
|
||||||
|
### C. String Format (Get: ucfirst)
|
||||||
|
| Model | Kolom |
|
||||||
|
|-------|-------|
|
||||||
|
| CashAccount | name |
|
||||||
|
| Category | name |
|
||||||
|
| Customer | name |
|
||||||
|
| Product | name |
|
||||||
|
| ProductVariant | name |
|
||||||
|
| RawMaterial | name |
|
||||||
|
| Supplier | name |
|
||||||
|
| UserProfile | first_name, last_name |
|
||||||
|
|
||||||
|
### D. Full Name (Computed)
|
||||||
|
| Model | Kolom | Get |
|
||||||
|
|-------|-------|-----|
|
||||||
|
| UserProfile | full_name | first_name . ' ' . last_name |
|
||||||
|
| User | fullName | userProfile full_name atau username |
|
||||||
|
|
||||||
|
### E. Email (Set: lowercase)
|
||||||
|
| Model | Kolom | Set |
|
||||||
|
|-------|-------|-----|
|
||||||
|
| User | email | strtolower |
|
||||||
|
|
||||||
|
### F. Date Format Indonesia (Get: `l, d F Y`)
|
||||||
|
| Model | Kolom |
|
||||||
|
|-------|-------|
|
||||||
|
| Attendance | attendance_date |
|
||||||
|
| Employee | join_date, resign_date |
|
||||||
|
| EmployeeAdvance | due_date |
|
||||||
|
| LeaveRequest | start_date, end_date |
|
||||||
|
| StokOpname | opname_date |
|
||||||
|
| UserProfile | birth_date |
|
||||||
|
|
||||||
|
### G. Status Label (Get: `->label()`)
|
||||||
|
| Model | Kolom |
|
||||||
|
|-------|-------|
|
||||||
|
| CashTransaction | typeLabel (type) |
|
||||||
|
| Cutting | statusLabel (status) |
|
||||||
|
| Employee | employmentStatusLabel (employment_status) |
|
||||||
|
| EmployeeAdvance | statusLabel (status) |
|
||||||
|
| LeaveRequest | statusLabel (status) |
|
||||||
|
| Order | statusLabel (status), channelLabel (channel), paymentTypeLabel (payment_type) |
|
||||||
|
| OrderItem | stockQualityLabel (stock_quality) |
|
||||||
|
| Payroll | statusLabel (status) |
|
||||||
|
| PayrollAdjustment | typeLabel (type) |
|
||||||
|
| PayrollPeriod | statusLabel (status) |
|
||||||
|
| Product | statusLabel (status) |
|
||||||
|
| ProductPrice | typeLabel (type) |
|
||||||
|
| RawMaterial | unitLabel (unit) |
|
||||||
|
| Restock | stockTypeLabel (stock_type) |
|
||||||
|
| StokOpname | statusLabel (status) |
|
||||||
|
| StokOpnameItem | stockQualityLabel (stock_quality) |
|
||||||
|
| UserProfile | genderLabel (gender) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Enum Label - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### Enum yang ditambah `label()` method:
|
||||||
|
| Enum | Labels |
|
||||||
|
|------|--------|
|
||||||
|
| CashTransactionType | Setoran, Pengeluaran, Transfer, Penarikan |
|
||||||
|
| CuttingStatus | Dibatalkan, Selesai, Dalam Proses |
|
||||||
|
| EmployeeAdvanceStatus | Disetujui, Dibatalkan, Dibayar, Menunggu, Ditolak |
|
||||||
|
| EmploymentStatus | Kontrak, Penuh Waktu, Magang, Paruh Waktu, Keluar |
|
||||||
|
| Gender | Perempuan, Laki-laki |
|
||||||
|
| LeaveRequestStatus | Disetujui, Dibatalkan, Menunggu, Ditolak |
|
||||||
|
| PayrollAdjustmentType | Bonus, Potongan |
|
||||||
|
| PayrollPeriodStatus | Tutup, Buka |
|
||||||
|
| PayrollStatus | Dibatalkan, Dibayar, Belum Dibayar |
|
||||||
|
| RawMaterialUnit | Kg, Meter, Yard |
|
||||||
|
| StokOpnameStatus | Dibatalkan, Selesai, Draft, Dalam Proses, Terverifikasi |
|
||||||
|
|
||||||
|
### Enum yang SUDAH punya `label()`:
|
||||||
|
OrderChannel, OrderStatus, PaymentType, PriceType, ProductStatus, ProductStockQuality
|
||||||
|
|
||||||
|
### HasValues Trait - `toSelect()` Method
|
||||||
|
Semua enum yang pakai `HasValues` trait bisa panggil `EnumName::toSelect()` untuk return `Collection<int, array{value: string, label: string}>`.
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Sebelum ( verbose ):
|
||||||
|
collect(OrderStatus::cases())->map(fn ($s) => ['value' => $s->value, 'label' => $s->label()])->values()
|
||||||
|
|
||||||
|
// Sesudah ( clean ):
|
||||||
|
OrderStatus::toSelect()
|
||||||
|
|
||||||
|
// Dengan filter:
|
||||||
|
PriceType::toSelect()->filter(fn ($p) => $p['value'] !== PriceType::CAPITAL->value)->values()
|
||||||
|
```
|
||||||
|
|
||||||
|
**File yang sudah di-refactor:**
|
||||||
|
- `app/Http/Controllers/Admin/Finance/CashAccountController.php` - `CashTransactionType::toSelect()`
|
||||||
|
- `app/Http/Controllers/Admin/HR/LeaveRequestController.php` - `LeaveRequestStatus::toSelect()`
|
||||||
|
- `app/Services/Admin/Manage/TransactionService.php` - `OrderStatus::toSelect()`, `OrderChannel::toSelect()`, `PaymentType::toSelect()`, `PriceType::toSelect()`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Appends - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### Catatan Penting:
|
||||||
|
- **Accessor tidak boleh sama nama dengan kolom database** → gunakan prefix `formatted_` untuk menghindari bentrok
|
||||||
|
- Label accessors (status_label, type_label, dll) tidak bentrok karena bukan kolom DB
|
||||||
|
|
||||||
|
### Model yang ditambah `#[Appends([...])]`:
|
||||||
|
|
||||||
|
| Model | Appends |
|
||||||
|
|-------|---------|
|
||||||
|
| CashAccount | `['formatted_balance', 'formatted_name']` |
|
||||||
|
| CashTransaction | `['formatted_amount', 'formatted_balance_after', 'formatted_created_at', 'type_label']` |
|
||||||
|
| Category | `['formatted_name']` |
|
||||||
|
| Cutting | `['formatted_cost_per_unit', 'formatted_other_cost', 'formatted_sewing_cost', 'status_label', 'formatted_total_material_cost']` |
|
||||||
|
| Customer | `['formatted_name', 'formatted_phone_number']` |
|
||||||
|
| Employee | `['formatted_base_salary', 'employment_status_label', 'formatted_join_date', 'formatted_resign_date']` |
|
||||||
|
| EmployeeAdvance | `['formatted_amount', 'formatted_created_at', 'formatted_due_date', 'formatted_paid_amount', 'status_label']` |
|
||||||
|
| Expense | `['formatted_amount', 'formatted_created_at', 'formatted_date']` |
|
||||||
|
| LeaveRequest | `['formatted_end_date', 'formatted_start_date', 'status_label']` |
|
||||||
|
| Order | `['channel_label', 'formatted_cogs', 'formatted_discount', 'formatted_nego_price', 'payment_type_label', 'status_label', 'formatted_subtotal', 'formatted_total_amount']` |
|
||||||
|
| OrderItem | `['stock_quality_label', 'formatted_subtotal', 'formatted_unit_price']` |
|
||||||
|
| Payroll | `['formatted_base_salary', 'formatted_bonus_amount', 'formatted_deduction_amount', 'status_label', 'formatted_total_amount']` |
|
||||||
|
| PayrollAdjustment | `['formatted_amount', 'type_label']` |
|
||||||
|
| PayrollPeriod | `['status_label']` |
|
||||||
|
| Product | `['formatted_name', 'status_label']` |
|
||||||
|
| ProductPrice | `['formatted_price', 'type_label']` |
|
||||||
|
| ProductVariant | `['formatted_name']` |
|
||||||
|
| Purchase | `['formatted_discount', 'formatted_shipping_cost', 'formatted_subtotal', 'formatted_total']` |
|
||||||
|
| PurchaseItem | `['formatted_subtotal', 'formatted_unit_price']` |
|
||||||
|
| RawMaterial | `['formatted_name', 'unit_label']` |
|
||||||
|
| RawMaterialPrice | `['formatted_price']` |
|
||||||
|
| Restock | `['stock_type_label', 'formatted_subtotal', 'formatted_total']` |
|
||||||
|
| RestockItem | `['formatted_subtotal', 'formatted_unit_price']` |
|
||||||
|
| StokOpname | `['formatted_opname_date', 'status_label']` |
|
||||||
|
| StokOpnameItem | `['stock_quality_label']` |
|
||||||
|
| Supplier | `['formatted_name', 'formatted_phone_number']` |
|
||||||
|
| UserProfile | `['formatted_birth_date', 'gender_label', 'formatted_phone_number']` |
|
||||||
|
| User | `['full_name', 'name']` |
|
||||||
|
|
||||||
|
### Yang TIDAK di-append:
|
||||||
|
- `User.email` - set-only accessor (tidak ada get)
|
||||||
|
|
||||||
|
### Aturan Penamaan Accessor:
|
||||||
|
| Tipe | Lama (BENTROK) | Baru (AMAN) |
|
||||||
|
|------|---------------|-------------|
|
||||||
|
| Currency | `amount()`, `price()`, `subtotal()` | `formattedAmount()`, `formattedPrice()`, `formattedSubtotal()` |
|
||||||
|
| Date | `joinDate()`, `dueDate()` | `formattedJoinDate()`, `formattedDueDate()` |
|
||||||
|
| String | `name()` | `formattedName()` |
|
||||||
|
| Phone | `phoneNumber()` | `formattedPhoneNumber()` |
|
||||||
|
| Label | `statusLabel()`, `typeLabel()` | TIDAK berubah (tidak bentrok) |
|
||||||
|
|
||||||
|
### Aturan Accessor Pattern:
|
||||||
|
- **Gunakan `$this->`** untuk mengakses attribute, bukan parameter `$value`
|
||||||
|
- Contoh: `get: fn () => 'Rp ' . number_format($this->amount, 0, ',', '.')`
|
||||||
|
- Null-safe: `get: fn () => $this->join_date?->translatedFormat('l, d F Y')`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Controller Conventions - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### Base Controller (`Controller.php`)
|
||||||
|
- `handleAction(callable $action, string $successMessage, string $redirectRoute, ?string $errorRoute = null, array $parameters = []): RedirectResponse`
|
||||||
|
- `handleToggle(callable $action, string $successMessage, string $redirectRoute): RedirectResponse`
|
||||||
|
|
||||||
|
### Aturan Penamaan Controller:
|
||||||
|
| Pattern | Keterangan |
|
||||||
|
|---------|------------|
|
||||||
|
| `handleAction()` | Untuk 2+ query/operasi dalam 1 action (try-catch) |
|
||||||
|
| `handleToggle()` | Untuk toggle operations (simple, non-dynamic message) |
|
||||||
|
| Manual flash | Untuk 1 query/operasi (single query) |
|
||||||
|
|
||||||
|
### Controller Property:
|
||||||
|
- Service properties harus `private readonly XService $service`
|
||||||
|
|
||||||
|
### Method Ordering:
|
||||||
|
1. `__construct`
|
||||||
|
2. `index`
|
||||||
|
3. `show` (jika ada)
|
||||||
|
4. `create`
|
||||||
|
5. `store`
|
||||||
|
6. `edit`
|
||||||
|
7. `update`
|
||||||
|
8. `destroy`
|
||||||
|
9. Custom actions (toggleStatus, approve, reject, dll)
|
||||||
|
|
||||||
|
### Perubahan di Sesi Ini:
|
||||||
|
|
||||||
|
| Controller | Perubahan |
|
||||||
|
|------------|-----------|
|
||||||
|
| StockMutationController | Fix inline instantiation → `private readonly StockMutationService $service` |
|
||||||
|
| ProfileController | Manual flash → `handleAction()` (2 queries: user save + profile updateOrCreate) |
|
||||||
|
| 23 controllers | Tambah `readonly` ke service properties |
|
||||||
|
|
||||||
|
### Catatan Penting:
|
||||||
|
- **`handleAction()` hanya untuk 2+ query/operasi** dalam 1 action
|
||||||
|
- **1 query = manual flash** (lebih simpel, tidak perlu try-catch overhead)
|
||||||
|
- Contoh 2+ query: `ProfileController::update()` → user save + profile updateOrCreate
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Service Conventions - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### Traits (Shared Concerns)
|
||||||
|
|
||||||
|
| Trait | Methods | Digunakan Oleh |
|
||||||
|
|-------|---------|----------------|
|
||||||
|
| `HandlesCashTransactions` | `getCashAccount()`, `creditCash()`, `debitCash()` | CashAccountService, ExpenseService, EmployeeAdvanceService, PayrollPeriodService |
|
||||||
|
| `HasStockAdjustment` | `adjustStock()`, `adjustVariantStock()`, `applyStock()`, `reverseStock()` | TransactionService, RestockService |
|
||||||
|
| `RegistersMedia` | `registerMedia()`, `syncPhoto()` | CashAccountService, CuttingService, ExpenseService, PurchaseService, RestockService, TransactionService |
|
||||||
|
|
||||||
|
### Aturan Penamaan Service:
|
||||||
|
| Pattern | Keterangan |
|
||||||
|
|---------|------------|
|
||||||
|
| `private readonly XService $service` | Service property harus readonly |
|
||||||
|
| `= new XService` dilarang | Gunakan dependency injection, bukan default value |
|
||||||
|
| `getAll(array $filters = []): Collection` | Standar method listing |
|
||||||
|
| `paginated(int $perPage, string $search, string $sort, string $direction, array $filters): LengthAwarePaginator` | Standar method pagination |
|
||||||
|
|
||||||
|
### Service Method Signatures:
|
||||||
|
```php
|
||||||
|
// Standard - dengan filter
|
||||||
|
getAll(array $filters = []): Collection
|
||||||
|
paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
||||||
|
|
||||||
|
// Standard - tanpa filter (tetap terima $filters untuk konsistensi)
|
||||||
|
getAll(): Collection
|
||||||
|
paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cash Transaction Patterns:
|
||||||
|
- **Credit (DEPOSIT)**: `$this->creditCash(amount, description)` → tambah saldo
|
||||||
|
- **Debit (EXPENSE/WITHDRAWAL)**: `$this->debitCash(amount, description)` → kurangi saldo + validasi
|
||||||
|
|
||||||
|
### Stock Adjustment Patterns:
|
||||||
|
- **ProductVariant**: `$this->applyStock(items, stockType, sign)` → increment/decrement stock/reject_stock
|
||||||
|
- **RawMaterialPrice**: `$this->adjustStock(model, field, quantity, sign)` → increment/decrement
|
||||||
|
|
||||||
|
### Service Files Diubah di Sesi Ini:
|
||||||
|
- `app/Services/Admin/Finance/CashAccountService.php` - hapus `= new`, tambah HandlesCashTransactions
|
||||||
|
- `app/Services/Admin/Finance/ExpenseService.php` - hapus `= new`, tambah HandlesCashTransactions
|
||||||
|
- `app/Services/Admin/Finance/EmployeeAdvanceService.php` - tambah HandlesCashTransactions
|
||||||
|
- `app/Services/Admin/Finance/PayrollPeriodService.php` - tambah HandlesCashTransactions
|
||||||
|
- `app/Services/Admin/Manage/TransactionService.php` - hapus `= new`, tambah HasStockAdjustment
|
||||||
|
- `app/Services/Admin/Manage/RestockService.php` - hapus `= new`, tambah HasStockAdjustment
|
||||||
|
- `app/Services/Admin/Manage/CuttingService.php` - hapus `= new`, hapus syncCuttingPhoto
|
||||||
|
- `app/Services/Admin/Manage/PurchaseService.php` - hapus `= new`, hapus syncPurchasePhoto
|
||||||
|
- `app/Services/Admin/Master/Product/ProductService.php` - hapus `= new`
|
||||||
|
- `app/Services/Admin/Master/Product/ProductVariantService.php` - hapus `= new`
|
||||||
|
- `app/Services/Admin/Master/RawMaterial/RawMaterialService.php` - hapus `= new`
|
||||||
|
- `app/Services/Admin/Master/RawMaterial/RawMaterialVariantService.php` - hapus `= new`
|
||||||
|
- `app/Services/Admin/AdminSettingsService.php` - hapus `= new`
|
||||||
|
- `app/Services/Admin/Settings/RoleService.php` - tambah $filters ke paginated()
|
||||||
|
- `app/Services/Admin/Master/CategoryService.php` - tambah $filters
|
||||||
|
- `app/Services/Admin/Master/CustomerService.php` - tambah $filters
|
||||||
|
- `app/Services/Admin/Master/SupplierService.php` - tambah $filters
|
||||||
|
|
||||||
|
### Trait Files Baru:
|
||||||
|
- `app/Services/Concerns/HandlesCashTransactions.php`
|
||||||
|
- `app/Services/Concerns/HasStockAdjustment.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Form Request Conventions - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### Traits (Shared Concerns)
|
||||||
|
|
||||||
|
| Trait | Methods | Digunakan Oleh |
|
||||||
|
|-------|---------|----------------|
|
||||||
|
| `CurrencyStripping` | `stripCurrencyDot(array $data, string ...$fields): array` | 11 Form Requests |
|
||||||
|
|
||||||
|
### Aturan Form Request:
|
||||||
|
| Pattern | Keterangan |
|
||||||
|
|---------|------------|
|
||||||
|
| `authorize()` wajib ada | Selalu return `true` (authorization di controller/middleware) |
|
||||||
|
| `attributes()` dalam Bahasa Indonesia | Label untuk semua field |
|
||||||
|
| `prepareForValidation()` | Strip dot currency via `CurrencyStripping` trait |
|
||||||
|
| Shared Store/Update | Gunakan 1 request dengan `sometimes` + if/else |
|
||||||
|
| Unique ignore | `Rule::unique('table')->ignore($this->route('model')?->id)` |
|
||||||
|
|
||||||
|
### Currency Stripping Pattern:
|
||||||
|
```php
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
|
|
||||||
|
class SomeRequest extends FormRequest
|
||||||
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
|
public function prepareForValidation(): void
|
||||||
|
{
|
||||||
|
$this->merge($this->stripCurrencyDot($this->validated(), 'amount', 'discount', 'variants.*.price'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Form Request Files Diubah di Sesi Ini:
|
||||||
|
|
||||||
|
#### Tambah `authorize()`:
|
||||||
|
- `app/Http/Requests/Settings/ProfileUpdateRequest.php`
|
||||||
|
- `app/Http/Requests/Settings/ProfileDeleteRequest.php`
|
||||||
|
- `app/Http/Requests/Settings/TwoFactorAuthenticationRequest.php`
|
||||||
|
- `app/Http/Requests/Settings/PasswordUpdateRequest.php`
|
||||||
|
|
||||||
|
#### Tambah `CurrencyStripping` trait:
|
||||||
|
- `app/Http/Requests/Admin/Manage/TransactionRequest.php` - `discount`, `nego_price`
|
||||||
|
- `app/Http/Requests/Admin/Manage/PurchaseRequest.php` - `variants.*.price`, `discount`, `shipping_cost`
|
||||||
|
- `app/Http/Requests/Admin/Master/RawMaterial/RawMaterialRequest.php` - `variants.*.price`
|
||||||
|
- `app/Http/Requests/Admin/Master/RawMaterial/RawMaterialVariantRequest.php` - `price`
|
||||||
|
- `app/Http/Requests/Admin/Master/Product/ProductRequest.php` - `shared_prices.*.price`, `variants.*.prices.*.price`
|
||||||
|
- `app/Http/Requests/Admin/Master/Product/ProductVariantRequest.php` - `prices.*.price`
|
||||||
|
- `app/Http/Requests/Admin/Finance/CashTransactionRequest.php` - `amount`
|
||||||
|
- `app/Http/Requests/Admin/Finance/ExpenseRequest.php` - `amount`
|
||||||
|
- `app/Http/Requests/Admin/Finance/EmployeeAdvanceRequest.php` - `amount`
|
||||||
|
- `app/Http/Requests/Admin/Finance/PayrollAdjustmentRequest.php` - `amount`
|
||||||
|
- `app/Http/Requests/Admin/Settings/UpdateHRRequest.php` - `late_penalty_amount`, `absent_penalty_amount`
|
||||||
|
|
||||||
|
### Trait Files Baru:
|
||||||
|
- `app/Concerns/CurrencyStripping.php`
|
||||||
|
|
||||||
|
### Catatan Penting:
|
||||||
|
- **Shared Store/Update** sudah cukup pakai `sometimes` + if/else untuk field yang berbeda
|
||||||
|
- **Split hanya jika** ruleset store dan update sangat berbeda (jarang terjadi)
|
||||||
|
- **Currency stripping** selalu di `prepareForValidation()`, sebelum validasi jalan
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. View Conventions - Perubahan di Sesi Ini
|
||||||
|
|
||||||
|
### Tech Stack
|
||||||
|
- **Framework**: Inertia.js + React + TypeScript
|
||||||
|
- **UI Components**: shadcn/ui (customized)
|
||||||
|
- **Styling**: Tailwind CSS
|
||||||
|
- **Routing**: Ziggy (type-safe routes)
|
||||||
|
|
||||||
|
### Directory Structure
|
||||||
|
```
|
||||||
|
resources/js/
|
||||||
|
├── pages/ # Page components (Inertia)
|
||||||
|
├── components/ # Shared UI components
|
||||||
|
├── hooks/ # Custom React hooks
|
||||||
|
├── lib/ # Utility functions
|
||||||
|
└── routes/ # Type-safe route definitions
|
||||||
|
```
|
||||||
|
|
||||||
|
### Page Patterns
|
||||||
|
|
||||||
|
#### Simple CRUD (Category, Customer, Supplier)
|
||||||
|
```tsx
|
||||||
|
// State: createOpen, editing, deleting
|
||||||
|
// Components: PageHeader, FormDialog, DataTable, DeleteConfirmDialog
|
||||||
|
// Hook: useServerTable untuk pagination/search
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Complex List (Transaction, Restock, Purchase, Cutting)
|
||||||
|
```tsx
|
||||||
|
// Components: PageHeader, CardTable (bukan DataTable)
|
||||||
|
// Features: FilterPopover, expandable rows, card + sub-row
|
||||||
|
// Hook: useServerTable + useCardTableExpand
|
||||||
|
```
|
||||||
|
|
||||||
|
### Columns Pattern
|
||||||
|
```tsx
|
||||||
|
// Type definition untuk entity
|
||||||
|
export type Category = { id: number; name: string; };
|
||||||
|
|
||||||
|
// Factory function untuk columns
|
||||||
|
export function createCategoryColumns(params: CreateColumnsParams): ColumnDef<Category>[] {
|
||||||
|
return [
|
||||||
|
{ accessorKey: 'name', header: ..., cell: ... },
|
||||||
|
{ id: 'actions', cell: ... RowActions ... }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enum Options dari Controller
|
||||||
|
```php
|
||||||
|
// Controller: kirim enum options ke view (pakai toSelect() dari HasValues trait)
|
||||||
|
'filterOptions' => [
|
||||||
|
'statusOptions' => OrderStatus::toSelect(),
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// View: gunakan options dari controller
|
||||||
|
{filterOptions.statusOptions.map((opt) => (
|
||||||
|
<SelectItem key={opt.value} value={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Draft Pattern
|
||||||
|
```tsx
|
||||||
|
// Hook: useXxxDraftSave (generated via createDraftHook)
|
||||||
|
export const useTransactionDraftSave = createDraftHook<TransactionDraftData>({
|
||||||
|
save: saveTransactionDraft,
|
||||||
|
clear: clearTransactionDraft,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
useTransactionDraftSave('create', draftData, userId);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Columns Pattern - Model Accessors
|
||||||
|
```tsx
|
||||||
|
// ❌ Jangan format di TypeScript
|
||||||
|
import { formatCurrency } from '@/lib/utils';
|
||||||
|
{
|
||||||
|
accessorKey: 'amount',
|
||||||
|
cell: ({ row }) => <span>{formatCurrency(row.getValue('amount') as number)}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Gunakan formatted_ accessor dari model
|
||||||
|
{
|
||||||
|
accessorKey: 'formatted_amount',
|
||||||
|
cell: ({ row }) => <span>{row.getValue('formatted_amount') as string}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Tetap format di TS untuk computed values (bukan dari DB)
|
||||||
|
{
|
||||||
|
accessorKey: 'payrolls_sum_total_amount',
|
||||||
|
cell: ({ row }) => <span>{formatCurrency(row.getValue('payrolls_sum_total_amount') as number)}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Tetap format di TS untuk nested objects (bukan model attribute)
|
||||||
|
{
|
||||||
|
cell: ({ row }) => <span>{formatCurrency(row.original.adjustment.amount)}</span>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Format Functions
|
||||||
|
```tsx
|
||||||
|
import { formatDate, formatShortDate, formatDateTime } from '@/lib/format';
|
||||||
|
import { formatCurrency, formatNumber } from '@/lib/utils';
|
||||||
|
|
||||||
|
formatDate(dateString) // "23 Agustus 2026 08:40"
|
||||||
|
formatShortDate(dateString) // "23 Agust 2026"
|
||||||
|
formatDateTime(dateString) // "23 Agustus 2026 08:40"
|
||||||
|
formatCurrency(1000000) // "Rp 1.000.000"
|
||||||
|
formatNumber(1000000) // "1.000.000"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shared Components
|
||||||
|
| Component | Digunakan Untuk |
|
||||||
|
|-----------|----------------|
|
||||||
|
| `FormDialog` | Modal form (create/edit) untuk simple CRUD |
|
||||||
|
| `DataTable` | Table dengan server-side pagination |
|
||||||
|
| `CardTable` | Card-based list dengan expandable rows |
|
||||||
|
| `PageHeader` | Header halaman dengan title + actions |
|
||||||
|
| `DeleteConfirmDialog` | Konfirmasi hapus |
|
||||||
|
| `FilterPopover` | Filter toolbar |
|
||||||
|
| `RowActions` | Action dropdown (edit/hapus) |
|
||||||
|
| `FileUpload` | Upload file ke S3 |
|
||||||
|
| `RupiahInput` | Input currency formatting |
|
||||||
|
| `NumberInput` | Input angka |
|
||||||
|
|
||||||
|
### Hooks
|
||||||
|
| Hook | Fungsi |
|
||||||
|
|------|--------|
|
||||||
|
| `useServerTable` | Pagination, search, filter server-side |
|
||||||
|
| `useCardTableExpand` | Expand/collapse rows |
|
||||||
|
| `useXxxDraft` | Auto-save draft (transaction, product, restock, purchase, cutting, raw-material) |
|
||||||
|
|
||||||
|
### Catatan Penting:
|
||||||
|
- **Enum options** harus dikirim dari controller, bukan hardcoded di view
|
||||||
|
- **Format data** gunakan `#[Appends]` attributes dari model
|
||||||
|
- **Type definitions** ada di `columns.tsx` bersama column definitions
|
||||||
|
- **Draft hooks** menggunakan `createDraftHook` factory
|
||||||
57
app/Concerns/CurrencyStripping.php
Normal file
57
app/Concerns/CurrencyStripping.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Concerns;
|
||||||
|
|
||||||
|
trait CurrencyStripping
|
||||||
|
{
|
||||||
|
protected function stripCurrencyDot(array $data, string ...$fields): array
|
||||||
|
{
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$data = $this->stripField($data, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function stripField(array $data, string $field): array
|
||||||
|
{
|
||||||
|
if (str_contains($field, '*')) {
|
||||||
|
return $this->stripNestedField($data, $field);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data[$field]) && is_string($data[$field])) {
|
||||||
|
$data[$field] = (int) str_replace('.', '', $data[$field]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function stripNestedField(array $data, string $pattern): array
|
||||||
|
{
|
||||||
|
$parts = explode('.', $pattern);
|
||||||
|
$this->stripNestedRecursive($data, $parts);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function stripNestedRecursive(array &$data, array $parts): void
|
||||||
|
{
|
||||||
|
$current = array_shift($parts);
|
||||||
|
|
||||||
|
if ($current === '*') {
|
||||||
|
if (is_array($data)) {
|
||||||
|
foreach ($data as &$item) {
|
||||||
|
$this->stripNestedRecursive($item, $parts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (empty($parts)) {
|
||||||
|
if (isset($data[$current]) && is_string($data[$current])) {
|
||||||
|
$data[$current] = (int) str_replace('.', '', $data[$current]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isset($data[$current]) && is_array($data[$current])) {
|
||||||
|
$this->stripNestedRecursive($data[$current], $parts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,17 @@ enum CashTransactionType: string
|
|||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
case DEPOSIT = 'deposit';
|
case DEPOSIT = 'deposit';
|
||||||
case WITHDRAWAL = 'withdrawal';
|
|
||||||
case EXPENSE = 'expense';
|
case EXPENSE = 'expense';
|
||||||
case TRANSFER = 'transfer';
|
case TRANSFER = 'transfer';
|
||||||
|
case WITHDRAWAL = 'withdrawal';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::DEPOSIT => 'Setoran',
|
||||||
|
self::EXPENSE => 'Pengeluaran',
|
||||||
|
self::TRANSFER => 'Transfer',
|
||||||
|
self::WITHDRAWAL => 'Penarikan',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Enums\Concerns;
|
namespace App\Enums\Concerns;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
trait HasValues
|
trait HasValues
|
||||||
{
|
{
|
||||||
public static function values(): array
|
public static function values(): array
|
||||||
{
|
{
|
||||||
return array_column(self::cases(), 'value');
|
return array_column(self::cases(), 'value');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<int, array{value: string, label: string}>
|
||||||
|
*/
|
||||||
|
public static function toSelect(): Collection
|
||||||
|
{
|
||||||
|
return collect(self::cases())->map(fn ($case) => [
|
||||||
|
'value' => $case->value,
|
||||||
|
'label' => $case->label(),
|
||||||
|
])->values();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,16 @@ enum CuttingStatus: string
|
|||||||
{
|
{
|
||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
case IN_PROGRESS = 'in_progress';
|
|
||||||
case COMPLETED = 'completed';
|
|
||||||
case CANCELLED = 'cancelled';
|
case CANCELLED = 'cancelled';
|
||||||
|
case COMPLETED = 'completed';
|
||||||
|
case IN_PROGRESS = 'in_progress';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::CANCELLED => 'Dibatalkan',
|
||||||
|
self::COMPLETED => 'Selesai',
|
||||||
|
self::IN_PROGRESS => 'Dalam Proses',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,20 @@ enum EmployeeAdvanceStatus: string
|
|||||||
{
|
{
|
||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
case PENDING = 'pending';
|
|
||||||
case APPROVED = 'approved';
|
case APPROVED = 'approved';
|
||||||
case PAID = 'paid';
|
|
||||||
case REJECTED = 'rejected';
|
|
||||||
case CANCELLED = 'cancelled';
|
case CANCELLED = 'cancelled';
|
||||||
|
case PAID = 'paid';
|
||||||
|
case PENDING = 'pending';
|
||||||
|
case REJECTED = 'rejected';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::APPROVED => 'Disetujui',
|
||||||
|
self::CANCELLED => 'Dibatalkan',
|
||||||
|
self::PAID => 'Dibayar',
|
||||||
|
self::PENDING => 'Menunggu',
|
||||||
|
self::REJECTED => 'Ditolak',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,20 @@ enum EmploymentStatus: string
|
|||||||
{
|
{
|
||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
case FULL_TIME = 'full_time';
|
|
||||||
case PART_TIME = 'part_time';
|
|
||||||
case CONTRACT = 'contract';
|
case CONTRACT = 'contract';
|
||||||
|
case FULL_TIME = 'full_time';
|
||||||
case INTERNSHIP = 'internship';
|
case INTERNSHIP = 'internship';
|
||||||
|
case PART_TIME = 'part_time';
|
||||||
case RESIGNED = 'resigned';
|
case RESIGNED = 'resigned';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::CONTRACT => 'Kontrak',
|
||||||
|
self::FULL_TIME => 'Penuh Waktu',
|
||||||
|
self::INTERNSHIP => 'Magang',
|
||||||
|
self::PART_TIME => 'Paruh Waktu',
|
||||||
|
self::RESIGNED => 'Keluar',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,14 @@ enum Gender: string
|
|||||||
{
|
{
|
||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
case MALE = 'male';
|
|
||||||
case FEMALE = 'female';
|
case FEMALE = 'female';
|
||||||
|
case MALE = 'male';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::FEMALE => 'Perempuan',
|
||||||
|
self::MALE => 'Laki-laki',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,18 @@ enum LeaveRequestStatus: string
|
|||||||
{
|
{
|
||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
case PENDING = 'pending';
|
|
||||||
case APPROVED = 'approved';
|
case APPROVED = 'approved';
|
||||||
case REJECTED = 'rejected';
|
|
||||||
case CANCELLED = 'cancelled';
|
case CANCELLED = 'cancelled';
|
||||||
|
case PENDING = 'pending';
|
||||||
|
case REJECTED = 'rejected';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::APPROVED => 'Disetujui',
|
||||||
|
self::CANCELLED => 'Dibatalkan',
|
||||||
|
self::PENDING => 'Menunggu',
|
||||||
|
self::REJECTED => 'Ditolak',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,4 +10,12 @@ enum PayrollAdjustmentType: string
|
|||||||
|
|
||||||
case BONUS = 'bonus';
|
case BONUS = 'bonus';
|
||||||
case DEDUCTION = 'deduction';
|
case DEDUCTION = 'deduction';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::BONUS => 'Bonus',
|
||||||
|
self::DEDUCTION => 'Potongan',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,14 @@ enum PayrollPeriodStatus: string
|
|||||||
{
|
{
|
||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
case OPEN = 'open';
|
|
||||||
case CLOSED = 'closed';
|
case CLOSED = 'closed';
|
||||||
|
case OPEN = 'open';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::CLOSED => 'Tutup',
|
||||||
|
self::OPEN => 'Buka',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,16 @@ enum PayrollStatus: string
|
|||||||
{
|
{
|
||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
case UNPAID = 'unpaid';
|
|
||||||
case PAID = 'paid';
|
|
||||||
case CANCELLED = 'cancelled';
|
case CANCELLED = 'cancelled';
|
||||||
|
case PAID = 'paid';
|
||||||
|
case UNPAID = 'unpaid';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::CANCELLED => 'Dibatalkan',
|
||||||
|
self::PAID => 'Dibayar',
|
||||||
|
self::UNPAID => 'Belum Dibayar',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
184
app/Enums/Permission.php
Normal file
184
app/Enums/Permission.php
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum Permission: string
|
||||||
|
{
|
||||||
|
// Dashboard
|
||||||
|
case DASHBOARD_VIEW = 'dashboard.view';
|
||||||
|
case DASHBOARD_ATTENDANCE = 'dashboard.attendance';
|
||||||
|
case DASHBOARD_REVENUE = 'dashboard.revenue';
|
||||||
|
case DASHBOARD_EXPENSE = 'dashboard.expense';
|
||||||
|
case DASHBOARD_ORDERS_CHANNEL = 'dashboard.orders_channel';
|
||||||
|
case DASHBOARD_ORDERS_PAYMENT = 'dashboard.orders_payment';
|
||||||
|
case DASHBOARD_ORDERS_MARKETING = 'dashboard.orders_marketing';
|
||||||
|
case DASHBOARD_ORDERS_STATUS = 'dashboard.orders_status';
|
||||||
|
case DASHBOARD_CASH = 'dashboard.cash';
|
||||||
|
|
||||||
|
// Analysis
|
||||||
|
case ANALYSIS_VIEW = 'analysis.view';
|
||||||
|
case ANALYSIS_ATTENDANCE = 'analysis.attendance';
|
||||||
|
case ANALYSIS_CASH = 'analysis.cash';
|
||||||
|
case ANALYSIS_PRODUCT_STOCK = 'analysis.product_stock';
|
||||||
|
case ANALYSIS_REVENUE = 'analysis.revenue';
|
||||||
|
case ANALYSIS_EXPENSE = 'analysis.expense';
|
||||||
|
case ANALYSIS_BUSY_HOURS = 'analysis.busy_hours';
|
||||||
|
case ANALYSIS_PROFIT_ORDERS = 'analysis.profit_orders';
|
||||||
|
case ANALYSIS_PROFIT_HPP = 'analysis.profit_hpp';
|
||||||
|
case ANALYSIS_PROFIT_GROSS = 'analysis.profit_gross';
|
||||||
|
case ANALYSIS_PROFIT_MARGIN = 'analysis.profit_margin';
|
||||||
|
case ANALYSIS_TOP_CUSTOMERS = 'analysis.top_customers';
|
||||||
|
case ANALYSIS_TOP_PRODUCTS = 'analysis.top_products';
|
||||||
|
case ANALYSIS_MARKETING_SALES = 'analysis.marketing_sales';
|
||||||
|
case ANALYSIS_RAW_MATERIALS = 'analysis.raw_materials';
|
||||||
|
|
||||||
|
// Employees
|
||||||
|
case EMPLOYEES_VIEW = 'employees.view';
|
||||||
|
case EMPLOYEES_CREATE = 'employees.create';
|
||||||
|
case EMPLOYEES_UPDATE = 'employees.update';
|
||||||
|
case EMPLOYEES_DELETE = 'employees.delete';
|
||||||
|
case EMPLOYEES_TOGGLE_STATUS = 'employees.toggle_status';
|
||||||
|
case EMPLOYEES_RESET_PASSWORD = 'employees.reset_password';
|
||||||
|
|
||||||
|
// Attendances
|
||||||
|
case ATTENDANCES_VIEW = 'attendances.view';
|
||||||
|
case ATTENDANCES_CREATE = 'attendances.create';
|
||||||
|
case ATTENDANCES_DELETE = 'attendances.delete';
|
||||||
|
case ATTENDANCES_MANAGE = 'attendances.manage';
|
||||||
|
|
||||||
|
// Leave Requests
|
||||||
|
case LEAVE_REQUESTS_VIEW = 'leave_requests.view';
|
||||||
|
case LEAVE_REQUESTS_CREATE = 'leave_requests.create';
|
||||||
|
case LEAVE_REQUESTS_UPDATE = 'leave_requests.update';
|
||||||
|
case LEAVE_REQUESTS_DELETE = 'leave_requests.delete';
|
||||||
|
case LEAVE_REQUESTS_VERIFY = 'leave_requests.verify';
|
||||||
|
|
||||||
|
// Categories
|
||||||
|
case CATEGORIES_VIEW = 'categories.view';
|
||||||
|
case CATEGORIES_CREATE = 'categories.create';
|
||||||
|
case CATEGORIES_UPDATE = 'categories.update';
|
||||||
|
case CATEGORIES_DELETE = 'categories.delete';
|
||||||
|
|
||||||
|
// Customers
|
||||||
|
case CUSTOMERS_VIEW = 'customers.view';
|
||||||
|
case CUSTOMERS_CREATE = 'customers.create';
|
||||||
|
case CUSTOMERS_UPDATE = 'customers.update';
|
||||||
|
case CUSTOMERS_DELETE = 'customers.delete';
|
||||||
|
|
||||||
|
// Products
|
||||||
|
case PRODUCTS_VIEW = 'products.view';
|
||||||
|
case PRODUCTS_CREATE = 'products.create';
|
||||||
|
case PRODUCTS_UPDATE = 'products.update';
|
||||||
|
case PRODUCTS_DELETE = 'products.delete';
|
||||||
|
case PRODUCTS_TOGGLE_STATUS = 'products.toggle_status';
|
||||||
|
|
||||||
|
// Stocks
|
||||||
|
case STOCKS_VIEW = 'stocks.view';
|
||||||
|
|
||||||
|
// Orders
|
||||||
|
case ORDERS_VIEW = 'orders.view';
|
||||||
|
case ORDERS_CREATE = 'orders.create';
|
||||||
|
case ORDERS_UPDATE = 'orders.update';
|
||||||
|
case ORDERS_DELETE = 'orders.delete';
|
||||||
|
case ORDERS_SEND = 'orders.send';
|
||||||
|
case ORDERS_COMPLETE = 'orders.complete';
|
||||||
|
case ORDERS_CANCEL = 'orders.cancel';
|
||||||
|
|
||||||
|
// Cuttings
|
||||||
|
case CUTTINGS_VIEW = 'cuttings.view';
|
||||||
|
case CUTTINGS_CREATE = 'cuttings.create';
|
||||||
|
case CUTTINGS_UPDATE = 'cuttings.update';
|
||||||
|
case CUTTINGS_DELETE = 'cuttings.delete';
|
||||||
|
case CUTTINGS_COMPLETE = 'cuttings.complete';
|
||||||
|
|
||||||
|
// Cash
|
||||||
|
case CASH_VIEW = 'cash.view';
|
||||||
|
case CASH_DEPOSIT = 'cash.deposit';
|
||||||
|
case CASH_WITHDRAW = 'cash.withdraw';
|
||||||
|
case CASH_UPDATE = 'cash.update';
|
||||||
|
case CASH_DELETE = 'cash.delete';
|
||||||
|
|
||||||
|
// Expenses
|
||||||
|
case EXPENSES_VIEW = 'expenses.view';
|
||||||
|
case EXPENSES_CREATE = 'expenses.create';
|
||||||
|
case EXPENSES_UPDATE = 'expenses.update';
|
||||||
|
case EXPENSES_DELETE = 'expenses.delete';
|
||||||
|
|
||||||
|
// Activity Logs
|
||||||
|
case ACTIVITY_LOGS_VIEW = 'activity_logs.view';
|
||||||
|
|
||||||
|
// Employee Advances
|
||||||
|
case EMPLOYEE_ADVANCES_VIEW = 'employee_advances.view';
|
||||||
|
case EMPLOYEE_ADVANCES_CREATE = 'employee_advances.create';
|
||||||
|
case EMPLOYEE_ADVANCES_UPDATE = 'employee_advances.update';
|
||||||
|
case EMPLOYEE_ADVANCES_DELETE = 'employee_advances.delete';
|
||||||
|
case EMPLOYEE_ADVANCES_PAY = 'employee_advances.pay';
|
||||||
|
case EMPLOYEE_ADVANCES_VERIFY = 'employee_advances.verify';
|
||||||
|
|
||||||
|
// Payroll
|
||||||
|
case PAYROLL_VIEW = 'payroll.view';
|
||||||
|
case PAYROLL_PAY = 'payroll.pay';
|
||||||
|
case PAYROLL_CANCEL = 'payroll.cancel';
|
||||||
|
case PAYROLL_ADJUST = 'payroll.adjust';
|
||||||
|
|
||||||
|
// Owner Verifications
|
||||||
|
case OWNER_VERIFICATIONS_VIEW = 'owner_verifications.view';
|
||||||
|
case OWNER_VERIFICATIONS_VERIFY = 'owner_verifications.verify';
|
||||||
|
case OWNER_VERIFICATIONS_REJECT = 'owner_verifications.reject';
|
||||||
|
|
||||||
|
// Restocks
|
||||||
|
case RESTOCKS_VIEW = 'restocks.view';
|
||||||
|
case RESTOCKS_CREATE = 'restocks.create';
|
||||||
|
case RESTOCKS_UPDATE = 'restocks.update';
|
||||||
|
case RESTOCKS_DELETE = 'restocks.delete';
|
||||||
|
|
||||||
|
// Raw Materials
|
||||||
|
case RAW_MATERIALS_VIEW = 'raw_materials.view';
|
||||||
|
case RAW_MATERIALS_CREATE = 'raw_materials.create';
|
||||||
|
case RAW_MATERIALS_UPDATE = 'raw_materials.update';
|
||||||
|
case RAW_MATERIALS_DELETE = 'raw_materials.delete';
|
||||||
|
case RAW_MATERIALS_TOGGLE_STATUS = 'raw_materials.toggle_status';
|
||||||
|
|
||||||
|
// Suppliers
|
||||||
|
case SUPPLIERS_VIEW = 'suppliers.view';
|
||||||
|
case SUPPLIERS_CREATE = 'suppliers.create';
|
||||||
|
case SUPPLIERS_UPDATE = 'suppliers.update';
|
||||||
|
case SUPPLIERS_DELETE = 'suppliers.delete';
|
||||||
|
|
||||||
|
// Purchases
|
||||||
|
case PURCHASES_VIEW = 'purchases.view';
|
||||||
|
case PURCHASES_CREATE = 'purchases.create';
|
||||||
|
case PURCHASES_UPDATE = 'purchases.update';
|
||||||
|
case PURCHASES_DELETE = 'purchases.delete';
|
||||||
|
|
||||||
|
// Stok Opnames
|
||||||
|
case STOK_OPNAMES_VIEW = 'stok_opnames.view';
|
||||||
|
case STOK_OPNAMES_CREATE = 'stok_opnames.create';
|
||||||
|
case STOK_OPNAMES_UPDATE = 'stok_opnames.update';
|
||||||
|
case STOK_OPNAMES_DELETE = 'stok_opnames.delete';
|
||||||
|
case STOK_OPNAMES_SUBMIT = 'stok_opnames.submit';
|
||||||
|
case STOK_OPNAMES_VERIFY = 'stok_opnames.verify';
|
||||||
|
|
||||||
|
// Roles
|
||||||
|
case ROLES_VIEW = 'roles.view';
|
||||||
|
case ROLES_CREATE = 'roles.create';
|
||||||
|
case ROLES_UPDATE = 'roles.update';
|
||||||
|
case ROLES_DELETE = 'roles.delete';
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
case SETTINGS_VIEW_SYSTEM = 'settings.view_system';
|
||||||
|
case SETTINGS_UPDATE_SYSTEM = 'settings.update_system';
|
||||||
|
case SETTINGS_VIEW_HOMEPAGE = 'settings.view_homepage';
|
||||||
|
case SETTINGS_UPDATE_HOMEPAGE = 'settings.update_homepage';
|
||||||
|
case SETTINGS_VIEW_SOCIAL_MEDIA = 'settings.view_social_media';
|
||||||
|
case SETTINGS_UPDATE_SOCIAL_MEDIA = 'settings.update_social_media';
|
||||||
|
case SETTINGS_VIEW_MARKETPLACE = 'settings.view_marketplace';
|
||||||
|
case SETTINGS_UPDATE_MARKETPLACE = 'settings.update_marketplace';
|
||||||
|
case SETTINGS_VIEW_HR = 'settings.view_hr';
|
||||||
|
case SETTINGS_UPDATE_HR = 'settings.update_hr';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,4 +11,13 @@ enum RawMaterialUnit: string
|
|||||||
case KG = 'kg';
|
case KG = 'kg';
|
||||||
case METER = 'meter';
|
case METER = 'meter';
|
||||||
case YARD = 'yard';
|
case YARD = 'yard';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::KG => 'Kg',
|
||||||
|
self::METER => 'Meter',
|
||||||
|
self::YARD => 'Yard',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
458
app/Enums/Role.php
Normal file
458
app/Enums/Role.php
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
use App\Traits\ProvidesEnumOptions;
|
||||||
|
|
||||||
|
enum Role: string
|
||||||
|
{
|
||||||
|
use ProvidesEnumOptions;
|
||||||
|
|
||||||
|
case DEVELOPER = 'developer';
|
||||||
|
case OWNER = 'owner';
|
||||||
|
case ADMIN_TOKO = 'admin-toko';
|
||||||
|
case ADMIN_BAHAN_BAKU = 'admin-bahan-baku';
|
||||||
|
case DIREKTUR = 'direktur';
|
||||||
|
case MARKETING_OFFLINE = 'marketing-offline';
|
||||||
|
case MARKETING_ONLINE = 'marketing-online';
|
||||||
|
case CASHIER = 'cashier';
|
||||||
|
case NON_OPERATOR = 'non-operator';
|
||||||
|
case STOK_OPNAME = 'stok-opname';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::DEVELOPER => 'Developer',
|
||||||
|
self::OWNER => 'Owner',
|
||||||
|
self::ADMIN_TOKO => 'Admin Toko',
|
||||||
|
self::ADMIN_BAHAN_BAKU => 'Admin Bahan Baku',
|
||||||
|
self::DIREKTUR => 'Direktur',
|
||||||
|
self::MARKETING_OFFLINE => 'Marketing Offline',
|
||||||
|
self::MARKETING_ONLINE => 'Marketing Online',
|
||||||
|
self::CASHIER => 'Kasir',
|
||||||
|
self::NON_OPERATOR => 'Non Operator',
|
||||||
|
self::STOK_OPNAME => 'Stok Opname',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function permissions(): array
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::DEVELOPER, self::OWNER => array_values(array_filter(
|
||||||
|
Permission::cases(),
|
||||||
|
fn (Permission $permission) => ! in_array($permission, [
|
||||||
|
Permission::ATTENDANCES_CREATE,
|
||||||
|
Permission::ATTENDANCES_DELETE,
|
||||||
|
|
||||||
|
Permission::STOK_OPNAMES_SUBMIT,
|
||||||
|
|
||||||
|
Permission::ROLES_VIEW,
|
||||||
|
Permission::ROLES_CREATE,
|
||||||
|
Permission::ROLES_UPDATE,
|
||||||
|
Permission::ROLES_DELETE,
|
||||||
|
], true)
|
||||||
|
)),
|
||||||
|
|
||||||
|
self::DIREKTUR => [
|
||||||
|
Permission::DASHBOARD_VIEW,
|
||||||
|
Permission::DASHBOARD_ATTENDANCE,
|
||||||
|
Permission::DASHBOARD_REVENUE,
|
||||||
|
Permission::DASHBOARD_EXPENSE,
|
||||||
|
Permission::DASHBOARD_ORDERS_CHANNEL,
|
||||||
|
Permission::DASHBOARD_ORDERS_PAYMENT,
|
||||||
|
Permission::DASHBOARD_ORDERS_MARKETING,
|
||||||
|
Permission::DASHBOARD_ORDERS_STATUS,
|
||||||
|
Permission::ANALYSIS_VIEW,
|
||||||
|
|
||||||
|
Permission::ANALYSIS_ATTENDANCE,
|
||||||
|
Permission::ANALYSIS_CASH,
|
||||||
|
Permission::ANALYSIS_PRODUCT_STOCK,
|
||||||
|
Permission::ANALYSIS_REVENUE,
|
||||||
|
Permission::ANALYSIS_EXPENSE,
|
||||||
|
Permission::ANALYSIS_BUSY_HOURS,
|
||||||
|
Permission::ANALYSIS_PROFIT_ORDERS,
|
||||||
|
Permission::ANALYSIS_PROFIT_HPP,
|
||||||
|
Permission::ANALYSIS_PROFIT_GROSS,
|
||||||
|
Permission::ANALYSIS_PROFIT_MARGIN,
|
||||||
|
Permission::ANALYSIS_TOP_CUSTOMERS,
|
||||||
|
Permission::ANALYSIS_TOP_PRODUCTS,
|
||||||
|
Permission::ANALYSIS_MARKETING_SALES,
|
||||||
|
|
||||||
|
Permission::EMPLOYEES_VIEW,
|
||||||
|
|
||||||
|
Permission::ATTENDANCES_VIEW,
|
||||||
|
Permission::ATTENDANCES_CREATE,
|
||||||
|
Permission::ATTENDANCES_DELETE,
|
||||||
|
Permission::ATTENDANCES_MANAGE,
|
||||||
|
|
||||||
|
Permission::LEAVE_REQUESTS_VIEW,
|
||||||
|
Permission::LEAVE_REQUESTS_CREATE,
|
||||||
|
Permission::LEAVE_REQUESTS_UPDATE,
|
||||||
|
Permission::LEAVE_REQUESTS_DELETE,
|
||||||
|
|
||||||
|
Permission::CATEGORIES_VIEW,
|
||||||
|
|
||||||
|
Permission::CUSTOMERS_VIEW,
|
||||||
|
|
||||||
|
Permission::PRODUCTS_VIEW,
|
||||||
|
Permission::STOCKS_VIEW,
|
||||||
|
|
||||||
|
Permission::ORDERS_VIEW,
|
||||||
|
|
||||||
|
Permission::CUTTINGS_VIEW,
|
||||||
|
|
||||||
|
Permission::CASH_VIEW,
|
||||||
|
|
||||||
|
Permission::EXPENSES_VIEW,
|
||||||
|
|
||||||
|
Permission::ACTIVITY_LOGS_VIEW,
|
||||||
|
|
||||||
|
Permission::EMPLOYEE_ADVANCES_VIEW,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_CREATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_UPDATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_DELETE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_PAY,
|
||||||
|
|
||||||
|
Permission::PAYROLL_VIEW,
|
||||||
|
],
|
||||||
|
|
||||||
|
self::ADMIN_TOKO => [
|
||||||
|
Permission::DASHBOARD_VIEW,
|
||||||
|
Permission::DASHBOARD_REVENUE,
|
||||||
|
Permission::DASHBOARD_EXPENSE,
|
||||||
|
Permission::DASHBOARD_ORDERS_CHANNEL,
|
||||||
|
Permission::DASHBOARD_ORDERS_PAYMENT,
|
||||||
|
Permission::DASHBOARD_ORDERS_MARKETING,
|
||||||
|
Permission::DASHBOARD_ORDERS_STATUS,
|
||||||
|
|
||||||
|
Permission::ANALYSIS_VIEW,
|
||||||
|
Permission::ANALYSIS_ATTENDANCE,
|
||||||
|
Permission::ANALYSIS_CASH,
|
||||||
|
Permission::ANALYSIS_PRODUCT_STOCK,
|
||||||
|
Permission::ANALYSIS_REVENUE,
|
||||||
|
Permission::ANALYSIS_EXPENSE,
|
||||||
|
Permission::ANALYSIS_BUSY_HOURS,
|
||||||
|
Permission::ANALYSIS_PROFIT_ORDERS,
|
||||||
|
Permission::ANALYSIS_PROFIT_HPP,
|
||||||
|
Permission::ANALYSIS_PROFIT_GROSS,
|
||||||
|
Permission::ANALYSIS_TOP_CUSTOMERS,
|
||||||
|
Permission::ANALYSIS_TOP_PRODUCTS,
|
||||||
|
Permission::ANALYSIS_MARKETING_SALES,
|
||||||
|
|
||||||
|
Permission::STOCKS_VIEW,
|
||||||
|
|
||||||
|
Permission::STOK_OPNAMES_VIEW,
|
||||||
|
|
||||||
|
Permission::ATTENDANCES_VIEW,
|
||||||
|
Permission::ATTENDANCES_CREATE,
|
||||||
|
Permission::ATTENDANCES_DELETE,
|
||||||
|
|
||||||
|
Permission::LEAVE_REQUESTS_VIEW,
|
||||||
|
Permission::LEAVE_REQUESTS_CREATE,
|
||||||
|
Permission::LEAVE_REQUESTS_UPDATE,
|
||||||
|
Permission::LEAVE_REQUESTS_DELETE,
|
||||||
|
|
||||||
|
Permission::RESTOCKS_VIEW,
|
||||||
|
Permission::RESTOCKS_CREATE,
|
||||||
|
Permission::RESTOCKS_UPDATE,
|
||||||
|
Permission::RESTOCKS_DELETE,
|
||||||
|
|
||||||
|
Permission::CUSTOMERS_VIEW,
|
||||||
|
Permission::CUSTOMERS_CREATE,
|
||||||
|
Permission::CUSTOMERS_UPDATE,
|
||||||
|
Permission::CUSTOMERS_DELETE,
|
||||||
|
|
||||||
|
Permission::PRODUCTS_VIEW,
|
||||||
|
Permission::PRODUCTS_CREATE,
|
||||||
|
Permission::PRODUCTS_UPDATE,
|
||||||
|
Permission::PRODUCTS_DELETE,
|
||||||
|
Permission::PRODUCTS_TOGGLE_STATUS,
|
||||||
|
Permission::STOCKS_VIEW,
|
||||||
|
|
||||||
|
Permission::OWNER_VERIFICATIONS_VIEW,
|
||||||
|
|
||||||
|
Permission::ORDERS_VIEW,
|
||||||
|
Permission::ORDERS_CREATE,
|
||||||
|
Permission::ORDERS_UPDATE,
|
||||||
|
Permission::ORDERS_DELETE,
|
||||||
|
Permission::ORDERS_SEND,
|
||||||
|
Permission::ORDERS_COMPLETE,
|
||||||
|
Permission::ORDERS_CANCEL,
|
||||||
|
|
||||||
|
Permission::CASH_VIEW,
|
||||||
|
Permission::CASH_DEPOSIT,
|
||||||
|
Permission::CASH_WITHDRAW,
|
||||||
|
Permission::CASH_UPDATE,
|
||||||
|
Permission::CASH_DELETE,
|
||||||
|
|
||||||
|
Permission::EXPENSES_VIEW,
|
||||||
|
Permission::EXPENSES_CREATE,
|
||||||
|
Permission::EXPENSES_UPDATE,
|
||||||
|
Permission::EXPENSES_DELETE,
|
||||||
|
|
||||||
|
Permission::ACTIVITY_LOGS_VIEW,
|
||||||
|
|
||||||
|
Permission::EMPLOYEE_ADVANCES_VIEW,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_CREATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_UPDATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_DELETE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_PAY,
|
||||||
|
|
||||||
|
Permission::PAYROLL_VIEW,
|
||||||
|
Permission::PAYROLL_ADJUST,
|
||||||
|
|
||||||
|
Permission::SETTINGS_VIEW_SYSTEM,
|
||||||
|
Permission::SETTINGS_UPDATE_SYSTEM,
|
||||||
|
Permission::SETTINGS_VIEW_SOCIAL_MEDIA,
|
||||||
|
Permission::SETTINGS_UPDATE_SOCIAL_MEDIA,
|
||||||
|
Permission::SETTINGS_VIEW_MARKETPLACE,
|
||||||
|
Permission::SETTINGS_UPDATE_MARKETPLACE,
|
||||||
|
Permission::SETTINGS_VIEW_HR,
|
||||||
|
Permission::SETTINGS_UPDATE_HR,
|
||||||
|
Permission::SETTINGS_VIEW_HOMEPAGE,
|
||||||
|
Permission::SETTINGS_UPDATE_HOMEPAGE,
|
||||||
|
|
||||||
|
Permission::EMPLOYEES_VIEW,
|
||||||
|
Permission::EMPLOYEES_CREATE,
|
||||||
|
Permission::EMPLOYEES_UPDATE,
|
||||||
|
Permission::EMPLOYEES_TOGGLE_STATUS,
|
||||||
|
Permission::EMPLOYEES_DELETE,
|
||||||
|
],
|
||||||
|
|
||||||
|
self::CASHIER => [
|
||||||
|
Permission::DASHBOARD_VIEW,
|
||||||
|
Permission::DASHBOARD_REVENUE,
|
||||||
|
Permission::DASHBOARD_ORDERS_CHANNEL,
|
||||||
|
Permission::DASHBOARD_ORDERS_PAYMENT,
|
||||||
|
Permission::DASHBOARD_ORDERS_STATUS,
|
||||||
|
|
||||||
|
Permission::ANALYSIS_VIEW,
|
||||||
|
Permission::ANALYSIS_ATTENDANCE,
|
||||||
|
Permission::ANALYSIS_REVENUE,
|
||||||
|
Permission::ANALYSIS_PROFIT_ORDERS,
|
||||||
|
Permission::ANALYSIS_TOP_CUSTOMERS,
|
||||||
|
Permission::ANALYSIS_TOP_PRODUCTS,
|
||||||
|
|
||||||
|
Permission::ATTENDANCES_VIEW,
|
||||||
|
Permission::ATTENDANCES_CREATE,
|
||||||
|
Permission::ATTENDANCES_DELETE,
|
||||||
|
|
||||||
|
Permission::LEAVE_REQUESTS_VIEW,
|
||||||
|
Permission::LEAVE_REQUESTS_CREATE,
|
||||||
|
Permission::LEAVE_REQUESTS_UPDATE,
|
||||||
|
Permission::LEAVE_REQUESTS_DELETE,
|
||||||
|
|
||||||
|
Permission::CUSTOMERS_VIEW,
|
||||||
|
Permission::CUSTOMERS_CREATE,
|
||||||
|
Permission::CUSTOMERS_UPDATE,
|
||||||
|
Permission::CUSTOMERS_DELETE,
|
||||||
|
|
||||||
|
Permission::PRODUCTS_VIEW,
|
||||||
|
|
||||||
|
Permission::ORDERS_VIEW,
|
||||||
|
Permission::ORDERS_CREATE,
|
||||||
|
Permission::ORDERS_UPDATE,
|
||||||
|
Permission::ORDERS_DELETE,
|
||||||
|
Permission::ORDERS_SEND,
|
||||||
|
Permission::ORDERS_COMPLETE,
|
||||||
|
Permission::ORDERS_CANCEL,
|
||||||
|
|
||||||
|
Permission::EMPLOYEE_ADVANCES_VIEW,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_CREATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_UPDATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_DELETE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_PAY,
|
||||||
|
|
||||||
|
Permission::PAYROLL_VIEW,
|
||||||
|
Permission::PAYROLL_ADJUST,
|
||||||
|
],
|
||||||
|
|
||||||
|
self::ADMIN_BAHAN_BAKU => [
|
||||||
|
Permission::DASHBOARD_VIEW,
|
||||||
|
|
||||||
|
Permission::EMPLOYEES_VIEW,
|
||||||
|
Permission::EMPLOYEES_CREATE,
|
||||||
|
Permission::EMPLOYEES_UPDATE,
|
||||||
|
Permission::EMPLOYEES_TOGGLE_STATUS,
|
||||||
|
Permission::EMPLOYEES_DELETE,
|
||||||
|
|
||||||
|
Permission::LEAVE_REQUESTS_VIEW,
|
||||||
|
Permission::LEAVE_REQUESTS_CREATE,
|
||||||
|
Permission::LEAVE_REQUESTS_UPDATE,
|
||||||
|
Permission::LEAVE_REQUESTS_DELETE,
|
||||||
|
|
||||||
|
Permission::CATEGORIES_VIEW,
|
||||||
|
Permission::CATEGORIES_CREATE,
|
||||||
|
Permission::CATEGORIES_UPDATE,
|
||||||
|
Permission::CATEGORIES_DELETE,
|
||||||
|
|
||||||
|
Permission::SUPPLIERS_VIEW,
|
||||||
|
Permission::SUPPLIERS_CREATE,
|
||||||
|
Permission::SUPPLIERS_UPDATE,
|
||||||
|
Permission::SUPPLIERS_DELETE,
|
||||||
|
|
||||||
|
Permission::RAW_MATERIALS_VIEW,
|
||||||
|
Permission::RAW_MATERIALS_CREATE,
|
||||||
|
Permission::RAW_MATERIALS_UPDATE,
|
||||||
|
Permission::RAW_MATERIALS_TOGGLE_STATUS,
|
||||||
|
Permission::STOCKS_VIEW,
|
||||||
|
|
||||||
|
Permission::OWNER_VERIFICATIONS_VIEW,
|
||||||
|
|
||||||
|
Permission::PRODUCTS_VIEW,
|
||||||
|
Permission::PRODUCTS_CREATE,
|
||||||
|
Permission::PRODUCTS_UPDATE,
|
||||||
|
Permission::PRODUCTS_DELETE,
|
||||||
|
Permission::PRODUCTS_TOGGLE_STATUS,
|
||||||
|
|
||||||
|
Permission::CUTTINGS_VIEW,
|
||||||
|
Permission::CUTTINGS_CREATE,
|
||||||
|
Permission::CUTTINGS_UPDATE,
|
||||||
|
Permission::CUTTINGS_DELETE,
|
||||||
|
Permission::CUTTINGS_COMPLETE,
|
||||||
|
Permission::PURCHASES_VIEW,
|
||||||
|
Permission::PURCHASES_CREATE,
|
||||||
|
Permission::PURCHASES_UPDATE,
|
||||||
|
Permission::PURCHASES_DELETE,
|
||||||
|
|
||||||
|
Permission::EMPLOYEE_ADVANCES_VIEW,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_CREATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_UPDATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_DELETE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_PAY,
|
||||||
|
|
||||||
|
Permission::ACTIVITY_LOGS_VIEW,
|
||||||
|
|
||||||
|
Permission::PAYROLL_VIEW,
|
||||||
|
],
|
||||||
|
|
||||||
|
self::MARKETING_OFFLINE, self::MARKETING_ONLINE => [
|
||||||
|
Permission::DASHBOARD_VIEW,
|
||||||
|
Permission::DASHBOARD_REVENUE,
|
||||||
|
Permission::DASHBOARD_ORDERS_CHANNEL,
|
||||||
|
Permission::DASHBOARD_ORDERS_PAYMENT,
|
||||||
|
Permission::DASHBOARD_ORDERS_MARKETING,
|
||||||
|
Permission::DASHBOARD_ORDERS_STATUS,
|
||||||
|
|
||||||
|
Permission::ANALYSIS_VIEW,
|
||||||
|
Permission::ANALYSIS_ATTENDANCE,
|
||||||
|
Permission::ANALYSIS_REVENUE,
|
||||||
|
Permission::ANALYSIS_PROFIT_ORDERS,
|
||||||
|
Permission::ANALYSIS_TOP_PRODUCTS,
|
||||||
|
Permission::ANALYSIS_TOP_CUSTOMERS,
|
||||||
|
|
||||||
|
Permission::ATTENDANCES_VIEW,
|
||||||
|
Permission::ATTENDANCES_CREATE,
|
||||||
|
|
||||||
|
Permission::LEAVE_REQUESTS_VIEW,
|
||||||
|
Permission::LEAVE_REQUESTS_CREATE,
|
||||||
|
Permission::LEAVE_REQUESTS_UPDATE,
|
||||||
|
Permission::LEAVE_REQUESTS_DELETE,
|
||||||
|
|
||||||
|
Permission::PRODUCTS_VIEW,
|
||||||
|
|
||||||
|
Permission::ORDERS_VIEW,
|
||||||
|
|
||||||
|
Permission::EMPLOYEE_ADVANCES_VIEW,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_CREATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_UPDATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_DELETE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_PAY,
|
||||||
|
|
||||||
|
Permission::PAYROLL_VIEW,
|
||||||
|
],
|
||||||
|
|
||||||
|
self::NON_OPERATOR => [
|
||||||
|
Permission::DASHBOARD_VIEW,
|
||||||
|
|
||||||
|
Permission::ANALYSIS_VIEW,
|
||||||
|
Permission::ANALYSIS_ATTENDANCE,
|
||||||
|
|
||||||
|
Permission::ATTENDANCES_VIEW,
|
||||||
|
Permission::ATTENDANCES_CREATE,
|
||||||
|
|
||||||
|
Permission::LEAVE_REQUESTS_VIEW,
|
||||||
|
Permission::LEAVE_REQUESTS_CREATE,
|
||||||
|
Permission::LEAVE_REQUESTS_UPDATE,
|
||||||
|
Permission::LEAVE_REQUESTS_DELETE,
|
||||||
|
|
||||||
|
Permission::EMPLOYEE_ADVANCES_VIEW,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_CREATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_UPDATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_DELETE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_PAY,
|
||||||
|
|
||||||
|
Permission::PAYROLL_VIEW,
|
||||||
|
],
|
||||||
|
|
||||||
|
self::STOK_OPNAME => [
|
||||||
|
Permission::DASHBOARD_VIEW,
|
||||||
|
|
||||||
|
Permission::ATTENDANCES_VIEW,
|
||||||
|
Permission::ATTENDANCES_CREATE,
|
||||||
|
|
||||||
|
Permission::LEAVE_REQUESTS_VIEW,
|
||||||
|
Permission::LEAVE_REQUESTS_CREATE,
|
||||||
|
Permission::LEAVE_REQUESTS_UPDATE,
|
||||||
|
Permission::LEAVE_REQUESTS_DELETE,
|
||||||
|
|
||||||
|
Permission::PRODUCTS_VIEW,
|
||||||
|
Permission::STOCKS_VIEW,
|
||||||
|
|
||||||
|
Permission::STOK_OPNAMES_VIEW,
|
||||||
|
Permission::STOK_OPNAMES_CREATE,
|
||||||
|
Permission::STOK_OPNAMES_UPDATE,
|
||||||
|
Permission::STOK_OPNAMES_DELETE,
|
||||||
|
Permission::STOK_OPNAMES_SUBMIT,
|
||||||
|
|
||||||
|
Permission::EMPLOYEE_ADVANCES_VIEW,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_CREATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_UPDATE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_DELETE,
|
||||||
|
Permission::EMPLOYEE_ADVANCES_PAY,
|
||||||
|
|
||||||
|
Permission::PAYROLL_VIEW,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isAssignable(): bool
|
||||||
|
{
|
||||||
|
return $this !== self::DEVELOPER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<array{value: string, label: string}>
|
||||||
|
*/
|
||||||
|
public static function assignableSelectOptions(): array
|
||||||
|
{
|
||||||
|
return collect(self::cases())
|
||||||
|
->filter(fn (self $role) => $role->isAssignable())
|
||||||
|
->map(fn (self $role) => [
|
||||||
|
'value' => $role->value,
|
||||||
|
'label' => $role->label(),
|
||||||
|
])
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public static function assignableValues(): array
|
||||||
|
{
|
||||||
|
return collect(self::cases())
|
||||||
|
->filter(fn (self $role) => $role->isAssignable())
|
||||||
|
->map(fn (self $role) => $role->value)
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public static function values(): array
|
||||||
|
{
|
||||||
|
return array_column(self::cases(), 'value');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,9 +8,20 @@ enum StokOpnameStatus: string
|
|||||||
{
|
{
|
||||||
use HasValues;
|
use HasValues;
|
||||||
|
|
||||||
|
case CANCELLED = 'cancelled';
|
||||||
|
case COMPLETED = 'completed';
|
||||||
case DRAFT = 'draft';
|
case DRAFT = 'draft';
|
||||||
case IN_PROGRESS = 'in_progress';
|
case IN_PROGRESS = 'in_progress';
|
||||||
case COMPLETED = 'completed';
|
|
||||||
case VERIFIED = 'verified';
|
case VERIFIED = 'verified';
|
||||||
case CANCELLED = 'cancelled';
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::CANCELLED => 'Dibatalkan',
|
||||||
|
self::COMPLETED => 'Selesai',
|
||||||
|
self::DRAFT => 'Draft',
|
||||||
|
self::IN_PROGRESS => 'Dalam Proses',
|
||||||
|
self::VERIFIED => 'Terverifikasi',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
class AdminSettingsController extends Controller
|
class AdminSettingsController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private AdminSettingsService $service
|
private readonly AdminSettingsService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
@ -70,7 +70,7 @@ public function updateHR(UpdateHRRequest $request): RedirectResponse
|
|||||||
{
|
{
|
||||||
$this->service->updateHR($request->validated());
|
$this->service->updateHR($request->validated());
|
||||||
|
|
||||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pengaturan hr berhasil diperbarui.']);
|
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pengaturan HR berhasil diperbarui.']);
|
||||||
|
|
||||||
return to_route('admin.settings.index');
|
return to_route('admin.settings.index');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Admin\Finance;
|
namespace App\Http\Controllers\Admin\Finance;
|
||||||
|
|
||||||
|
use App\Enums\CashTransactionType;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Admin\Finance\CashTransactionRequest;
|
use App\Http\Requests\Admin\Finance\CashTransactionRequest;
|
||||||
use App\Http\Requests\PaginatedRequest;
|
use App\Http\Requests\PaginatedRequest;
|
||||||
@ -14,7 +15,7 @@
|
|||||||
class CashAccountController extends Controller
|
class CashAccountController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private CashAccountService $service
|
private readonly CashAccountService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
@ -28,6 +29,9 @@ public function index(PaginatedRequest $request): Response
|
|||||||
filters: $request->only(['type']),
|
filters: $request->only(['type']),
|
||||||
),
|
),
|
||||||
'filters' => $request->only(['type']),
|
'filters' => $request->only(['type']),
|
||||||
|
'filterOptions' => [
|
||||||
|
'typeOptions' => CashTransactionType::toSelect(),
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class EmployeeAdvanceController extends Controller
|
class EmployeeAdvanceController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private EmployeeAdvanceService $service
|
private readonly EmployeeAdvanceService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class ExpenseController extends Controller
|
class ExpenseController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private ExpenseService $service
|
private readonly ExpenseService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
class PayrollAdjustmentController extends Controller
|
class PayrollAdjustmentController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private PayrollAdjustmentService $service
|
private readonly PayrollAdjustmentService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function store(PayrollAdjustmentRequest $request, Payroll $payroll): RedirectResponse
|
public function store(PayrollAdjustmentRequest $request, Payroll $payroll): RedirectResponse
|
||||||
@ -21,7 +21,7 @@ public function store(PayrollAdjustmentRequest $request, Payroll $payroll): Redi
|
|||||||
fn () => $this->service->create($payroll, $request->validated()),
|
fn () => $this->service->create($payroll, $request->validated()),
|
||||||
'Adjustment gaji berhasil ditambahkan.',
|
'Adjustment gaji berhasil ditambahkan.',
|
||||||
'admin.finance.payroll-periods.show',
|
'admin.finance.payroll-periods.show',
|
||||||
['payroll_period' => $payroll->payroll_period_id]
|
parameters : ['payroll_period' => $payroll->payroll_period_id]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ public function destroy(PayrollAdjustment $payrollAdjustment): RedirectResponse
|
|||||||
fn () => $this->service->delete($payrollAdjustment),
|
fn () => $this->service->delete($payrollAdjustment),
|
||||||
'Adjustment gaji berhasil dihapus.',
|
'Adjustment gaji berhasil dihapus.',
|
||||||
'admin.finance.payroll-periods.show',
|
'admin.finance.payroll-periods.show',
|
||||||
['payroll_period' => $payrollAdjustment->payroll->payroll_period_id]
|
parameters: ['payroll_period' => $payrollAdjustment->payroll->payroll_period_id]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
class PayrollController extends Controller
|
class PayrollController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private PayrollPeriodService $service
|
private readonly PayrollPeriodService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function pay(Payroll $payroll): RedirectResponse
|
public function pay(Payroll $payroll): RedirectResponse
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class PayrollPeriodController extends Controller
|
class PayrollPeriodController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private PayrollPeriodService $service
|
private readonly PayrollPeriodService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
class AttendanceController extends Controller
|
class AttendanceController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private AttendanceService $service
|
private readonly AttendanceService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
|
|||||||
@ -10,11 +10,12 @@
|
|||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Inertia\Inertia;
|
use Inertia\Inertia;
|
||||||
use Inertia\Response;
|
use Inertia\Response;
|
||||||
|
use Spatie\Permission\Models\Role;
|
||||||
|
|
||||||
class EmployeeController extends Controller
|
class EmployeeController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private EmployeeService $service
|
private readonly EmployeeService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
@ -30,13 +31,15 @@ public function index(PaginatedRequest $request): Response
|
|||||||
|
|
||||||
public function create(): Response
|
public function create(): Response
|
||||||
{
|
{
|
||||||
return Inertia::render('admin/hr/employee/create');
|
return Inertia::render('admin/hr/employee/create', [
|
||||||
|
'roles' => Role::where('name', '!=', 'Developer')->get(['id', 'name']),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(EmployeeRequest $request): RedirectResponse
|
public function store(EmployeeRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
return $this->handleAction(
|
return $this->handleAction(
|
||||||
fn () => $this->service->create($request->validated()),
|
fn() => $this->service->create($request->validated()),
|
||||||
'Pegawai berhasil ditambahkan.',
|
'Pegawai berhasil ditambahkan.',
|
||||||
'admin.hr.employees.index'
|
'admin.hr.employees.index'
|
||||||
);
|
);
|
||||||
@ -44,17 +47,18 @@ public function store(EmployeeRequest $request): RedirectResponse
|
|||||||
|
|
||||||
public function edit(User $user): Response
|
public function edit(User $user): Response
|
||||||
{
|
{
|
||||||
$user->load(['userProfile', 'employee']);
|
$user->load(['userProfile', 'employee', 'roles']);
|
||||||
|
|
||||||
return Inertia::render('admin/hr/employee/edit', [
|
return Inertia::render('admin/hr/employee/edit', [
|
||||||
'employee' => $user,
|
'employee' => $user,
|
||||||
|
'roles' => Role::where('name', '!=', 'Developer')->get(['id', 'name']),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(EmployeeRequest $request, User $user): RedirectResponse
|
public function update(EmployeeRequest $request, User $user): RedirectResponse
|
||||||
{
|
{
|
||||||
return $this->handleAction(
|
return $this->handleAction(
|
||||||
fn () => $this->service->update($user, $request->validated()),
|
fn() => $this->service->update($user, $request->validated()),
|
||||||
'Pegawai berhasil diperbarui.',
|
'Pegawai berhasil diperbarui.',
|
||||||
'admin.hr.employees.index'
|
'admin.hr.employees.index'
|
||||||
);
|
);
|
||||||
@ -63,7 +67,7 @@ public function update(EmployeeRequest $request, User $user): RedirectResponse
|
|||||||
public function destroy(User $user): RedirectResponse
|
public function destroy(User $user): RedirectResponse
|
||||||
{
|
{
|
||||||
return $this->handleAction(
|
return $this->handleAction(
|
||||||
fn () => $this->service->delete($user),
|
fn() => $this->service->delete($user),
|
||||||
'Pegawai berhasil dihapus.',
|
'Pegawai berhasil dihapus.',
|
||||||
'admin.hr.employees.index'
|
'admin.hr.employees.index'
|
||||||
);
|
);
|
||||||
@ -82,7 +86,7 @@ public function toggleActive(User $user): RedirectResponse
|
|||||||
public function resetPassword(User $user): RedirectResponse
|
public function resetPassword(User $user): RedirectResponse
|
||||||
{
|
{
|
||||||
return $this->handleAction(
|
return $this->handleAction(
|
||||||
fn () => $this->service->resetPassword($user),
|
fn() => $this->service->resetPassword($user),
|
||||||
'Kata sandi pegawai berhasil direset ke kata sandi default.',
|
'Kata sandi pegawai berhasil direset ke kata sandi default.',
|
||||||
'admin.hr.employees.index'
|
'admin.hr.employees.index'
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Admin\HR;
|
namespace App\Http\Controllers\Admin\HR;
|
||||||
|
|
||||||
|
use App\Enums\LeaveRequestStatus;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Admin\HR\LeaveRequestRequest;
|
use App\Http\Requests\Admin\HR\LeaveRequestRequest;
|
||||||
use App\Http\Requests\PaginatedRequest;
|
use App\Http\Requests\PaginatedRequest;
|
||||||
@ -14,7 +15,7 @@
|
|||||||
class LeaveRequestController extends Controller
|
class LeaveRequestController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private LeaveRequestService $service
|
private readonly LeaveRequestService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
@ -25,6 +26,9 @@ public function index(PaginatedRequest $request): Response
|
|||||||
filters: $request->only(['status']),
|
filters: $request->only(['status']),
|
||||||
),
|
),
|
||||||
'filters' => $request->only(['status']),
|
'filters' => $request->only(['status']),
|
||||||
|
'filterOptions' => [
|
||||||
|
'statusOptions' => LeaveRequestStatus::toSelect(),
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class CuttingController extends Controller
|
class CuttingController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private CuttingService $service,
|
private readonly CuttingService $service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class PurchaseController extends Controller
|
class PurchaseController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private PurchaseService $service,
|
private readonly PurchaseService $service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class RestockController extends Controller
|
class RestockController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private RestockService $service,
|
private readonly RestockService $service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class TransactionController extends Controller
|
class TransactionController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private TransactionService $service,
|
private readonly TransactionService $service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class CategoryController extends Controller
|
class CategoryController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private CategoryService $service
|
private readonly CategoryService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class CustomerController extends Controller
|
class CustomerController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private CustomerService $service
|
private readonly CustomerService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -15,8 +15,8 @@
|
|||||||
class ProductController extends Controller
|
class ProductController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private ProductService $service,
|
private readonly ProductService $service,
|
||||||
private CategoryService $categoryService,
|
private readonly CategoryService $categoryService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
class ProductVariantController extends Controller
|
class ProductVariantController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private ProductVariantService $variantService,
|
private readonly ProductVariantService $variantService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function edit(Product $product, ProductVariant $variant): Response
|
public function edit(Product $product, ProductVariant $variant): Response
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
class StockMutationController extends Controller
|
class StockMutationController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private StockMutationService $service = new StockMutationService,
|
private readonly StockMutationService $service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(StockMutationRequest $request, Product $product, ProductVariant $variant): Response
|
public function index(StockMutationRequest $request, Product $product, ProductVariant $variant): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class RawMaterialController extends Controller
|
class RawMaterialController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private RawMaterialService $service,
|
private readonly RawMaterialService $service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class RawMaterialVariantController extends Controller
|
class RawMaterialVariantController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private RawMaterialVariantService $variantService,
|
private readonly RawMaterialVariantService $variantService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function edit(RawMaterial $rawMaterial, RawMaterialPrice $variant): Response
|
public function edit(RawMaterial $rawMaterial, RawMaterialPrice $variant): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class SupplierController extends Controller
|
class SupplierController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private SupplierService $service
|
private readonly SupplierService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
class RoleController extends Controller
|
class RoleController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private RoleService $service
|
private readonly RoleService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function index(PaginatedRequest $request): Response
|
public function index(PaginatedRequest $request): Response
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
class PresignedUrlController extends Controller
|
class PresignedUrlController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $service
|
private readonly S3PresignedService $service
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function store(PresignedUrlRequest $request): JsonResponse
|
public function store(PresignedUrlRequest $request): JsonResponse
|
||||||
|
|||||||
@ -28,4 +28,9 @@ protected function handleAction(callable $action, string $successMessage, string
|
|||||||
return to_route($errorRoute ?? $redirectRoute, $parameters);
|
return to_route($errorRoute ?? $redirectRoute, $parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleToggle(callable $action, string $successMessage, string $redirectRoute): RedirectResponse
|
||||||
|
{
|
||||||
|
return $this->handleAction($action, $successMessage, $redirectRoute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,9 +12,6 @@
|
|||||||
|
|
||||||
class ProfileController extends Controller
|
class ProfileController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Show the user's profile settings page.
|
|
||||||
*/
|
|
||||||
public function edit(Request $request): Response
|
public function edit(Request $request): Response
|
||||||
{
|
{
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
@ -38,38 +35,37 @@ public function edit(Request $request): Response
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the user's profile information.
|
|
||||||
*/
|
|
||||||
public function update(ProfileUpdateRequest $request): RedirectResponse
|
public function update(ProfileUpdateRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
$validated = $request->validated();
|
return $this->handleAction(
|
||||||
$user = $request->user();
|
function () use ($request) {
|
||||||
|
$validated = $request->validated();
|
||||||
|
$user = $request->user();
|
||||||
|
|
||||||
$user->fill([
|
$user->fill([
|
||||||
'email' => $validated['email'],
|
'email' => $validated['email'],
|
||||||
'username' => $validated['username'],
|
'username' => $validated['username'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($user->isDirty('email')) {
|
if ($user->isDirty('email')) {
|
||||||
$user->email_verified_at = null;
|
$user->email_verified_at = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
$user->userProfile()->updateOrCreate(
|
$user->userProfile()->updateOrCreate(
|
||||||
[],
|
[],
|
||||||
[
|
[
|
||||||
'full_name' => $validated['full_name'],
|
'full_name' => $validated['full_name'],
|
||||||
'phone_number' => $validated['phone_number'] ?? null,
|
'phone_number' => $validated['phone_number'] ?? null,
|
||||||
'gender' => $validated['gender'] ?? null,
|
'gender' => $validated['gender'] ?? null,
|
||||||
'birth_date' => $validated['birth_date'] ?? null,
|
'birth_date' => $validated['birth_date'] ?? null,
|
||||||
'address' => $validated['address'] ?? null,
|
'address' => $validated['address'] ?? null,
|
||||||
],
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
'Profil berhasil diperbarui.',
|
||||||
|
'profile.edit',
|
||||||
);
|
);
|
||||||
|
|
||||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Profil berhasil diperbarui.']);
|
|
||||||
|
|
||||||
return to_route('profile.edit');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,26 +11,16 @@
|
|||||||
|
|
||||||
class SecurityController extends Controller
|
class SecurityController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Show the user's security settings page.
|
|
||||||
*/
|
|
||||||
public function edit(): Response
|
public function edit(): Response
|
||||||
{
|
{
|
||||||
$props = [
|
return Inertia::render('settings/security', [
|
||||||
'passwordRules' => Password::defaults()->toPasswordRulesString(),
|
'passwordRules' => Password::defaults()->toPasswordRulesString(),
|
||||||
];
|
]);
|
||||||
|
|
||||||
return Inertia::render('settings/security', $props);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the user's password.
|
|
||||||
*/
|
|
||||||
public function update(PasswordUpdateRequest $request): RedirectResponse
|
public function update(PasswordUpdateRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
$request->user()->update([
|
$request->user()->update(['password' => $request->password]);
|
||||||
'password' => $request->password,
|
|
||||||
]);
|
|
||||||
|
|
||||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil diperbarui.']);
|
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil diperbarui.']);
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,9 @@ public function share(Request $request): array
|
|||||||
'name' => config('app.name'),
|
'name' => config('app.name'),
|
||||||
'auth' => [
|
'auth' => [
|
||||||
'user' => $request->user()
|
'user' => $request->user()
|
||||||
? $request->user()->load('userProfile', 'roles', 'permissions')
|
? tap($request->user()->load('userProfile', 'roles'), function ($user) {
|
||||||
|
$user->setRelation('permissions', $user->getAllPermissions());
|
||||||
|
})
|
||||||
: null,
|
: null,
|
||||||
],
|
],
|
||||||
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
|
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
|
||||||
|
|||||||
@ -2,24 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Finance;
|
namespace App\Http\Requests\Admin\Finance;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Override;
|
use Override;
|
||||||
|
|
||||||
class CashTransactionRequest extends FormRequest
|
class CashTransactionRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Override]
|
#[Override]
|
||||||
public function prepareForValidation()
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
if ($this->has('amount')) {
|
$this->merge($this->stripCurrencyDot($this->all(), 'amount'));
|
||||||
$this->merge([
|
|
||||||
'amount' => str_replace('.', '', $this->amount),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,24 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Finance;
|
namespace App\Http\Requests\Admin\Finance;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Override;
|
use Override;
|
||||||
|
|
||||||
class EmployeeAdvanceRequest extends FormRequest
|
class EmployeeAdvanceRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Override]
|
#[Override]
|
||||||
public function prepareForValidation()
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
if ($this->has('amount')) {
|
$this->merge($this->stripCurrencyDot($this->all(), 'amount'));
|
||||||
$this->merge([
|
|
||||||
'amount' => str_replace('.', '', $this->amount),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,24 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Finance;
|
namespace App\Http\Requests\Admin\Finance;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Override;
|
use Override;
|
||||||
|
|
||||||
class ExpenseRequest extends FormRequest
|
class ExpenseRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Override]
|
#[Override]
|
||||||
public function prepareForValidation()
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
if ($this->has('amount')) {
|
$this->merge($this->stripCurrencyDot($this->all(), 'amount'));
|
||||||
$this->merge([
|
|
||||||
'amount' => str_replace('.', '', $this->amount),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Finance;
|
namespace App\Http\Requests\Admin\Finance;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use App\Enums\PayrollAdjustmentType;
|
use App\Enums\PayrollAdjustmentType;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
@ -9,19 +10,17 @@
|
|||||||
|
|
||||||
class PayrollAdjustmentRequest extends FormRequest
|
class PayrollAdjustmentRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Override]
|
#[Override]
|
||||||
public function prepareForValidation()
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
if ($this->has('amount')) {
|
$this->merge($this->stripCurrencyDot($this->all(), 'amount'));
|
||||||
$this->merge([
|
|
||||||
'amount' => str_replace('.', '', $this->amount),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -15,6 +15,7 @@ public function authorize(): bool
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
$userId = $this->route('user')?->id;
|
$userId = $this->route('user')?->id;
|
||||||
|
$isOwner = $this->input('role') === 'owner';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'email' => [
|
'email' => [
|
||||||
@ -30,15 +31,30 @@ public function rules(): array
|
|||||||
'alpha_dash',
|
'alpha_dash',
|
||||||
Rule::unique('users', 'username')->ignore($userId, 'id'),
|
Rule::unique('users', 'username')->ignore($userId, 'id'),
|
||||||
],
|
],
|
||||||
|
'role' => ['required', 'string', Rule::exists('roles', 'name')],
|
||||||
'full_name' => ['required', 'string', 'max:200'],
|
'full_name' => ['required', 'string', 'max:200'],
|
||||||
'phone_number' => ['nullable', 'string', 'max:20'],
|
'phone_number' => ['nullable', 'string', 'max:20'],
|
||||||
'gender' => ['nullable', 'in:male,female'],
|
'gender' => ['nullable', 'in:male,female'],
|
||||||
'birth_date' => ['nullable', 'date'],
|
'birth_date' => ['nullable', 'date'],
|
||||||
'address' => ['nullable', 'string'],
|
'address' => ['nullable', 'string'],
|
||||||
'join_date' => ['required', 'date'],
|
'join_date' => [
|
||||||
'resign_date' => ['nullable', 'date', 'after_or_equal:join_date'],
|
'date',
|
||||||
'employment_status' => ['required', Rule::in(['full_time', 'part_time', 'contract', 'internship', 'resigned'])],
|
Rule::requiredIf(! $isOwner),
|
||||||
'base_salary' => ['required', 'integer', 'min:0'],
|
],
|
||||||
|
'resign_date' => [
|
||||||
|
'nullable',
|
||||||
|
'date',
|
||||||
|
'after_or_equal:join_date',
|
||||||
|
],
|
||||||
|
'employment_status' => [
|
||||||
|
Rule::requiredIf(! $isOwner),
|
||||||
|
Rule::in(['full_time', 'part_time', 'contract', 'internship', 'resigned']),
|
||||||
|
],
|
||||||
|
'base_salary' => [
|
||||||
|
Rule::requiredIf(! $isOwner),
|
||||||
|
'integer',
|
||||||
|
'min:0',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +63,7 @@ public function attributes(): array
|
|||||||
return [
|
return [
|
||||||
'email' => 'Email',
|
'email' => 'Email',
|
||||||
'username' => 'Username',
|
'username' => 'Username',
|
||||||
|
'role' => 'Role',
|
||||||
'full_name' => 'Nama Lengkap',
|
'full_name' => 'Nama Lengkap',
|
||||||
'phone_number' => 'No. Telepon',
|
'phone_number' => 'No. Telepon',
|
||||||
'gender' => 'Jenis Kelamin',
|
'gender' => 'Jenis Kelamin',
|
||||||
|
|||||||
@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Manage;
|
namespace App\Http\Requests\Admin\Manage;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use App\Enums\RawMaterialUnit;
|
use App\Enums\RawMaterialUnit;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class PurchaseRequest extends FormRequest
|
class PurchaseRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -15,22 +18,7 @@ public function authorize(): bool
|
|||||||
|
|
||||||
public function prepareForValidation(): void
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
$variants = $this->variants;
|
$this->merge($this->stripCurrencyDot($this->all(), 'variants.*.price', 'discount', 'shipping_cost'));
|
||||||
if (is_array($variants)) {
|
|
||||||
foreach ($variants as $i => $variant) {
|
|
||||||
if (isset($variant['price']) && is_string($variant['price'])) {
|
|
||||||
$this->request->set("variants.$i.price", (int) str_replace('.', '', $variant['price']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($this->discount)) {
|
|
||||||
$this->request->set('discount', (int) str_replace('.', '', $this->discount));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($this->shipping_cost)) {
|
|
||||||
$this->request->set('shipping_cost', (int) str_replace('.', '', $this->shipping_cost));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Manage;
|
namespace App\Http\Requests\Admin\Manage;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use App\Enums\OrderChannel;
|
use App\Enums\OrderChannel;
|
||||||
use App\Enums\PaymentType;
|
use App\Enums\PaymentType;
|
||||||
use App\Enums\PriceType;
|
use App\Enums\PriceType;
|
||||||
@ -11,6 +12,8 @@
|
|||||||
|
|
||||||
class TransactionRequest extends FormRequest
|
class TransactionRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -18,17 +21,7 @@ public function authorize(): bool
|
|||||||
|
|
||||||
public function prepareForValidation(): void
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
if ($this->has('discount')) {
|
$this->merge($this->stripCurrencyDot($this->all(), 'discount', 'nego_price'));
|
||||||
$this->merge([
|
|
||||||
'discount' => str_replace('.', '', $this->discount),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->has('nego_price')) {
|
|
||||||
$this->merge([
|
|
||||||
'nego_price' => str_replace('.', '', $this->nego_price),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Master\Product;
|
namespace App\Http\Requests\Admin\Master\Product;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use App\Enums\PriceType;
|
use App\Enums\PriceType;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
@ -9,35 +10,17 @@
|
|||||||
|
|
||||||
class ProductRequest extends FormRequest
|
class ProductRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Override]
|
#[Override]
|
||||||
public function prepareForValidation()
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
$sharedPrices = $this->shared_prices;
|
$this->merge($this->stripCurrencyDot($this->all(), 'shared_prices.*.price', 'variants.*.prices.*.price'));
|
||||||
if (is_array($sharedPrices)) {
|
|
||||||
foreach ($sharedPrices as $i => $price) {
|
|
||||||
if (isset($price['price']) && is_string($price['price'])) {
|
|
||||||
$this->request->set("shared_prices.$i.price", (int) str_replace('.', '', $price['price']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$variants = $this->variants;
|
|
||||||
if (is_array($variants)) {
|
|
||||||
foreach ($variants as $i => $variant) {
|
|
||||||
if (isset($variant['prices']) && is_array($variant['prices'])) {
|
|
||||||
foreach ($variant['prices'] as $j => $price) {
|
|
||||||
if (isset($price['price']) && is_string($price['price'])) {
|
|
||||||
$this->request->set("variants.$i.prices.$j.price", (int) str_replace('.', '', $price['price']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Master\Product;
|
namespace App\Http\Requests\Admin\Master\Product;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use App\Enums\PriceType;
|
use App\Enums\PriceType;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class ProductVariantRequest extends FormRequest
|
class ProductVariantRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -15,14 +18,7 @@ public function authorize(): bool
|
|||||||
|
|
||||||
public function prepareForValidation(): void
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
$prices = $this->prices;
|
$this->merge($this->stripCurrencyDot($this->all(), 'prices.*.price'));
|
||||||
if (is_array($prices)) {
|
|
||||||
foreach ($prices as $i => $price) {
|
|
||||||
if (isset($price['price']) && is_string($price['price'])) {
|
|
||||||
$this->request->set("prices.$i.price", (int) str_replace('.', '', $price['price']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Master\RawMaterial;
|
namespace App\Http\Requests\Admin\Master\RawMaterial;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use App\Enums\RawMaterialUnit;
|
use App\Enums\RawMaterialUnit;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class RawMaterialRequest extends FormRequest
|
class RawMaterialRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -15,14 +18,7 @@ public function authorize(): bool
|
|||||||
|
|
||||||
public function prepareForValidation(): void
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
$variants = $this->variants;
|
$this->merge($this->stripCurrencyDot($this->all(), 'variants.*.price'));
|
||||||
if (is_array($variants)) {
|
|
||||||
foreach ($variants as $i => $variant) {
|
|
||||||
if (isset($variant['price']) && is_string($variant['price'])) {
|
|
||||||
$this->request->set("variants.$i.price", (int) str_replace('.', '', $variant['price']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Master\RawMaterial;
|
namespace App\Http\Requests\Admin\Master\RawMaterial;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class RawMaterialVariantRequest extends FormRequest
|
class RawMaterialVariantRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -13,10 +16,7 @@ public function authorize(): bool
|
|||||||
|
|
||||||
public function prepareForValidation(): void
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
$price = $this->price;
|
$this->merge($this->stripCurrencyDot($this->all(), 'price'));
|
||||||
if (is_string($price)) {
|
|
||||||
$this->request->set('price', (int) str_replace('.', '', $price));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -2,30 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Admin\Settings;
|
namespace App\Http\Requests\Admin\Settings;
|
||||||
|
|
||||||
|
use App\Concerns\CurrencyStripping;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Override;
|
use Override;
|
||||||
|
|
||||||
class UpdateHRRequest extends FormRequest
|
class UpdateHRRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
use CurrencyStripping;
|
||||||
|
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Override]
|
#[Override]
|
||||||
public function prepareForValidation()
|
public function prepareForValidation(): void
|
||||||
{
|
{
|
||||||
if ($this->has('late_penalty_amount')) {
|
$this->merge($this->stripCurrencyDot($this->all(), 'late_penalty_amount', 'absent_penalty_amount'));
|
||||||
$this->merge([
|
|
||||||
'late_penalty_amount' => str_replace('.', '', $this->late_penalty_amount),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->has('absent_penalty_amount')) {
|
|
||||||
$this->merge([
|
|
||||||
'absent_penalty_amount' => str_replace('.', '', $this->absent_penalty_amount),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
|
|||||||
@ -10,6 +10,11 @@ class PasswordUpdateRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
use PasswordValidationRules;
|
use PasswordValidationRules;
|
||||||
|
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -10,6 +10,11 @@ class ProfileDeleteRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
use PasswordValidationRules;
|
use PasswordValidationRules;
|
||||||
|
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -8,6 +8,11 @@
|
|||||||
|
|
||||||
class ProfileUpdateRequest extends FormRequest
|
class ProfileUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -10,6 +10,11 @@ class TwoFactorAuthenticationRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
use InteractsWithTwoFactorState;
|
use InteractsWithTwoFactorState;
|
||||||
|
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -29,6 +30,13 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function attendanceDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn ($value) => $value?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function employee(): BelongsTo
|
public function employee(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Employee::class);
|
return $this->belongsTo(Employee::class);
|
||||||
|
|||||||
@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_balance', 'formatted_name'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class CashAccount extends Model
|
class CashAccount extends Model
|
||||||
{
|
{
|
||||||
@ -21,6 +24,20 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedBalance(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->balance, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedName(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => ucfirst($this->name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function cashTransactions(): HasMany
|
public function cashTransactions(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(CashTransaction::class);
|
return $this->hasMany(CashTransaction::class);
|
||||||
|
|||||||
@ -3,9 +3,11 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\CashTransactionType;
|
use App\Enums\CashTransactionType;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -16,6 +18,7 @@
|
|||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
#[Appends(['formatted_amount', 'formatted_balance_after', 'formatted_created_at', 'type_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class CashTransaction extends Model implements HasMedia
|
class CashTransaction extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
@ -30,6 +33,34 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->amount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedBalanceAfter(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->balance_after, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedCreatedAt(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->created_at?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function typeLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->type->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function deposit(Builder $query): void
|
protected function deposit(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,19 +2,29 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Spatie\Sluggable\Attributes\Sluggable;
|
use Spatie\Sluggable\Attributes\Sluggable;
|
||||||
|
|
||||||
|
#[Appends(['formatted_name'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
#[Sluggable(from: 'name', to: 'slug')]
|
#[Sluggable(from: 'name', to: 'slug')]
|
||||||
class Category extends Model
|
class Category extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes;
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected function formattedName(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => ucfirst($this->name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function products(): BelongsToMany
|
public function products(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Product::class, 'product_categories')
|
return $this->belongsToMany(Product::class, 'product_categories')
|
||||||
|
|||||||
@ -2,17 +2,37 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_name', 'formatted_phone_number'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Customer extends Model
|
class Customer extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes;
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected function formattedName(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => ucfirst($this->name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedPhoneNumber(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->phone_number
|
||||||
|
? substr($this->phone_number, 0, 4) . ' ' . substr($this->phone_number, 4, 4) . ' ' . substr($this->phone_number, 8)
|
||||||
|
: null,
|
||||||
|
set: fn (?string $value) => $value ? preg_replace('/\s/', '', $value) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function orders(): HasMany
|
public function orders(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Order::class);
|
return $this->hasMany(Order::class);
|
||||||
|
|||||||
@ -3,9 +3,11 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\CuttingStatus;
|
use App\Enums\CuttingStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -14,6 +16,7 @@
|
|||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
#[Appends(['formatted_cost_per_unit', 'formatted_other_cost', 'formatted_sewing_cost', 'status_label', 'formatted_total_material_cost'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Cutting extends Model implements HasMedia
|
class Cutting extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
@ -30,6 +33,41 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedCostPerUnit(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->cost_per_unit, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedOtherCost(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->other_cost, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedSewingCost(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->sewing_cost, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedTotalMaterialCost(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->total_material_cost, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function cancelled(Builder $query): void
|
protected function cancelled(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,15 +3,18 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\EmploymentStatus;
|
use App\Enums\EmploymentStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_base_salary', 'employment_status_label', 'formatted_join_date', 'formatted_resign_date'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Employee extends Model
|
class Employee extends Model
|
||||||
{
|
{
|
||||||
@ -27,6 +30,34 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedBaseSalary(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->base_salary, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function employmentStatusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->employment_status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedJoinDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->join_date?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedResignDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->resign_date?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function contract(Builder $query): void
|
protected function contract(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,14 +3,17 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\EmployeeAdvanceStatus;
|
use App\Enums\EmployeeAdvanceStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_amount', 'formatted_created_at', 'formatted_due_date', 'formatted_paid_amount', 'status_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class EmployeeAdvance extends Model
|
class EmployeeAdvance extends Model
|
||||||
{
|
{
|
||||||
@ -28,6 +31,41 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->amount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedCreatedAt(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->created_at?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedDueDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->due_date?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedPaidAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->paid_amount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function approved(Builder $query): void
|
protected function approved(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -10,6 +12,7 @@
|
|||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
#[Appends(['formatted_amount', 'formatted_created_at', 'formatted_date'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Expense extends Model implements HasMedia
|
class Expense extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
@ -19,9 +22,31 @@ protected function casts(): array
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'amount' => 'integer',
|
'amount' => 'integer',
|
||||||
|
'date' => 'date:Y-m-d',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->amount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedCreatedAt(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->created_at?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->date?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function cashTransaction(): BelongsTo
|
public function cashTransaction(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(CashTransaction::class);
|
return $this->belongsTo(CashTransaction::class);
|
||||||
|
|||||||
@ -3,14 +3,17 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\LeaveRequestStatus;
|
use App\Enums\LeaveRequestStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_end_date', 'formatted_start_date', 'status_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class LeaveRequest extends Model
|
class LeaveRequest extends Model
|
||||||
{
|
{
|
||||||
@ -27,6 +30,27 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedEndDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->end_date?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedStartDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->start_date?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function approved(Builder $query): void
|
protected function approved(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,9 +6,11 @@
|
|||||||
use App\Enums\OrderStatus;
|
use App\Enums\OrderStatus;
|
||||||
use App\Enums\PaymentType;
|
use App\Enums\PaymentType;
|
||||||
use App\Enums\PriceType;
|
use App\Enums\PriceType;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -17,6 +19,7 @@
|
|||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
#[Appends(['channel_label', 'formatted_cogs', 'formatted_discount', 'formatted_nego_price', 'payment_type_label', 'status_label', 'formatted_subtotal', 'formatted_total_amount'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Order extends Model implements HasMedia
|
class Order extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
@ -39,6 +42,62 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function channelLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->channel->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedCogs(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->cogs, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedDiscount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->discount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedNegoPrice(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->nego_price, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function paymentTypeLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->payment_type->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedSubtotal(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->subtotal, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedTotalAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->total_amount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function cancelled(Builder $query): void
|
protected function cancelled(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,14 +3,17 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\ProductStockQuality;
|
use App\Enums\ProductStockQuality;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['stock_quality_label', 'formatted_subtotal', 'formatted_unit_price'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class OrderItem extends Model
|
class OrderItem extends Model
|
||||||
{
|
{
|
||||||
@ -26,6 +29,27 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function stockQualityLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->stock_quality->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedSubtotal(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->subtotal, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedUnitPrice(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->unit_price, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function good(Builder $query): void
|
protected function good(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\PayrollStatus;
|
use App\Enums\PayrollStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
@ -13,6 +14,7 @@
|
|||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_base_salary', 'formatted_bonus_amount', 'formatted_deduction_amount', 'status_label', 'formatted_total_amount'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Payroll extends Model
|
class Payroll extends Model
|
||||||
{
|
{
|
||||||
@ -30,10 +32,45 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedBaseSalary(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->base_salary, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedBonusAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->bonus_amount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedDeductionAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->deduction_amount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected function formattedAmount(): Attribute
|
protected function formattedAmount(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
get: fn () => 'Rp '.number_format($this->total_amount, 0, ',', '.'),
|
get: fn () => 'Rp ' . number_format($this->attributes['total_amount'] ?? 0, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedTotalAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->total_amount, 0, ',', '.'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,14 +3,17 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\PayrollAdjustmentType;
|
use App\Enums\PayrollAdjustmentType;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_amount', 'type_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class PayrollAdjustment extends Model
|
class PayrollAdjustment extends Model
|
||||||
{
|
{
|
||||||
@ -24,6 +27,20 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->amount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function typeLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->type->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function bonus(Builder $query): void
|
protected function bonus(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,15 +3,18 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\PayrollPeriodStatus;
|
use App\Enums\PayrollPeriodStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['status_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class PayrollPeriod extends Model
|
class PayrollPeriod extends Model
|
||||||
{
|
{
|
||||||
@ -27,6 +30,13 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function statusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function closed(Builder $query): void
|
protected function closed(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,9 +3,11 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\ProductStatus;
|
use App\Enums\ProductStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
@ -13,6 +15,7 @@
|
|||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Spatie\Sluggable\Attributes\Sluggable;
|
use Spatie\Sluggable\Attributes\Sluggable;
|
||||||
|
|
||||||
|
#[Appends(['formatted_name', 'status_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
#[Sluggable(from: 'name', to: 'slug')]
|
#[Sluggable(from: 'name', to: 'slug')]
|
||||||
class Product extends Model
|
class Product extends Model
|
||||||
@ -26,6 +29,20 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedName(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => ucfirst($this->name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function active(Builder $query): void
|
protected function active(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
#[Appends(['formatted_price', 'type_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
#[Appends(['type_label'])]
|
|
||||||
class ProductPrice extends Model
|
class ProductPrice extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
@ -26,6 +26,13 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedPrice(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->price, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function retail(Builder $query): void
|
protected function retail(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -11,6 +13,7 @@
|
|||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
#[Appends(['formatted_name'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class ProductVariant extends Model implements HasMedia
|
class ProductVariant extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
@ -25,6 +28,13 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedName(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => ucfirst($this->name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function orderItems(): HasMany
|
public function orderItems(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(OrderItem::class);
|
return $this->hasMany(OrderItem::class);
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -11,6 +13,7 @@
|
|||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
#[Appends(['formatted_discount', 'formatted_shipping_cost', 'formatted_subtotal', 'formatted_total'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Purchase extends Model implements HasMedia
|
class Purchase extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
@ -26,6 +29,34 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedDiscount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->discount, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedShippingCost(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->shipping_cost, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedSubtotal(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->subtotal, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedTotal(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->total, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function createdBy(): BelongsTo
|
public function createdBy(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(User::class, 'created_by_id');
|
return $this->belongsTo(User::class, 'created_by_id');
|
||||||
|
|||||||
@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_subtotal', 'formatted_unit_price'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class PurchaseItem extends Model
|
class PurchaseItem extends Model
|
||||||
{
|
{
|
||||||
@ -22,6 +25,20 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedSubtotal(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->subtotal, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedUnitPrice(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->unit_price, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function purchase(): BelongsTo
|
public function purchase(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Purchase::class);
|
return $this->belongsTo(Purchase::class);
|
||||||
|
|||||||
@ -3,14 +3,17 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\RawMaterialUnit;
|
use App\Enums\RawMaterialUnit;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_name', 'unit_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class RawMaterial extends Model
|
class RawMaterial extends Model
|
||||||
{
|
{
|
||||||
@ -24,6 +27,20 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedName(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => ucfirst($this->name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function unitLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->unit->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function kg(Builder $query): void
|
protected function kg(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,7 +3,9 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -12,6 +14,7 @@
|
|||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
#[Appends(['formatted_price'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class RawMaterialPrice extends Model implements HasMedia
|
class RawMaterialPrice extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
@ -25,6 +28,13 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedPrice(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->price, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function cuttingMaterials(): HasMany
|
public function cuttingMaterials(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(CuttingMaterial::class);
|
return $this->hasMany(CuttingMaterial::class);
|
||||||
|
|||||||
@ -3,9 +3,11 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\ProductStockQuality;
|
use App\Enums\ProductStockQuality;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@ -14,6 +16,7 @@
|
|||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
|
#[Appends(['stock_type_label', 'formatted_subtotal', 'formatted_total'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Restock extends Model implements HasMedia
|
class Restock extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
@ -28,6 +31,27 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function stockTypeLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->stock_type->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedSubtotal(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->subtotal, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedTotal(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->total, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function good(Builder $query): void
|
protected function good(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_subtotal', 'formatted_unit_price'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class RestockItem extends Model
|
class RestockItem extends Model
|
||||||
{
|
{
|
||||||
@ -22,6 +25,20 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedSubtotal(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->subtotal, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedUnitPrice(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => 'Rp ' . number_format($this->unit_price, 0, ',', '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function productVariant(): BelongsTo
|
public function productVariant(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(ProductVariant::class);
|
return $this->belongsTo(ProductVariant::class);
|
||||||
|
|||||||
@ -3,15 +3,18 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\StokOpnameStatus;
|
use App\Enums\StokOpnameStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_opname_date', 'status_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class StokOpname extends Model
|
class StokOpname extends Model
|
||||||
{
|
{
|
||||||
@ -25,6 +28,20 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedOpnameDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->opname_date?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->status->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function cancelled(Builder $query): void
|
protected function cancelled(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,13 +3,16 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\ProductStockQuality;
|
use App\Enums\ProductStockQuality;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
#[Appends(['stock_quality_label'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class StokOpnameItem extends Model
|
class StokOpnameItem extends Model
|
||||||
{
|
{
|
||||||
@ -25,6 +28,13 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function stockQualityLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->stock_quality->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function good(Builder $query): void
|
protected function good(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,17 +2,37 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_name', 'formatted_phone_number'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class Supplier extends Model
|
class Supplier extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes;
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected function formattedName(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => ucfirst($this->name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedPhoneNumber(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->phone_number
|
||||||
|
? substr($this->phone_number, 0, 4) . ' ' . substr($this->phone_number, 4, 4) . ' ' . substr($this->phone_number, 8)
|
||||||
|
: null,
|
||||||
|
set: fn (?string $value) => $value ? preg_replace('/\s/', '', $value) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function purchases(): HasMany
|
public function purchases(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Purchase::class);
|
return $this->hasMany(Purchase::class);
|
||||||
|
|||||||
@ -17,8 +17,8 @@
|
|||||||
use NotificationChannels\WebPush\HasPushSubscriptions;
|
use NotificationChannels\WebPush\HasPushSubscriptions;
|
||||||
use Spatie\Permission\Traits\HasRoles;
|
use Spatie\Permission\Traits\HasRoles;
|
||||||
|
|
||||||
|
#[Appends(['full_name', 'name'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
#[Appends(['full_name'])]
|
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable
|
||||||
{
|
{
|
||||||
use HasFactory, HasPushSubscriptions, HasRoles, Notifiable, SoftDeletes, TwoFactorAuthenticatable;
|
use HasFactory, HasPushSubscriptions, HasRoles, Notifiable, SoftDeletes, TwoFactorAuthenticatable;
|
||||||
@ -34,10 +34,11 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Scope]
|
protected function email(): Attribute
|
||||||
protected function active(Builder $query): void
|
|
||||||
{
|
{
|
||||||
$query->where('is_active', true);
|
return Attribute::make(
|
||||||
|
set: fn (string $value) => strtolower($value),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function name(): Attribute
|
protected function name(): Attribute
|
||||||
@ -54,6 +55,12 @@ protected function fullName(): Attribute
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Scope]
|
||||||
|
protected function active(Builder $query): void
|
||||||
|
{
|
||||||
|
$query->where('is_active', true);
|
||||||
|
}
|
||||||
|
|
||||||
public function attendances(): HasMany
|
public function attendances(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Attendance::class);
|
return $this->hasMany(Attendance::class);
|
||||||
|
|||||||
@ -3,14 +3,17 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\Gender;
|
use App\Enums\Gender;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
#[Appends(['formatted_birth_date', 'gender_label', 'formatted_phone_number'])]
|
||||||
#[Guarded(['id'])]
|
#[Guarded(['id'])]
|
||||||
class UserProfile extends Model
|
class UserProfile extends Model
|
||||||
{
|
{
|
||||||
@ -24,6 +27,30 @@ protected function casts(): array
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formattedBirthDate(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->birth_date?->translatedFormat('l, d F Y'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function genderLabel(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->gender?->label(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formattedPhoneNumber(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->phone_number
|
||||||
|
? substr($this->phone_number, 0, 4) . ' ' . substr($this->phone_number, 4, 4) . ' ' . substr($this->phone_number, 8)
|
||||||
|
: null,
|
||||||
|
set: fn (?string $value) => $value ? preg_replace('/\s/', '', $value) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[Scope]
|
#[Scope]
|
||||||
protected function female(Builder $query): void
|
protected function female(Builder $query): void
|
||||||
{
|
{
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
class AdminSettingsService
|
class AdminSettingsService
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service = new S3PresignedService,
|
private readonly S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function getSystemData(): array
|
public function getSystemData(): array
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
use App\Enums\CashTransactionType;
|
use App\Enums\CashTransactionType;
|
||||||
use App\Models\CashAccount;
|
use App\Models\CashAccount;
|
||||||
use App\Models\CashTransaction;
|
use App\Models\CashTransaction;
|
||||||
|
use App\Services\Concerns\HandlesCashTransactions;
|
||||||
use App\Services\Concerns\RegistersMedia;
|
use App\Services\Concerns\RegistersMedia;
|
||||||
use App\Services\NotificationService;
|
use App\Services\NotificationService;
|
||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
@ -16,10 +17,10 @@
|
|||||||
|
|
||||||
class CashAccountService
|
class CashAccountService
|
||||||
{
|
{
|
||||||
use RegistersMedia;
|
use HandlesCashTransactions, RegistersMedia;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service = new S3PresignedService,
|
private readonly S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function get(): ?CashAccount
|
public function get(): ?CashAccount
|
||||||
@ -94,27 +95,14 @@ private function formatTransaction(CashTransaction $transaction): array
|
|||||||
|
|
||||||
public function deposit(array $data): CashTransaction
|
public function deposit(array $data): CashTransaction
|
||||||
{
|
{
|
||||||
$transaction = DB::transaction(function () use ($data) {
|
$transaction = DB::transaction(fn () => $this->creditCash(
|
||||||
$cashAccount = CashAccount::firstOrFail();
|
amount: $data['amount'],
|
||||||
$newBalance = $cashAccount->balance + $data['amount'];
|
description: $data['description'],
|
||||||
|
));
|
||||||
|
|
||||||
$cashAccount->update(['balance' => $newBalance]);
|
if (! empty($data['receipt_key'])) {
|
||||||
|
$this->registerMedia($transaction, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||||
$transaction = CashTransaction::create([
|
}
|
||||||
'cash_account_id' => $cashAccount->id,
|
|
||||||
'created_by_id' => auth()->id(),
|
|
||||||
'amount' => $data['amount'],
|
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'type' => CashTransactionType::DEPOSIT,
|
|
||||||
'description' => $data['description'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (! empty($data['receipt_key'])) {
|
|
||||||
$this->registerMedia($transaction, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transaction;
|
|
||||||
});
|
|
||||||
|
|
||||||
NotificationService::notify(
|
NotificationService::notify(
|
||||||
roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
|
roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
|
||||||
@ -128,33 +116,15 @@ public function deposit(array $data): CashTransaction
|
|||||||
|
|
||||||
public function withdrawal(array $data): CashTransaction
|
public function withdrawal(array $data): CashTransaction
|
||||||
{
|
{
|
||||||
$transaction = DB::transaction(function () use ($data) {
|
$transaction = DB::transaction(fn () => $this->debitCash(
|
||||||
$cashAccount = CashAccount::firstOrFail();
|
amount: $data['amount'],
|
||||||
|
description: $data['description'],
|
||||||
|
type: CashTransactionType::WITHDRAWAL,
|
||||||
|
));
|
||||||
|
|
||||||
if ($cashAccount->balance < $data['amount']) {
|
if (! empty($data['receipt_key'])) {
|
||||||
throw ValidationException::withMessages([
|
$this->registerMedia($transaction, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
||||||
'amount' => 'Saldo tidak mencukupi.',
|
}
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$newBalance = $cashAccount->balance - $data['amount'];
|
|
||||||
$cashAccount->update(['balance' => $newBalance]);
|
|
||||||
|
|
||||||
$transaction = CashTransaction::create([
|
|
||||||
'cash_account_id' => $cashAccount->id,
|
|
||||||
'created_by_id' => auth()->id(),
|
|
||||||
'amount' => $data['amount'],
|
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'type' => CashTransactionType::WITHDRAWAL,
|
|
||||||
'description' => $data['description'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (! empty($data['receipt_key'])) {
|
|
||||||
$this->registerMedia($transaction, $data['receipt_key'], 'receipts', ['thumb' => true], $data['file_size'] ?? null, $data['file_mime_type'] ?? null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transaction;
|
|
||||||
});
|
|
||||||
|
|
||||||
NotificationService::notify(
|
NotificationService::notify(
|
||||||
roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
|
roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
use App\Models\CashAccount;
|
use App\Models\CashAccount;
|
||||||
use App\Models\CashTransaction;
|
use App\Models\CashTransaction;
|
||||||
use App\Models\EmployeeAdvance;
|
use App\Models\EmployeeAdvance;
|
||||||
|
use App\Services\Concerns\HandlesCashTransactions;
|
||||||
use App\Services\NotificationService;
|
use App\Services\NotificationService;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@ -15,7 +16,8 @@
|
|||||||
|
|
||||||
class EmployeeAdvanceService
|
class EmployeeAdvanceService
|
||||||
{
|
{
|
||||||
public function getAll(): Collection
|
use HandlesCashTransactions;
|
||||||
|
public function getAll(array $filters = []): Collection
|
||||||
{
|
{
|
||||||
return EmployeeAdvance::select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at')
|
return EmployeeAdvance::select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at')
|
||||||
->with(['employee.user.userProfile'])
|
->with(['employee.user.userProfile'])
|
||||||
@ -23,7 +25,7 @@ public function getAll(): Collection
|
|||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
return EmployeeAdvance::query()
|
return EmployeeAdvance::query()
|
||||||
->select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at')
|
->select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at')
|
||||||
@ -36,30 +38,16 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
public function create(array $data): EmployeeAdvance
|
public function create(array $data): EmployeeAdvance
|
||||||
{
|
{
|
||||||
$employeeAdvance = DB::transaction(function () use ($data) {
|
$employeeAdvance = DB::transaction(function () use ($data) {
|
||||||
$cashAccount = CashAccount::firstOrFail();
|
|
||||||
$employee = auth()->user()->employee;
|
$employee = auth()->user()->employee;
|
||||||
|
|
||||||
if (! $employee) {
|
if (! $employee) {
|
||||||
throw new \Exception('Anda tidak terdaftar sebagai karyawan.');
|
throw new \Exception('Anda tidak terdaftar sebagai karyawan.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cashAccount->balance < $data['amount']) {
|
$cashTransaction = $this->debitCash(
|
||||||
throw ValidationException::withMessages([
|
amount: $data['amount'],
|
||||||
'amount' => 'Saldo tidak mencukupi.',
|
description: 'Kasbon: '.$data['description'],
|
||||||
]);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
$newBalance = $cashAccount->balance - $data['amount'];
|
|
||||||
$cashAccount->update(['balance' => $newBalance]);
|
|
||||||
|
|
||||||
$cashTransaction = CashTransaction::create([
|
|
||||||
'cash_account_id' => $cashAccount->id,
|
|
||||||
'created_by_id' => auth()->id(),
|
|
||||||
'amount' => $data['amount'],
|
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'type' => CashTransactionType::EXPENSE,
|
|
||||||
'description' => 'Kasbon: '.$data['description'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
return EmployeeAdvance::create([
|
return EmployeeAdvance::create([
|
||||||
'cash_transaction_id' => $cashTransaction->id,
|
'cash_transaction_id' => $cashTransaction->id,
|
||||||
@ -155,19 +143,10 @@ public function approve(EmployeeAdvance $employeeAdvance): EmployeeAdvance
|
|||||||
public function pay(EmployeeAdvance $employeeAdvance): EmployeeAdvance
|
public function pay(EmployeeAdvance $employeeAdvance): EmployeeAdvance
|
||||||
{
|
{
|
||||||
$employeeAdvance = DB::transaction(function () use ($employeeAdvance) {
|
$employeeAdvance = DB::transaction(function () use ($employeeAdvance) {
|
||||||
$cashAccount = CashAccount::firstOrFail();
|
$cashTransaction = $this->creditCash(
|
||||||
|
amount: $employeeAdvance->amount,
|
||||||
$newBalance = $cashAccount->balance + $employeeAdvance->amount;
|
description: 'Pembayaran kasbon: '.$employeeAdvance->description,
|
||||||
$cashAccount->update(['balance' => $newBalance]);
|
);
|
||||||
|
|
||||||
$cashTransaction = CashTransaction::create([
|
|
||||||
'cash_account_id' => $cashAccount->id,
|
|
||||||
'created_by_id' => auth()->id(),
|
|
||||||
'amount' => $employeeAdvance->amount,
|
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'type' => CashTransactionType::DEPOSIT,
|
|
||||||
'description' => 'Pembayaran kasbon: '.$employeeAdvance->description,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$employeeAdvance->update([
|
$employeeAdvance->update([
|
||||||
'status' => EmployeeAdvanceStatus::PAID,
|
'status' => EmployeeAdvanceStatus::PAID,
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
use App\Models\CashAccount;
|
use App\Models\CashAccount;
|
||||||
use App\Models\CashTransaction;
|
use App\Models\CashTransaction;
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
|
use App\Services\Concerns\HandlesCashTransactions;
|
||||||
use App\Services\Concerns\RegistersMedia;
|
use App\Services\Concerns\RegistersMedia;
|
||||||
use App\Services\NotificationService;
|
use App\Services\NotificationService;
|
||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
@ -17,13 +18,13 @@
|
|||||||
|
|
||||||
class ExpenseService
|
class ExpenseService
|
||||||
{
|
{
|
||||||
use RegistersMedia;
|
use HandlesCashTransactions, RegistersMedia;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service = new S3PresignedService,
|
private readonly S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function getAll(): Collection
|
public function getAll(array $filters = []): Collection
|
||||||
{
|
{
|
||||||
return Expense::select('id', 'created_by_id', 'amount', 'description', 'created_at')
|
return Expense::select('id', 'created_by_id', 'amount', 'description', 'created_at')
|
||||||
->with('createdBy.userProfile', 'media')
|
->with('createdBy.userProfile', 'media')
|
||||||
@ -32,7 +33,7 @@ public function getAll(): Collection
|
|||||||
->map(fn (Expense $expense) => $this->formatExpense($expense));
|
->map(fn (Expense $expense) => $this->formatExpense($expense));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
$paginator = Expense::query()
|
$paginator = Expense::query()
|
||||||
->select('id', 'created_by_id', 'amount', 'description', 'created_at')
|
->select('id', 'created_by_id', 'amount', 'description', 'created_at')
|
||||||
@ -78,25 +79,10 @@ private function formatExpense(Expense $expense): array
|
|||||||
public function create(array $data): Expense
|
public function create(array $data): Expense
|
||||||
{
|
{
|
||||||
$expense = DB::transaction(function () use ($data) {
|
$expense = DB::transaction(function () use ($data) {
|
||||||
$cashAccount = CashAccount::firstOrFail();
|
$cashTransaction = $this->debitCash(
|
||||||
|
amount: $data['amount'],
|
||||||
if ($cashAccount->balance < $data['amount']) {
|
description: $data['description'],
|
||||||
throw ValidationException::withMessages([
|
);
|
||||||
'amount' => 'Saldo tidak mencukupi.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$newBalance = $cashAccount->balance - $data['amount'];
|
|
||||||
$cashAccount->update(['balance' => $newBalance]);
|
|
||||||
|
|
||||||
$cashTransaction = CashTransaction::create([
|
|
||||||
'cash_account_id' => $cashAccount->id,
|
|
||||||
'created_by_id' => auth()->id(),
|
|
||||||
'amount' => $data['amount'],
|
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'type' => CashTransactionType::EXPENSE,
|
|
||||||
'description' => $data['description'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$expense = Expense::create([
|
$expense = Expense::create([
|
||||||
'cash_transaction_id' => $cashTransaction->id,
|
'cash_transaction_id' => $cashTransaction->id,
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
use App\Models\CashTransaction;
|
use App\Models\CashTransaction;
|
||||||
use App\Models\Payroll;
|
use App\Models\Payroll;
|
||||||
use App\Models\PayrollPeriod;
|
use App\Models\PayrollPeriod;
|
||||||
|
use App\Services\Concerns\HandlesCashTransactions;
|
||||||
use App\Services\NotificationService;
|
use App\Services\NotificationService;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@ -17,7 +18,8 @@
|
|||||||
|
|
||||||
class PayrollPeriodService
|
class PayrollPeriodService
|
||||||
{
|
{
|
||||||
public function getAll(): Collection
|
use HandlesCashTransactions;
|
||||||
|
public function getAll(array $filters = []): Collection
|
||||||
{
|
{
|
||||||
return PayrollPeriod::select('id', 'year', 'month', 'status', 'closed_at', 'created_at')
|
return PayrollPeriod::select('id', 'year', 'month', 'status', 'closed_at', 'created_at')
|
||||||
->withCount('payrolls')
|
->withCount('payrolls')
|
||||||
@ -35,7 +37,7 @@ public function getAll(): Collection
|
|||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
return PayrollPeriod::query()
|
return PayrollPeriod::query()
|
||||||
->select('id', 'year', 'month', 'status', 'closed_at', 'created_at')
|
->select('id', 'year', 'month', 'status', 'closed_at', 'created_at')
|
||||||
@ -123,19 +125,10 @@ public function pay(Payroll $payroll): Payroll
|
|||||||
}
|
}
|
||||||
|
|
||||||
$payroll = DB::transaction(function () use ($payroll) {
|
$payroll = DB::transaction(function () use ($payroll) {
|
||||||
$cashAccount = CashAccount::firstOrFail();
|
$cashTransaction = $this->creditCash(
|
||||||
|
amount: $payroll->total_amount,
|
||||||
$newBalance = $cashAccount->balance + $payroll->total_amount;
|
description: 'Pembayaran gaji karyawan',
|
||||||
$cashAccount->update(['balance' => $newBalance]);
|
);
|
||||||
|
|
||||||
$cashTransaction = CashTransaction::create([
|
|
||||||
'cash_account_id' => $cashAccount->id,
|
|
||||||
'created_by_id' => auth()->id(),
|
|
||||||
'amount' => $payroll->total_amount,
|
|
||||||
'balance_after' => $newBalance,
|
|
||||||
'type' => CashTransactionType::DEPOSIT,
|
|
||||||
'description' => 'Pembayaran gaji karyawan',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$payroll->update([
|
$payroll->update([
|
||||||
'status' => PayrollStatus::PAID,
|
'status' => PayrollStatus::PAID,
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class AttendanceService
|
|||||||
use RegistersMedia;
|
use RegistersMedia;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service = new S3PresignedService,
|
private readonly S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function getAll(): Collection
|
public function getAll(): Collection
|
||||||
|
|||||||
@ -11,15 +11,16 @@ class EmployeeService
|
|||||||
{
|
{
|
||||||
public function getAll(array $filters = []): Collection
|
public function getAll(array $filters = []): Collection
|
||||||
{
|
{
|
||||||
return User::select('id', 'email', 'username', 'is_active')
|
return User::select(['id', 'email', 'username', 'is_active'])
|
||||||
->whereHas('employee')
|
->where(fn ($q) => $q->whereHas('employee')->orWhereHas('roles', fn ($rq) => $rq->where('name', 'Owner')))
|
||||||
->with([
|
->with([
|
||||||
'userProfile' => fn ($q) => $q->select('id', 'user_id', 'full_name', 'phone_number', 'gender'),
|
'userProfile' => fn($q) => $q->select('id', 'user_id', 'full_name', 'phone_number', 'gender'),
|
||||||
'employee' => fn ($q) => $q->select('id', 'user_id', 'join_date', 'employment_status', 'base_salary'),
|
'employee' => fn($q) => $q->select('id', 'user_id', 'join_date', 'employment_status', 'base_salary'),
|
||||||
|
'roles' => fn($q) => $q->select('id', 'name'),
|
||||||
])
|
])
|
||||||
->when($filters['employment_status'] ?? null, fn ($q, $status) => $q->whereHas('employee', fn ($eq) => $eq->where('employment_status', $status)))
|
->when($filters['employment_status'] ?? null, fn($q, $status) => $q->whereHas('employee', fn($eq) => $eq->where('employment_status', $status)))
|
||||||
->when(isset($filters['is_active']) && $filters['is_active'] !== '', fn ($q) => $q->where('is_active', filter_var($filters['is_active'], FILTER_VALIDATE_BOOLEAN)))
|
->when(isset($filters['is_active']) && $filters['is_active'] !== '', fn($q) => $q->where('is_active', filter_var($filters['is_active'], FILTER_VALIDATE_BOOLEAN)))
|
||||||
->when($filters['gender'] ?? null, fn ($q, $gender) => $q->whereHas('userProfile', fn ($uq) => $uq->where('gender', $gender)))
|
->when($filters['gender'] ?? null, fn($q, $gender) => $q->whereHas('userProfile', fn($uq) => $uq->where('gender', $gender)))
|
||||||
->latest()
|
->latest()
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
@ -27,25 +28,21 @@ public function getAll(array $filters = []): Collection
|
|||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
return User::query()
|
return User::query()
|
||||||
->select('id', 'email', 'username', 'is_active')
|
->select(['id', 'email', 'username', 'is_active'])
|
||||||
->whereHas('employee')
|
->where(fn ($q) => $q->whereHas('employee')->orWhereHas('roles', fn ($rq) => $rq->where('name', 'Owner')))
|
||||||
->with([
|
->with([
|
||||||
'userProfile' => fn ($q) => $q->select('id', 'user_id', 'full_name', 'phone_number', 'gender'),
|
'userProfile' => fn($q) => $q->select('id', 'user_id', 'full_name', 'phone_number', 'gender'),
|
||||||
'employee' => fn ($q) => $q->select('id', 'user_id', 'join_date', 'employment_status', 'base_salary'),
|
'employee' => fn($q) => $q->select('id', 'user_id', 'join_date', 'employment_status', 'base_salary'),
|
||||||
|
'roles' => fn($q) => $q->select('id', 'name'),
|
||||||
])
|
])
|
||||||
->when($search, fn ($q) => $q->whereHas('userProfile', fn ($uq) => $uq->where('full_name', 'like', "%{$search}%")))
|
->when($search, fn($q) => $q->whereHas('userProfile', fn($uq) => $uq->where('full_name', 'like', "%{$search}%")))
|
||||||
->when($filters['employment_status'] ?? null, fn ($q, $status) => $q->whereHas('employee', fn ($eq) => $eq->where('employment_status', $status)))
|
->when($filters['employment_status'] ?? null, fn($q, $status) => $q->whereHas('employee', fn($eq) => $eq->where('employment_status', $status)))
|
||||||
->when(isset($filters['is_active']) && $filters['is_active'] !== '', fn ($q) => $q->where('is_active', filter_var($filters['is_active'], FILTER_VALIDATE_BOOLEAN)))
|
->when(isset($filters['is_active']) && $filters['is_active'] !== '', fn($q) => $q->where('is_active', filter_var($filters['is_active'], FILTER_VALIDATE_BOOLEAN)))
|
||||||
->when($filters['gender'] ?? null, fn ($q, $gender) => $q->whereHas('userProfile', fn ($uq) => $uq->where('gender', $gender)))
|
->when($filters['gender'] ?? null, fn($q, $gender) => $q->whereHas('userProfile', fn($uq) => $uq->where('gender', $gender)))
|
||||||
->orderBy($sort, $direction)
|
->orderBy($sort, $direction)
|
||||||
->paginate($perPage);
|
->paginate($perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getById(int $id): User
|
|
||||||
{
|
|
||||||
return User::with(['userProfile', 'employee'])->findOrFail($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create(array $data): User
|
public function create(array $data): User
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($data) {
|
return DB::transaction(function () use ($data) {
|
||||||
@ -56,6 +53,8 @@ public function create(array $data): User
|
|||||||
'is_active' => true,
|
'is_active' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$user->assignRole($data['role']);
|
||||||
|
|
||||||
$user->userProfile()->create([
|
$user->userProfile()->create([
|
||||||
'full_name' => $data['full_name'],
|
'full_name' => $data['full_name'],
|
||||||
'phone_number' => $data['phone_number'] ?? null,
|
'phone_number' => $data['phone_number'] ?? null,
|
||||||
@ -64,12 +63,14 @@ public function create(array $data): User
|
|||||||
'address' => $data['address'] ?? null,
|
'address' => $data['address'] ?? null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user->employee()->create([
|
if ($data['role'] !== 'owner') {
|
||||||
'join_date' => $data['join_date'],
|
$user->employee()->create([
|
||||||
'resign_date' => $data['resign_date'] ?? null,
|
'join_date' => $data['join_date'],
|
||||||
'employment_status' => $data['employment_status'],
|
'resign_date' => $data['resign_date'] ?? null,
|
||||||
'base_salary' => $data['base_salary'],
|
'employment_status' => $data['employment_status'],
|
||||||
]);
|
'base_salary' => $data['base_salary'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
});
|
});
|
||||||
@ -83,6 +84,8 @@ public function update(User $user, array $data): User
|
|||||||
'username' => $data['username'],
|
'username' => $data['username'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$user->syncRoles($data['role']);
|
||||||
|
|
||||||
$user->userProfile()->updateOrCreate([], [
|
$user->userProfile()->updateOrCreate([], [
|
||||||
'full_name' => $data['full_name'],
|
'full_name' => $data['full_name'],
|
||||||
'phone_number' => $data['phone_number'] ?? null,
|
'phone_number' => $data['phone_number'] ?? null,
|
||||||
@ -91,12 +94,16 @@ public function update(User $user, array $data): User
|
|||||||
'address' => $data['address'] ?? null,
|
'address' => $data['address'] ?? null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user->employee()->updateOrCreate([], [
|
if ($data['role'] !== 'owner') {
|
||||||
'join_date' => $data['join_date'],
|
$user->employee()->updateOrCreate([], [
|
||||||
'resign_date' => $data['resign_date'] ?? null,
|
'join_date' => $data['join_date'],
|
||||||
'employment_status' => $data['employment_status'],
|
'resign_date' => $data['resign_date'] ?? null,
|
||||||
'base_salary' => $data['base_salary'],
|
'employment_status' => $data['employment_status'],
|
||||||
]);
|
'base_salary' => $data['base_salary'],
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$user->employee()->delete();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return $user->fresh(['userProfile', 'employee']);
|
return $user->fresh(['userProfile', 'employee']);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class CuttingService
|
|||||||
use RegistersMedia;
|
use RegistersMedia;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service = new S3PresignedService,
|
private readonly S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
||||||
@ -342,36 +342,12 @@ public function update(Cutting $cutting, array $data): Cutting
|
|||||||
'updated_at' => $now,
|
'updated_at' => $now,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->syncCuttingPhoto($cutting, $data);
|
$this->syncPhoto($cutting, $data);
|
||||||
|
|
||||||
return $cutting;
|
return $cutting;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncCuttingPhoto(Cutting $cutting, array $data): void
|
|
||||||
{
|
|
||||||
if (! array_key_exists('photo_key', $data)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentKey = $cutting->getFirstMedia('photos')?->file_name;
|
|
||||||
|
|
||||||
if ($data['photo_key'] === $currentKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cutting->clearMediaCollection('photos');
|
|
||||||
|
|
||||||
if (! empty($data['photo_key'])) {
|
|
||||||
$this->registerMedia(
|
|
||||||
model: $cutting,
|
|
||||||
s3Key: $data['photo_key'],
|
|
||||||
collectionName: 'photos',
|
|
||||||
orderColumn: 1,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(Cutting $cutting): bool
|
public function delete(Cutting $cutting): bool
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($cutting) {
|
return DB::transaction(function () use ($cutting) {
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class PurchaseService
|
|||||||
use RegistersMedia;
|
use RegistersMedia;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service = new S3PresignedService,
|
private readonly S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
||||||
@ -455,36 +455,12 @@ public function update(Purchase $purchase, array $data): Purchase
|
|||||||
}
|
}
|
||||||
DB::table('purchase_items')->insert($itemRows);
|
DB::table('purchase_items')->insert($itemRows);
|
||||||
|
|
||||||
$this->syncPurchasePhoto($purchase, $data);
|
$this->syncPhoto($purchase, $data);
|
||||||
|
|
||||||
return $purchase;
|
return $purchase;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function syncPurchasePhoto(Purchase $purchase, array $data): void
|
|
||||||
{
|
|
||||||
if (! array_key_exists('photo_key', $data)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentKey = $purchase->getFirstMedia('photos')?->file_name;
|
|
||||||
|
|
||||||
if ($data['photo_key'] === $currentKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$purchase->clearMediaCollection('photos');
|
|
||||||
|
|
||||||
if (! empty($data['photo_key'])) {
|
|
||||||
$this->registerMedia(
|
|
||||||
model: $purchase,
|
|
||||||
s3Key: $data['photo_key'],
|
|
||||||
collectionName: 'photos',
|
|
||||||
orderColumn: 1,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(Purchase $purchase): bool
|
public function delete(Purchase $purchase): bool
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($purchase) {
|
return DB::transaction(function () use ($purchase) {
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
use App\Models\ProductVariant;
|
use App\Models\ProductVariant;
|
||||||
use App\Models\Restock;
|
use App\Models\Restock;
|
||||||
use App\Models\RestockItem;
|
use App\Models\RestockItem;
|
||||||
|
use App\Services\Concerns\HasStockAdjustment;
|
||||||
use App\Services\Concerns\RegistersMedia;
|
use App\Services\Concerns\RegistersMedia;
|
||||||
use App\Services\NotificationService;
|
use App\Services\NotificationService;
|
||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
@ -16,15 +17,10 @@
|
|||||||
|
|
||||||
class RestockService
|
class RestockService
|
||||||
{
|
{
|
||||||
use RegistersMedia;
|
use HasStockAdjustment, RegistersMedia;
|
||||||
|
|
||||||
private const QUALITY_STOCK_MAP = [
|
|
||||||
ProductStockQuality::GOOD->value => 'stock',
|
|
||||||
ProductStockQuality::REJECT->value => 'reject_stock',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service = new S3PresignedService,
|
private readonly S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
|
||||||
@ -240,45 +236,4 @@ private function buildItemRows(array $items, string $stockType, $now, int &$subt
|
|||||||
})->toArray();
|
})->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
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 adjustVariantStock(int $variantId, int $quantity, int $sign, string $stockType): void
|
|
||||||
{
|
|
||||||
$field = self::QUALITY_STOCK_MAP[$stockType] ?? 'stock';
|
|
||||||
|
|
||||||
if ($sign > 0) {
|
|
||||||
ProductVariant::whereKey($variantId)->increment($field, $quantity);
|
|
||||||
} else {
|
|
||||||
ProductVariant::whereKey($variantId)->decrement($field, $quantity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function syncPhoto(Restock $restock, array $data): void
|
|
||||||
{
|
|
||||||
if (! array_key_exists('photo_key', $data)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentKey = $restock->getFirstMedia('photos')?->file_name;
|
|
||||||
|
|
||||||
if ($data['photo_key'] === $currentKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$restock->clearMediaCollection('photos');
|
|
||||||
|
|
||||||
if (! empty($data['photo_key'])) {
|
|
||||||
$this->registerMedia(
|
|
||||||
model: $restock,
|
|
||||||
s3Key: $data['photo_key'],
|
|
||||||
collectionName: 'photos',
|
|
||||||
orderColumn: 1,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\ProductVariant;
|
use App\Models\ProductVariant;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Services\Concerns\HasStockAdjustment;
|
||||||
use App\Services\Concerns\RegistersMedia;
|
use App\Services\Concerns\RegistersMedia;
|
||||||
use App\Services\NotificationService;
|
use App\Services\NotificationService;
|
||||||
use App\Services\S3PresignedService;
|
use App\Services\S3PresignedService;
|
||||||
@ -21,12 +22,7 @@
|
|||||||
|
|
||||||
class TransactionService
|
class TransactionService
|
||||||
{
|
{
|
||||||
use RegistersMedia;
|
use HasStockAdjustment, RegistersMedia;
|
||||||
|
|
||||||
private const QUALITY_STOCK_MAP = [
|
|
||||||
ProductStockQuality::GOOD->value => 'stock',
|
|
||||||
ProductStockQuality::REJECT->value => 'reject_stock',
|
|
||||||
];
|
|
||||||
|
|
||||||
private const SELLING_PRICE_MAP = [
|
private const SELLING_PRICE_MAP = [
|
||||||
PriceType::DISTRIBUTOR->value => PriceType::DISTRIBUTOR,
|
PriceType::DISTRIBUTOR->value => PriceType::DISTRIBUTOR,
|
||||||
@ -39,7 +35,7 @@ class TransactionService
|
|||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private S3PresignedService $s3Service = new S3PresignedService,
|
private readonly S3PresignedService $s3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
|
||||||
@ -96,6 +92,9 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
|
|||||||
public function getFilterOptions(): array
|
public function getFilterOptions(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
'statusOptions' => OrderStatus::toSelect(),
|
||||||
|
'channelOptions' => OrderChannel::toSelect(),
|
||||||
|
'paymentTypeOptions' => PaymentType::toSelect(),
|
||||||
'customers' => Customer::query()
|
'customers' => Customer::query()
|
||||||
->select('id', 'name')
|
->select('id', 'name')
|
||||||
->orderBy('name')
|
->orderBy('name')
|
||||||
@ -149,9 +148,9 @@ public function getForCreate(): array
|
|||||||
->get()
|
->get()
|
||||||
->filter(fn (User $user) => $user->userProfile?->full_name)
|
->filter(fn (User $user) => $user->userProfile?->full_name)
|
||||||
->values(),
|
->values(),
|
||||||
'channelOptions' => collect(OrderChannel::cases())->map(fn ($c) => ['value' => $c->value, 'label' => $c->label()])->values(),
|
'channelOptions' => OrderChannel::toSelect(),
|
||||||
'paymentTypeOptions' => collect(PaymentType::cases())->map(fn ($p) => ['value' => $p->value, 'label' => $p->label()])->values(),
|
'paymentTypeOptions' => PaymentType::toSelect(),
|
||||||
'priceTypeOptions' => collect(PriceType::cases())->filter(fn ($p) => ! in_array($p, [PriceType::CAPITAL]))->map(fn ($p) => ['value' => $p->value, 'label' => $p->label()])->values(),
|
'priceTypeOptions' => PriceType::toSelect()->filter(fn ($p) => $p['value'] !== PriceType::CAPITAL->value)->values(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,48 +377,6 @@ private function buildItemRows(array $items, string $stockType, string $priceTyp
|
|||||||
})->toArray();
|
})->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
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 adjustVariantStock(int $variantId, int $quantity, int $sign, string $stockType): void
|
|
||||||
{
|
|
||||||
$field = self::QUALITY_STOCK_MAP[$stockType] ?? 'stock';
|
|
||||||
|
|
||||||
if ($sign > 0) {
|
|
||||||
ProductVariant::whereKey($variantId)->increment($field, $quantity);
|
|
||||||
} else {
|
|
||||||
ProductVariant::whereKey($variantId)->decrement($field, $quantity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function syncPhoto(Order $order, array $data): void
|
|
||||||
{
|
|
||||||
if (! array_key_exists('photo_key', $data)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentKey = $order->getFirstMedia('photos')?->file_name;
|
|
||||||
|
|
||||||
if ($data['photo_key'] === $currentKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$order->clearMediaCollection('photos');
|
|
||||||
|
|
||||||
if (! empty($data['photo_key'])) {
|
|
||||||
$this->registerMedia(
|
|
||||||
model: $order,
|
|
||||||
s3Key: $data['photo_key'],
|
|
||||||
collectionName: 'photos',
|
|
||||||
orderColumn: 1,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function generateOrderNumber(): string
|
private function generateOrderNumber(): string
|
||||||
{
|
{
|
||||||
$prefix = 'TRX';
|
$prefix = 'TRX';
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user