diff --git a/TODO.md b/TODO.md index 35f197e..a9a8967 100644 --- a/TODO.md +++ b/TODO.md @@ -15,7 +15,7 @@ - [x] Manual Approve Deposit - [x] List Customer Verification - [x] Manual Approve Verification -> mendapatkan limit hutang -- [ ] Setting Bonus Coin (memasukan amount bonus coin yang didapat dengan level dan harga voucher) - bonus coin +- [x] Setting Bonus Coin (memasukan amount bonus coin yang didapat dengan level dan harga voucher) - bonus coin - [ ] Voucher Sales (index: customer, total, jumlah voucher, detail: customer, list voucher, payment) - [ ] Dashboard (gafik hasil penjualan : disorting tanggal, lokasi dan customer) [total voucher] [total customer] [total customer verified] [total deposit] diff --git a/app/Http/Controllers/CoinRewardController.php b/app/Http/Controllers/CoinRewardController.php new file mode 100644 index 0000000..99aa06a --- /dev/null +++ b/app/Http/Controllers/CoinRewardController.php @@ -0,0 +1,62 @@ +orderBy('updated_at', 'desc'); + + return inertia('CoinReward/Index', [ + 'query' => $query->paginate(), + 'levels' => CustomerLevel::all() + ]); + } + + public function store(Request $request) + { + $request->validate([ + 'amount_buy' => 'required|numeric', + 'bonus_coin' => 'required|numeric', + 'customer_level_id' => 'required|exists:customer_levels,id', + ]); + + CoinReward::create([ + 'amount_buy' => $request->amount_buy, + 'bonus_coin' => $request->bonus_coin, + 'customer_level_id' => $request->customer_level_id, + ]); + + session()->flash('message', ['type' => 'success', 'message' => 'Item has beed saved']); + } + + public function update(Request $request, CoinReward $reward) + { + $request->validate([ + 'amount_buy' => 'required|numeric', + 'bonus_coin' => 'required|numeric', + 'customer_level_id' => 'required|exists:customer_levels,id', + ]); + + $reward->update([ + 'amount_buy' => $request->amount_buy, + 'bonus_coin' => $request->bonus_coin, + 'customer_level_id' => $request->customer_level_id, + ]); + + session()->flash('message', ['type' => 'success', 'message' => 'Item has beed updated']); + } + + public function destroy(CoinReward $reward) + { + $reward->delete(); + + session()->flash('message', ['type' => 'success', 'message' => 'Item has beed deleted']); + } +} diff --git a/app/Http/Controllers/Customer/CartController.php b/app/Http/Controllers/Customer/CartController.php index 6f2a9a8..f875d87 100644 --- a/app/Http/Controllers/Customer/CartController.php +++ b/app/Http/Controllers/Customer/CartController.php @@ -3,6 +3,8 @@ namespace App\Http\Controllers\Customer; use App\Http\Controllers\Controller; +use App\Models\CoinHistory; +use App\Models\CoinReward; use App\Models\Customer; use App\Models\DepositHistory; use App\Models\Sale; @@ -122,7 +124,6 @@ class CartController extends Controller $customer = Customer::find(auth()->id()); - // tolak payment jika limit dan deposit kurang dari total $paylater_limit = (int) $customer->paylater_limit; if (($paylater_limit + $customer->deposit_balance) < $total) { session()->remove('carts'); @@ -130,9 +131,9 @@ class CartController extends Controller ->with('message', ['type' => 'error', 'message' => 'transaksi gagal, pembayaran ditolak']); } - $payedWith = Sale::PAYED_WITH_DEPOSIT; //default deposit + $payedWith = Sale::PAYED_WITH_DEPOSIT; if ($total > $customer->deposit_balance && $customer->deposit_balance == 0) { - $payedWith = Sale::PAYED_WITH_PAYLATER; //sale dibayar dengan paylater jika hanya deposit 0 + $payedWith = Sale::PAYED_WITH_PAYLATER; } $sale = $customer->sales()->create([ @@ -157,11 +158,22 @@ class CartController extends Controller } } + $bonus = CoinReward::where('customer_level_id', $customer->customer_level_id) + ->where('amount_buy', '<=', $total) + ->orderBy('bonus_coin', 'desc')->first(); + + if ($bonus != null) { + $coin = $customer->coins()->create([ + 'debit' => $bonus->bonus_coin, + 'description' => 'Bonus Pembelian #' . $sale->code, + ]); + + $coin->update_customer_balance(); + } + $description = 'Pembayaran #' . $sale->code; - // paylater payment if ($customer->deposit_balance < $total) { - // allin if ($customer->deposit_balance > 0) { $deposit = $customer->deposites()->create([ 'credit' => $customer->deposit_balance, diff --git a/app/Models/CoinReward.php b/app/Models/CoinReward.php index fc30fe4..3f6f85d 100644 --- a/app/Models/CoinReward.php +++ b/app/Models/CoinReward.php @@ -9,4 +9,9 @@ class CoinReward extends Model 'bonus_coin', 'customer_level_id', ]; + + public function level() + { + return $this->belongsTo(CustomerLevel::class, 'customer_level_id'); + } } diff --git a/app/Models/Customer.php b/app/Models/Customer.php index c559252..d72a1d4 100644 --- a/app/Models/Customer.php +++ b/app/Models/Customer.php @@ -226,7 +226,7 @@ class Customer extends Authenticatable return [$allowProcess, $isPaylater]; } - public function repayPaylater(DepositHistory $deposit) + public function repayPaylater(DepositHistory $deposit): void { if ($this->paylater != null && $this->paylater->usage > 0) { $cut = $deposit->debit > $this->paylater->usage ? $this->paylater->usage : $deposit->debit; diff --git a/app/Services/GeneralService.php b/app/Services/GeneralService.php index c2f0978..9e2a209 100644 --- a/app/Services/GeneralService.php +++ b/app/Services/GeneralService.php @@ -61,7 +61,7 @@ class GeneralService $midtrans_enable = Setting::getByKey('MIDTRANS_ENABLED'); if ($midtrans_enable == 1) { - $payment[] = ['name' => Setting::PAYMENT_MIDTRANS, 'logo' => Setting::getByKey('MIDTRANS_LOGO')]; + $payment[] = ['name' => Setting::PAYMENT_MIDTRANS, 'logo' => asset(Setting::getByKey('MIDTRANS_LOGO'))]; } return $payment; diff --git a/resources/js/Layouts/Partials/routes.js b/resources/js/Layouts/Partials/routes.js index 99c6d3b..5f6792e 100644 --- a/resources/js/Layouts/Partials/routes.js +++ b/resources/js/Layouts/Partials/routes.js @@ -61,12 +61,12 @@ export default [ permission: 'view-deposit', }, { - name: 'Bonus Coin', //TODO + name: 'Bonus Coin', show: true, icon: HiOutlineCurrencyDollar, - route: route('voucher.index'), - active: 'voucher.*', - permission: 'view-voucher', + route: route('coin-reward.index'), + active: 'coin-reward.*', + permission: 'view-coin-reward', }, { name: 'Front Home', diff --git a/resources/js/Pages/CoinReward/FormModal.jsx b/resources/js/Pages/CoinReward/FormModal.jsx new file mode 100644 index 0000000..b37a8e1 --- /dev/null +++ b/resources/js/Pages/CoinReward/FormModal.jsx @@ -0,0 +1,122 @@ +import React, { useEffect } from 'react' +import Modal from '@/Components/Modal' +import { useForm, usePage } from '@inertiajs/react' +import Button from '@/Components/Button' +import FormInput from '@/Components/FormInput' +import RoleSelectionInput from '../Role/SelectionInput' + +import { isEmpty } from 'lodash' + +export default function FormModal(props) { + const { + props: { levels }, + } = usePage() + const { modalState } = props + const { data, setData, post, put, processing, errors, reset, clearErrors } = + useForm({ + amount_buy: 0, + bonus_coin: 0, + customer_level_id: null, + }) + + const handleOnChange = (event) => { + setData( + event.target.name, + event.target.type === 'checkbox' + ? event.target.checked + ? 1 + : 0 + : event.target.value + ) + } + + const handleReset = () => { + modalState.setData(null) + reset() + clearErrors() + } + + const handleClose = () => { + handleReset() + modalState.toggle() + } + + const handleSubmit = () => { + const reward = modalState.data + if (reward !== null) { + put(route('coin-reward.update', reward), { + onSuccess: () => handleClose(), + }) + return + } + post(route('coin-reward.store'), { + onSuccess: () => handleClose(), + }) + } + + useEffect(() => { + const reward = modalState.data + if (isEmpty(reward) === false) { + setData({ + amount_buy: reward.amount_buy, + bonus_coin: reward.bonus_coin, + customer_level_id: reward.customer_level_id, + }) + return + } + }, [modalState]) + + return ( + + +
+
Level
+ + {errors.customer_level_id && ( +

+ {errors.customer_level_id} +

+ )} +
+ +
+ + +
+
+ ) +} diff --git a/resources/js/Pages/CoinReward/Index.jsx b/resources/js/Pages/CoinReward/Index.jsx new file mode 100644 index 0000000..a5b4f05 --- /dev/null +++ b/resources/js/Pages/CoinReward/Index.jsx @@ -0,0 +1,175 @@ +import React from 'react' +import { router } from '@inertiajs/react' +import { Head } from '@inertiajs/react' +import { Button, Dropdown } from 'flowbite-react' +import { HiPencil, HiTrash } from 'react-icons/hi' +import { useModalState } from '@/hooks' + +import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' +import Pagination from '@/Components/Pagination' +import ModalConfirm from '@/Components/ModalConfirm' +import FormModal from './FormModal' +import { formatIDR, hasPermission } from '@/utils' + +export default function Info(props) { + const { + query: { links, data }, + auth, + } = props + + const confirmModal = useModalState() + const formModal = useModalState() + + const toggleFormModal = (reward = null) => { + formModal.setData(reward) + formModal.toggle() + } + + const handleDeleteClick = (reward) => { + confirmModal.setData(reward) + confirmModal.toggle() + } + + const onDelete = () => { + if (confirmModal.data !== null) { + router.delete(route('coin-reward.destroy', confirmModal.data.id)) + } + } + + const canCreate = hasPermission(auth, 'create-coin-reward') + const canUpdate = hasPermission(auth, 'update-coin-reward') + const canDelete = hasPermission(auth, 'delete-coin-reward') + + return ( + + + +
+
+
+
+ {canCreate && ( + + )} +
+
+
+ + + + + + + + + + {data.map((reward) => ( + + + + + + + ))} + +
+ Jumlah Transaksi + + Level + + Coin + +
+ {formatIDR( + reward.amount_buy + )} + + {reward.level.name} + + {formatIDR( + reward.bonus_coin + )} + + + {canUpdate && ( + + toggleFormModal( + reward + ) + } + > +
+ +
+ Ubah +
+
+
+ )} + {canDelete && ( + + handleDeleteClick( + reward + ) + } + > +
+ +
+ Hapus +
+
+
+ )} +
+
+
+
+ +
+
+
+
+
+ + +
+ ) +} diff --git a/resources/js/Pages/Setting/Index.jsx b/resources/js/Pages/Setting/Index.jsx index 8034e55..2fe7d12 100644 --- a/resources/js/Pages/Setting/Index.jsx +++ b/resources/js/Pages/Setting/Index.jsx @@ -21,7 +21,7 @@ export default function General(props) { MIDTRANS_SERVER_KEY: extractValue(setting, 'MIDTRANS_SERVER_KEY'), MIDTRANS_CLIENT_KEY: extractValue(setting, 'MIDTRANS_CLIENT_KEY'), MIDTRANS_MERCHANT_ID: extractValue(setting, 'MIDTRANS_MERCHANT_ID'), - MIDTRANS_LOGO: extractValue(setting, 'MIDTRANS_LOGO'), + MIDTRANS_LOGO_URL: extractValue(setting, 'MIDTRANS_LOGO'), MIDTRANS_ENABLED: extractValue(setting, 'MIDTRANS_ENABLED'), midtrans_logo_file: null, }) @@ -126,7 +126,7 @@ export default function General(props) { error={errors.midtrans_logo_file} preview={ site logo diff --git a/routes/admin.php b/routes/admin.php index 7d4926c..63461e4 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -3,6 +3,7 @@ use App\Http\Controllers\AccountController; use App\Http\Controllers\Auth\AuthenticatedSessionController; use App\Http\Controllers\BannerController; +use App\Http\Controllers\CoinRewardController; use App\Http\Controllers\CustomerController; use App\Http\Controllers\CustomerLevelController; use App\Http\Controllers\VerificationController; @@ -115,5 +116,11 @@ Route::middleware(['http_secure_aware', 'inertia.admin']) // deposit Route::get('/deposites', [DepositController::class, 'index'])->name('deposit.index'); Route::post('/deposites/{deposit}', [DepositController::class, 'update'])->name('deposit.update'); + + // coin rewared + Route::get('/bonus-coin', [CoinRewardController::class, 'index'])->name('coin-reward.index'); + Route::post('/bonus-coin', [CoinRewardController::class, 'store'])->name('coin-reward.store'); + Route::put('/bonus-coin/{reward}', [CoinRewardController::class, 'update'])->name('coin-reward.update'); + Route::delete('/bonus-coin/{reward}', [CoinRewardController::class, 'destroy'])->name('coin-reward.destroy'); }); });