first commit

This commit is contained in:
Firdachs08 2024-05-17 01:51:01 +07:00
commit d2b89cef7d
2983 changed files with 347530 additions and 0 deletions

18
.editorconfig Normal file
View File

@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4

56
.env.example Normal file
View File

@ -0,0 +1,56 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:pECxKdEqRKAZRX/2sUxIwWQLK617XWmqUqtuwNCBEr0=
APP_DEBUG=true
APP_URL=http://127.0.0.1:8000/
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=ecommerce
DB_USERNAME=root
DB_PASSWORD=
MIDTRANS_ID_MERCHANT=G415351610
MIDTRANS_CLIENT_KEY=SB-Mid-client-4QzG9xHXyPZzefUN
MIDTRANS_SERVER_KEY=SB-Mid-server-qbkLVLWGDXpR9tBHb7YUrX9s
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

5
.gitattributes vendored Normal file
View File

@ -0,0 +1,5 @@
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.env.backup
.phpunit.result.cache
docker-compose.override.yml
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
/.idea
/.vscode

14
.styleci.yml Normal file
View File

@ -0,0 +1,14 @@
php:
preset: laravel
version: 8
disabled:
- no_unused_imports
finder:
not-name:
- index.php
- server.php
js:
finder:
not-name:
- webpack.mix.js
css: true

32
app/Console/Kernel.php Normal file
View File

@ -0,0 +1,32 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* @var array<int, class-string<Throwable>>
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
$this->reportable(function (Throwable $e) {
//
});
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Exceptions;
use Exception;
class OutOfStockException extends Exception
{
public function report()
{
\Log::debug('The product is out of stock');
}
}

22
app/Exports/Revenue.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace App\Exports;
use App\Models\Booking;
use App\Models\Order;
use Maatwebsite\Excel\Concerns\FromCollection;
class RevenueExport implements FromCollection
{
public function collection()
{
// Retrieve data from Booking and Order models
$bookings = Booking::all();
$orders = Order::all();
// Merge data from bookings and orders into one collection
$data = $bookings->merge($orders);
return $data;
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Exports;
use App\Models\Booking;
use App\Models\Order;
use Maatwebsite\Excel\Concerns\FromCollection;
class RevenueExport implements FromCollection
{
public function collection()
{
// Retrieve data from Booking and Order models
$bookings = Booking::all();
$orders = Order::all();
// Merge data from bookings and orders into one collection
$data = $bookings->merge($orders);
return $data;
}
}

30
app/Helpers/General.php Normal file
View File

@ -0,0 +1,30 @@
<?php
namespace App\Helpers;
class General
{
/**
* Convert number to roman
*
* @param int $integer name
*
* @return string
*/
public static function integerToRoman($integer)
{
$integer = intval($integer);
$result = '';
// Create a lookup array that contains all of the Roman numerals.
$lookup = ['M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1];
foreach ($lookup as $roman => $value) {
$matches = intval($integer/$value);
$result .= str_repeat($roman, $matches);
$integer = $integer % $value;
}
return $result;
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class BaseController extends Controller
{
public function responseOk($result, $code = 200,$message = 'Success', $meta = []){
$response = [
'code' => $code,
'data' => $result,
'message' => $message,
];
if($meta){
$response['meta'] = $meta;
}
return response()->json($response, $code);
}
public function responseError($error, $code = 422,$errorDetails = []){
$response = [
'code' => $code,
'error' => $error
];
if(!empty($errorDetails)){
$response['errorDetails'] = $errorDetails;
}
return response()->json($response, $code);
}
}

View File

@ -0,0 +1,411 @@
<?php
namespace App\Http\Controllers\API;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Http\Controllers\API\BaseController;
use App\Http\Resources\Item as ItemResource;
use App\Models\Review;
use GuzzleHttp\Exception\GuzzleException;
use PhpParser\Node\Stmt\TryCatch;
class CartController extends BaseController
{
public function index(Request $request,$sessionKey = null)
{
if ($sessionKey = $request->user()->id) {
$cart = \Cart::session($sessionKey)->getContent();
}else{
$cart = \Cart::getContent();
}
if ($sessionKey) {
$shipping_cost = \Cart::session($sessionKey)->getCondition('shipping_cost');
}
$shipping_cost = \Cart::getCondition('shipping_cost');
$condition = new \Darryldecode\Cart\CartCondition(
[
'name' => 'TAX 10%',
'type' => 'tax',
'target' => 'subtotal',
'value' => '10%',
]
);
if ($sessionKey) {
\Cart::session($sessionKey)->removeConditionsByType('tax');
\Cart::session($sessionKey)->condition($condition);
} else {
\Cart::removeConditionsByType('tax');
\Cart::condition($condition);
}
if ($sessionKey) {
$tax = \Cart::session($sessionKey)->getCondition('TAX 10%');
}
$tax = \Cart::getCondition('TAX 10%');
if ($sessionKey) {
$subTotal = \Cart::session($sessionKey)->getSubTotal();
}
$subTotal = \Cart::getSubTotal();
if ($sessionKey) {
$total = \Cart::session($sessionKey)->getTotal();
}
$total = \Cart::getTotal();
$carts = [
'item' => ItemResource::collection($cart),
'shipping_cost' => $shipping_cost,
'tax' => $tax,
'sub_total' => $subTotal,
'total' => $total,
];
return $this->responseOk($carts,200,'success');
}
public function store(Request $request, $sessionKey = 0)
{
$validator = Validator::make($request->all(), [
'slug' => 'required',
'qty' => 'required'
]);
if($validator->fails()){
return $this->responseError('add item failed !', 422, $validator->errors());
}
$params = $request->all();
$product = Product::where('slug',$params['slug'])->firstOrFail();
$carts = \Cart::getContent();
$itemQuantity = 0;
if ($carts) {
foreach ($carts as $cart) {
if ($cart->id == $product->id) {
$itemQuantity = $cart->quantity;
break;
}
}
}
$itemQuantity += $request->qty;
if ($product->quantity < $itemQuantity) {
// throw new \App\Exceptions\OutOfStockException('The product '. $product->sku .' is out of stock');
}
$item = [
'id' => md5($product->id),
'name' => $product->name,
'price' => $product->price,
'quantity' => $request->qty,
'associatedModel' => $product,
];
if ($sessionKey = $request->user()->id) {
\Cart::session($sessionKey)->add($item);
$carts = \Cart::getContent();
return $this->responseOk(true,200,'success');
}else{
\Cart::add($item);
return $this->responseOk(true, 200,'success');
}
return $this->responseError('add item failed !', 422);
}
public function update(Request $request, $id)
{
$params = $request->all();
$validator = Validator::make($params, [
'quantity' => 'required|numeric'
]);
if($validator->fails()){
return $this->responseError('update failed !', 422,$validator->errors());
}
$sessionKey = $request->user()->id;
if ($sessionKey) {
$carts = \Cart::session($sessionKey)->getContent();
}else{
$carts = \Cart::getContent();
}
$item = !(empty($carts[$id])) ? $carts[$id] : null;
if(!$item){
return $this->responseError('item not found !', 404);
}
if ($item->quantity < $params['quantity'] ) {
// throw new \App\Exceptions\OutOfStockException('The product '. $carts[$cartId]->associatedModel->sku .' is out of stock');
}
$cartUpdate = \Cart::update($id,[
'quantity' => [
'relative' => false,
'value' => $params['quantity'],
],
]);
return $this->responseOk($cartUpdate, 200,'the item has been updated !');
}
public function destroy(Request $request, $id)
{
$sessionKey = $request->user()->id;
if ($sessionKey) {
$carts = \Cart::session($sessionKey)->getContent();
}else{
$carts = \Cart::getContent();
}
$item = !(empty($carts[$id])) ? $carts[$id] : null;
if(!$item){
return $this->responseError('item not found !', 404);
}
if ($sessionKey) {
$cartDelete = \Cart::session($sessionKey)->remove($id);
return $this->responseOk($cartDelete, 200,'the item has been deleted !');
}else {
$cartDelete = \Cart::remove($id);
return $this->responseOk($cartDelete, 200,'the item has been deleted !');
}
$this->responseError('deleted item failed !', 400);
}
public function clear(Request $request){
$sessionKey = $request->user()->id;
if ($sessionKey) {
$cartDestroy = \Cart::session($sessionKey)->clear();
}
$cartDestroy = \Cart::clear();
if($cartDestroy){
return $this->responseOk($cartDestroy, 200, 'the item has been cleared !');
}
return $this->responseError('clear cart item failed !', 400);
}
public function shippingOptions(Request $request)
{
$parameter = $request->all();
$validator = Validator::make($parameter, [
'city_id' => 'required|numeric'
]);
$sessionKey = $request->user()->id;
if($validator->fails()){
return $this->responseError('get shipping options failed !', 422, $validator->errors());
}
if ($sessionKey) {
\Cart::session($sessionKey)->isEmpty();
} else {
\Cart::isEmpty();
}
try {
$totalWeight = 0;
if ($sessionKey) {
$items = \Cart::session($sessionKey)->getContent();
} else {
$items = \Cart::getContent();
}
foreach ($items as $item) {
$totalWeight += ($item->quantity * $item->associatedModel->weight);
}
$params = [
'origin' => env('RAJAONGKIR_ORIGIN'),
'destination' => $parameter['city_id'],
'weight' => $totalWeight,
];
$results = [];
foreach ($this->couriers as $code => $courier) {
$params['courier'] = $code;
$response = $this->rajaOngkirRequest('cost', $params, 'POST');
if (!empty($response['rajaongkir']['results'])) {
foreach ($response['rajaongkir']['results'] as $cost) {
if (!empty($cost['costs'])) {
foreach ($cost['costs'] as $costDetail) {
$serviceName = strtoupper($cost['code']) .' - '. $costDetail['service'];
$costAmount = $costDetail['cost'][0]['value'];
$etd = $costDetail['cost'][0]['etd'];
$result = [
'service' => $serviceName,
'cost' => $costAmount,
'etd' => $etd,
'courier' => $code,
];
$results[] = $result;
}
}
}
}
}
$response = [
'origin' => $params['origin'],
'destination' => $params ['destination'],
'weight' => $totalWeight,
'results' => $results,
];
return $this->responseOk($response, 200,'success !');
} catch (\GuzzleHttp\Exception\RequestException $err) {
return $this->responseError($err->getMessage(), 400);
}
return $this->responseError('get shipping options failed !', 400);
}
public function setShipping(Request $request)
{
$params = $request->all();
$validator = Validator::make($params, [
'city_id' => ['required', 'numeric'],
'shipping_service' => ['required', 'string'],
]);
if ($validator->fails()) {
return $this->responseError('Set shipping failed', 422, $validator->errors());
}
$sessionKey = $request->user()->id;
if ($sessionKey) {
\Cart::session($sessionKey)->removeConditionsByType('shipping');
}
\Cart::removeConditionsByType('shipping');
$shippingService = $request->get('shipping_service');
$destination = $request->get('city_id');
$totalWeight = 0;
if ($sessionKey) {
$items = \Cart::session($sessionKey)->getContent();
} else {
$items = \Cart::getContent();
}
foreach ($items as $item) {
$totalWeight += ($item->quantity * $item->associatedModel->weight);
}
$params = [
'origin' => env('RAJAONGKIR_ORIGIN'),
'destination' => $destination,
'weight' => $totalWeight,
];
$results = [];
foreach ($this->couriers as $code => $courier) {
$params['courier'] = $code;
$response = $this->rajaOngkirRequest('cost', $params, 'POST');
if (!empty($response['rajaongkir']['results'])) {
foreach ($response['rajaongkir']['results'] as $cost) {
if (!empty($cost['costs'])) {
foreach ($cost['costs'] as $costDetail) {
$serviceName = strtoupper($cost['code']) .' - '. $costDetail['service'];
$costAmount = $costDetail['cost'][0]['value'];
$etd = $costDetail['cost'][0]['etd'];
$result = [
'service' => $serviceName,
'cost' => $costAmount,
'etd' => $etd,
'courier' => $code,
];
$results[] = $result;
}
}
}
}
}
$shippingOptions = [
'origin' => $params['origin'],
'destination' => $destination,
'weight' => $totalWeight,
'results' => $results,
];
$selectedShipping = null;
if ($shippingOptions['results']) {
foreach ($shippingOptions['results'] as $shippingOption) {
if (str_replace(' ', '', $shippingOption['service']) == $shippingService) {
$selectedShipping = $shippingOption;
break;
}
}
}
$status = null;
$message = null;
$data = [];
if ($selectedShipping) {
$status = 200;
$message = 'Success set shipping cost';
$condition = new \Darryldecode\Cart\CartCondition(
[
'name' => 'shipping_cost',
'type' => 'shipping',
'target' => 'total',
'value' => '+'. $selectedShipping['cost'],
]
);
\Cart::condition($condition);
if ($sessionKey) {
$carts= \Cart::session($sessionKey)->getTotal();
}
$carts = \Cart::getTotal();
$data['total'] = number_format($carts);
return $this->responseOk($data, 200, 'success');
}
return $this->responseError('Failed to set shipping cost', 400);
}
}

View File

@ -0,0 +1,347 @@
<?php
namespace App\Http\Controllers\API;
use App\Models\Order;
use App\Models\Payment;
use App\Models\Product;
use App\Models\Shipment;
use App\Models\OrderItem;
use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController;
class OrderController extends BaseController
{
public function checkout(Request $request){
$params = $request->user()->toArray();
$params = array_merge($params, $request->all());
$sessionKey = $request->user()->id;
$orders = \DB::transaction(
function () use ($params, $sessionKey) {
$destination = isset($params['ship_to']) ? $params['shipping_city_id'] : $params['city_id'];
if ($sessionKey) {
\Cart::session($sessionKey)->isEmpty();
} else {
\Cart::isEmpty();
}
$totalWeight = 0;
if ($sessionKey) {
$items = \Cart::session($sessionKey)->getContent();
} else {
$items = \Cart::getContent();
}
foreach ($items as $item) {
$totalWeight += ($item->quantity * $item->associatedModel->weight);
}
$param = [
'origin' => env('RAJAONGKIR_ORIGIN'),
'destination' => $destination,
'weight' => $totalWeight,
];
$results = [];
foreach ($this->couriers as $code => $courier) {
$param['courier'] = $code;
$response = $this->rajaOngkirRequest('cost', $param, 'POST');
if (!empty($response['rajaongkir']['results'])) {
foreach ($response['rajaongkir']['results'] as $cost) {
if (!empty($cost['costs'])) {
foreach ($cost['costs'] as $costDetail) {
$serviceName = strtoupper($cost['code']) .' - '. $costDetail['service'];
$costAmount = $costDetail['cost'][0]['value'];
$etd = $costDetail['cost'][0]['etd'];
$result = [
'service' => $serviceName,
'cost' => $costAmount,
'etd' => $etd,
'courier' => $code,
];
$results[] = $result;
}
}
}
}
}
$shippingOptions = [
'origin' => $param['origin'],
'destination' => $destination,
'weight' => $totalWeight,
'results' => $results,
];
$shippingService = $params['shipping_service'];
$selectedShipping = null;
if ($shippingOptions['results']) {
foreach ($shippingOptions['results'] as $shippingOption) {
if (str_replace(' ', '', $shippingOption['service']) == $shippingService) {
$selectedShipping = $shippingOption;
break;
}
}
}
if ($sessionKey) {
$condition = new \Darryldecode\Cart\CartCondition(
[
'name' => 'TAX 10%',
'type' => 'tax',
'target' => 'subtotal',
'value' => '10%',
]
);
if ($sessionKey) {
\Cart::session($sessionKey)->removeConditionsByType('tax');
\Cart::session($sessionKey)->condition($condition);
} else {
\Cart::removeConditionsByType('tax');
\Cart::condition($condition);
}
$items = \Cart::session($sessionKey)->getContent();
}
$condition = new \Darryldecode\Cart\CartCondition(
[
'name' => 'TAX 10%',
'type' => 'tax',
'target' => 'subtotal',
'value' => '10%',
]
);
if ($sessionKey) {
\Cart::session($sessionKey)->removeConditionsByType('tax');
\Cart::session($sessionKey)->condition($condition);
} else {
\Cart::removeConditionsByType('tax');
\Cart::condition($condition);
}
$items = \Cart::getContent();
$baseTotalPrice = 0;
foreach ($items as $item) {
$baseTotalPrice += $item->getPriceSum();
}
if ($sessionKey) {
\Cart::session($sessionKey)->getSubTotal();
}
\Cart::getSubTotal();
if ($sessionKey) {
$taxAmount = (float) \Cart::session($sessionKey)->getCondition('TAX 10%')->parsedRawValue;
}
$taxAmount = (float) \Cart::getCondition('TAX 10%')->parsedRawValue;
if ($sessionKey) {
$taxPercent = (float) \Cart::session($sessionKey)->getCondition('TAX 10%')->getValue();
}
$taxPercent = (float) \Cart::getCondition('TAX 10%')->getValue();
$shippingCost = $selectedShipping['cost'];
$discountAmount = 0;
$discountPercent = 0;
$grandTotal = ($baseTotalPrice + $taxAmount + $shippingCost) - $discountAmount;
$orderDate = date('Y-m-d H:i:s');
$paymentDue = (new \DateTime($orderDate))->modify('+7 day')->format('Y-m-d H:i:s');
$orderParams = [
'user_id' => auth()->user()->id,
'code' => Order::generateCode(),
'status' => Order::CREATED,
'order_date' => $orderDate,
'payment_due' => $paymentDue,
'payment_status' => Order::UNPAID,
'base_total_price' => $baseTotalPrice,
'tax_amount' => $taxAmount,
'tax_percent' => $taxPercent,
'discount_amount' => $discountAmount,
'discount_percent' => $discountPercent,
'shipping_cost' => $shippingCost,
'grand_total' => $grandTotal,
'note' => $params['note'],
'customer_first_name' => $params['first_name'],
'customer_last_name' => $params['last_name'],
'customer_address1' => $params['address1'],
'customer_address2' => $params['address2'],
'customer_phone' => $params['phone'],
'customer_email' => $params['email'],
'customer_city_id' => $params['city_id'],
'customer_province_id' => $params['province_id'],
'customer_postcode' => $params['postcode'],
'shipping_courier' => $selectedShipping['courier'],
'shipping_service_name' => $selectedShipping['service'],
];
$order = Order::create($orderParams);
if ($sessionKey) {
$condition = new \Darryldecode\Cart\CartCondition(
[
'name' => 'TAX 10%',
'type' => 'tax',
'target' => 'subtotal',
'value' => '10%',
]
);
if ($sessionKey) {
\Cart::session($sessionKey)->removeConditionsByType('tax');
\Cart::session($sessionKey)->condition($condition);
} else {
\Cart::removeConditionsByType('tax');
\Cart::condition($condition);
}
$cartItems = \Cart::session($sessionKey)->getContent();
}
$condition = new \Darryldecode\Cart\CartCondition(
[
'name' => 'TAX 10%',
'type' => 'tax',
'target' => 'subtotal',
'value' => '10%',
]
);
if ($sessionKey) {
\Cart::session($sessionKey)->removeConditionsByType('tax');
\Cart::session($sessionKey)->condition($condition);
} else {
\Cart::removeConditionsByType('tax');
\Cart::condition($condition);
}
$cartItems = \Cart::getContent();
if ($order && $cartItems) {
foreach ($cartItems as $item) {
$itemTaxAmount = 0;
$itemTaxPercent = 0;
$itemDiscountAmount = 0;
$itemDiscountPercent = 0;
$itemBaseTotal = $item->quantity * $item->price;
$itemSubTotal = $itemBaseTotal + $itemTaxAmount - $itemDiscountAmount;
$product = isset($item->associatedModel->parent) ? $item->associatedModel->parent : $item->associatedModel;
$orderItemParams = [
'order_id' => $order->id,
'product_id' => $item->associatedModel->id,
'qty' => $item->quantity,
'base_price' => $item->price,
'base_total' => $itemBaseTotal,
'tax_amount' => $itemTaxAmount,
'tax_percent' => $itemTaxPercent,
'discount_amount' => $itemDiscountAmount,
'discount_percent' => $itemDiscountPercent,
'sub_total' => $itemSubTotal,
'type' => $product->type,
'name' => $item->name,
'weight' => $item->associatedModel->weight,
];
$orderItem = OrderItem::create($orderItemParams);
if ($orderItem) {
$product = Product::findOrFail($product->id);
$product->quantity -= $item->quantity;
$product->save();
}
}
}
$this->initPaymentGateway();
$customerDetails = [
'first_name' => $order->customer_first_name,
'last_name' => $order->customer_last_name,
'email' => $order->customer_email,
'phone' => $order->customer_phone,
];
$data_payment = [
'enable_payments' => Payment::PAYMENT_CHANNELS,
'transaction_details' => [
'order_id' => $order->code,
'gross_amount' => (int) $order->grand_total,
],
'customer_details' => $customerDetails,
'expiry' => [
'start_time' => date('Y-m-d H:i:s T'),
'unit' => \App\Models\Payment::EXPIRY_UNIT,
'duration' => \App\Models\Payment::EXPIRY_DURATION,
],
];
$snap = \Midtrans\Snap::createTransaction($data_payment);
if ($snap->token) {
$order->payment_token = $snap->token;
$order->payment_url = $snap->redirect_url;
$order->save();
}
$shippingFirstName = isset($params['ship_to']) ? $params['shipping_first_name'] : $params['first_name'];
$shippingLastName = isset($params['ship_to']) ? $params['shipping_last_name'] : $params['last_name'];
$shippingAddress1 = isset($params['ship_to']) ? $params['shipping_address1'] : $params['address1'];
$shippingAddress2 = isset($params['ship_to']) ? $params['shipping_address2'] : $params['address2'];
$shippingPhone = isset($params['ship_to']) ? $params['shipping_phone'] : $params['phone'];
$shippingEmail = isset($params['ship_to']) ? $params['shipping_email'] : $params['email'];
$shippingCityId = isset($params['ship_to']) ? $params['shipping_city_id'] : $params['city_id'];
$shippingProvinceId = isset($params['ship_to']) ? $params['shipping_province_id'] : $params['province_id'];
$shippingPostcode = isset($params['ship_to']) ? $params['shipping_postcode'] : $params['postcode'];
$shipmentParams = [
'user_id' => auth()->user()->id,
'order_id' => $order->id,
'status' => Shipment::PENDING,
'total_qty' => \Cart::getTotalQuantity(),
'total_weight' => $totalWeight,
'first_name' => $shippingFirstName,
'last_name' => $shippingLastName,
'address1' => $shippingAddress1,
'address2' => $shippingAddress2,
'phone' => $shippingPhone,
'email' => $shippingEmail,
'city_id' => $shippingCityId,
'province_id' => $shippingProvinceId,
'postcode' => $shippingPostcode,
];
Shipment::create($shipmentParams);
return $order;
}
);
if ($orders) {
if ($sessionKey) {
\Cart::session($sessionKey)->clearCartConditions();
\Cart::session($sessionKey)->clear();
}
\Cart::clearCartConditions();
\Cart::clear();
return $this->responseOk($orders, 200, 'success');
}
return $this->responseError('Order process failed, 422');
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\API;
use App\Models\Product;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Http\Resources\Product as ProductResource;
use App\Http\Controllers\API\BaseController;
class ProductController extends BaseController
{
private $paginate = 2;
public function index(Request $request)
{
if((int)$request->req_page && (int)$request->req_page < 10){
$this->paginate = $request->req_page;
}
$products = Product::paginate($this->paginate);
if ($q = $request->query('q')) {
$products = Product::where('name','LIKE', '%'. $request->query('q'). '%')
->orWhere('description', 'LIKE', '%' . $request->query('q') . '%')
->paginate($this->paginate);
}
$meta = [
'paginate' => $this->paginate,
'current_page' => $products->currentPage(),
'total_pages' => $products->lastPage()
];
return $this->responseOk(ProductResource::collection($products),200,'success', $meta);
}
public function show(Request $request){
$product = Product::with('media', 'category', 'tags')
->where('slug', $request->slug)
->withCount('media','approvedReviews')
->withAvg('approvedReviews', 'rating')
->active()
->hasQuantity()
->firstOrFail();
return $this->responseOk(new ProductResource($product),200,'success');
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace App\Http\Controllers\API;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use App\Http\Controllers\API\BaseController;
class UserController extends BaseController
{
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => ['required', 'string', 'email'],
'password' => ['required', 'string']
]);
if($validator->fails()){
return $this->responseError('Login Failed !', 422, $validator->errors());
}
if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){
$user = auth()->user();
$response = [
'token' => $user->createToken('MyToken')->accessToken,
'first_name' => $user->first_name,
'last_name' => $user->last_name,
];
return $this->responseOk($response);
}else {
return $this->responseError('wrong email or password !', 401);
}
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'username' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
if ($validator->fails()) {
return $this->responseError('Registration failed', 422, $validator->errors());
}
$params = [
'username' => $request->username,
'email' => $request->email,
'password' => bcrypt($request->password),
];
if (!$user = User::create($params)) {
return $this->responseError('Registration failed', 400);
}
$token = $user->createToken('MyToken')->accessToken;
$response = [
'token' => $token,
'user' => $user,
];
return $this->responseOk($response);
}
public function getProfile(Request $request)
{
return $this->responseOk($request->user());
}
public function logout(Request $request)
{
$request->user()->token()->revoke();
return $this->responseOk(null, 200, 'Logged out successfully.');
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Booking;
use Illuminate\Http\Request;
class BookingController extends Controller
{
public function index()
{
$bookings = Booking::orderBy('id', 'DESC')->get();
return view('admin.booking.index', compact('bookings'));
}
}

View File

@ -0,0 +1,161 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Category;
use App\Traits\ImageUploadTrait;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Gate;
use App\Http\Requests\Admin\CategoryRequest;
use Symfony\Component\HttpFoundation\Response;
class CategoryController extends Controller
{
use ImageUploadTrait;
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//abort_if(Gate::denies('category_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$categories = Category::with('parent')->withCount('products')->latest()->paginate(5);
return view('admin.categories.index', compact('categories'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//abort_if(Gate::denies('category_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$parent_categories = Category::whereNull('category_id')->get(['id', 'name']);
return view('admin.categories.create', compact('parent_categories'));
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(CategoryRequest $request)
{
//abort_if(Gate::denies('category_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$image = NULL;
if ($request->hasFile('cover')) {
$image = $this->uploadImage($request->name, $request->cover, 'categories', 268, 268);
}
Category::create([
'name' => $request->name,
'category_id' => $request->category_id,
'cover' => $image,
]);
return redirect()->route('admin.categories.index')->with([
'message' => 'success created !',
'alert-type' => 'success'
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Category $category)
{
//abort_if(Gate::denies('category_view'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.categories.show', compact('category'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(Category $category)
{
//abort_if(Gate::denies('category_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$parent_categories = Category::whereNull('category_id')->get(['id', 'name']);
return view('admin.categories.edit', compact('parent_categories', 'category'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(CategoryRequest $request,Category $category)
{
//abort_if(Gate::denies('category_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$image = $category->cover;
if ($request->has('cover')) {
if ($category->cover != null && File::exists('storage/images/categories/'. $category->cover)) {
unlink('storage/images/categories/'. $category->cover);
}
$image = $this->uploadImage($request->name, $request->cover, 'categories', 268, 268);
}
$category->update([
'name' => $request->name,
'category_id' => $request->category_id,
'cover' => $image,
]);
return redirect()->route('admin.categories.index')->with([
'message' => 'success updated !',
'alert-type' => 'info'
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Category $category)
{
//abort_if(Gate::denies('category_delete'), Response::HTTP_FORBIDDEN, '403 Forbidden');
if($category->category_id == null) {
foreach($category->children as $child) {
if (File::exists('storage/images/categories/'. $child->cover)) {
unlink('storage/images/categories/'. $child->cover);
}
}
}
if ($category->cover) {
if (File::exists('storage/images/categories/'. $category->cover)) {
unlink('storage/images/categories/'. $category->cover);
}
}
$category->delete();
return redirect()->route('admin.categories.index')->with([
'message' => 'success deleted !',
'alert-type' => 'danger',
]);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Order;
use App\Models\Product;
use App\Models\Booking;
use App\Models\Service;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class DashboardController extends Controller
{
public function index(){
$product_count = Product::count();
$booking_count = Booking::count();
$service_count = Service::count();
$order = Order::count();
return view('admin.dashboard', compact('product_count','booking_count', 'service_count','order'));
}
}

View File

@ -0,0 +1,110 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Obtained;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\StoreObtainedRequest;
use App\Http\Requests\Admin\UpdateObtainedRequest;
use Illuminate\Support\Facades\Gate;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Http\Request;
class ObtainedController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//abort_if(Gate::denies('obtained_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$obtaineds = Obtained::paginate(5);
return view('admin.obtaineds.index', compact('obtaineds'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//abort_if(Gate::denies('obtained_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.obtaineds.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(StoreObtainedRequest $request)
{
//abort_if(Gate::denies('obtained_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
Obtained::create($request->validated());
return redirect()->route('admin.obtained.index')->with('message', "Service Obtained Successfully Created !");
}
/**
* Display the specified resource.
*
* @param \App\Models\Obtained $obtained
* @return \Illuminate\Http\Response
*/
public function show(Obtained $obtained)
{
return redirect()->route('admin.obtained.index');
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Obtained $obtained
* @return \Illuminate\Http\Response
*/
public function edit(Obtained $obtained)
{
//abort_if(Gate::denies('obtained_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.obtaineds.edit', compact('obtained'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Obtained $obtained
* @return \Illuminate\Http\Response
*/
public function update(UpdateObtainedRequest $request, Obtained $obtained)
{
//abort_if(Gate::denies('obtained_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$obtained->update($request->validated());
return redirect()->route('admin.obtained.index')->with('message', 'Service Obtained Successfully Updated !');
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Obtained $obtained
* @return \Illuminate\Http\Response
*/
public function destroy(Obtained $obtained)
{
//abort_if(Gate::denies('obtained_delete'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$obtained->delete();
return redirect()->route('admin.obtained.index')->with('message', 'Obtained Service Successfully Deleted !');
}
}

View File

@ -0,0 +1,156 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Order;
use App\Models\OrderItem;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Product;
class OrderController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$orders = Order::latest();
if ($request->input('status') && in_array($request->input('status'), array_keys(Order::STATUSES))) {
$orders = $orders->where('status', '=', $request->input('status'));
}
$startDate = $request->input('start');
$endDate = $request->input('end');
if ($startDate && !$endDate) {
return redirect('admin/orders');
}
if (!$startDate && $endDate) {
return redirect('admin/orders');
}
if ($startDate && $endDate) {
if (strtotime($endDate) < strtotime($startDate)) {
return redirect('admin/orders');
}
$orders = $orders->whereRaw("DATE(order_date) >= ?", $startDate)
->whereRaw("DATE(order_date) <= ? ", $endDate);
}
$orders = $orders->paginate(10);
return view('admin.orders.index', compact('orders'));
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Order $order)
{
return view('admin.orders.show', compact('order'));
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Order $order)
{
// \DB::transaction(
// function () use ($order) {
// OrderItem::where('order_id', $order->id)->delete();
// $order->shipment->delete();
// $order->forceDelete();
// return true;
// }
// );
OrderItem::where('order_id', $order->id)->delete();
$order->delete();
return redirect()->route('admin.orders.index')->with([
'message' => 'success deleted !',
'alert-type' => 'danger'
]);;
}
public function cancel($id)
{
$order = Order::where('id', $id)
->whereIn('status', [Order::CREATED, Order::CONFIRMED])
->firstOrFail();
return view('admin.orders.cancel', compact('order'));
}
public function cancelUpdate(Request $request, $id)
{
$request->validate(
[
'cancellation_note' => 'required|max:255',
]
);
$order = Order::findOrFail($id);
$cancelOrder = \DB::transaction(
function () use ($order, $request) {
$params = [
'status' => Order::CANCELLED,
'cancelled_by' => auth()->id(),
'cancelled_at' => now(),
'cancellation_note' => $request->cancellation_note,
];
if ($cancelOrder = $order->update($params) && $order->orderItems->count() > 0) {
foreach ($order->orderItems as $item) {
$product = Product::findOrFail($item->product_id);
$product->quantity += $item->qty;
$product->save();
}
}
return $cancelOrder;
}
);
return redirect()->route('admin.orders.index')->with([
'message' => 'success cancelled !',
'alert-type' => 'danger'
]);;
}
public function complete(Request $request, $id)
{
$order = Order::findOrFail($id);
if (!$order->isDelivered()) {
return redirect()->route('admin.orders.index');
}
$order->status = Order::COMPLETED;
$order->approved_by = auth()->id();
$order->approved_at = now();
if ($order->save()) {
return redirect()->route('admin.orders.index')->with([
'message' => 'completed order !',
'alert-type' => 'success'
]);;
}
}
}

View File

@ -0,0 +1,175 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Tag;
use App\Models\Product;
use App\Models\Category;
use App\Services\ImageService;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Gate;
use Illuminate\Http\Request;
use App\Http\Requests\Admin\ProductRequest;
use Symfony\Component\HttpFoundation\Response;
class ProductController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//abort_if(Gate::denies('product_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$products = Product::with('category', 'tags', 'firstMedia')->latest()->paginate(5);
return view('admin.products.index', compact('products'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//abort_if(Gate::denies('product_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$categories = Category::latest()->get(['id', 'name']);
$tags = Tag::latest()->get(['id', 'name']);
return view('admin.products.create', compact('categories','tags'));
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(ProductRequest $request)
{
//abort_if(Gate::denies('product_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
if ($request->validated()){
$product = Product::create($request->except('tags', 'images', '_token'));
$product->tags()->attach($request->tags);
if ($request->images && count($request->images) > 0) {
(new ImageService())->storeProductImages($request->images, $product);
}
return redirect()->route('admin.products.index')->with([
'message' => 'success created !',
'alert-type' => 'success'
]);
}
return back()->with([
'message' => 'Something was wrong, please try again later',
'alert-type' => 'danger'
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Product $product)
{
//abort_if(Gate::denies('product_view'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.products.show', compact('product'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(Product $product)
{
//abort_if(Gate::denies('product_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$categories = Category::latest()->get(['id', 'name']);
$tags = Tag::latest()->get(['id', 'name']);
return view('admin.products.edit', compact('categories','product','tags'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(ProductRequest $request,Product $product)
{
//abort_if(Gate::denies('product_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
if ($request->validated()) {
$product->update($request->except('tags', 'images', '_token'));
$product->tags()->sync($request->tags);
$i = $product->media()->count() + 1;
if ($request->images && count($request->images) > 0) {
(new ImageService())->storeProductImages($request->images, $product, $i);
}
return redirect()->route('admin.products.index')->with([
'message' => 'success created !',
'alert-type' => 'success'
]);
}
return back()->with([
'message' => 'Something was wrong, please try again late',
'alert-type' => 'danger'
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Product $product)
{
//abort_if(Gate::denies('product_delete'), Response::HTTP_FORBIDDEN, '403 Forbidden');
if ($product->media->count() > 0) {
foreach ($product->media as $media) {
(new ImageService())->unlinkImage($media->file_name, 'products');
$media->delete();
}
}
$product->delete();
return redirect()->route('admin.products.index')->with([
'message' => 'success deleted !',
'alert-type' => 'danger',
]);
}
public function removeImage(Request $request)
{
//abort_if(Gate::denies('product_delete'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$product = Product::findOrFail($request->product_id);
$image = $product->media()->whereId($request->image_id)->first();
(new ImageService())->unlinkImage($image->file_name, 'products');
$image->delete();
return true;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Booking;
use App\Models\Order;
use App\Exports\RevenueExport;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Maatwebsite\Excel\Facades\Excel;
use PDF;
class ReportController extends Controller
{
public function export(Request $request)
{
$exportType = $request->input('export');
if ($exportType == 'pdf') {
$data = Booking::all()->merge(Order::all());
$startDate = $data->min('created_at')->format('Y-m-d'); // Tanggal pertama
$endDate = $data->max('created_at')->format('Y-m-d');
$pdf = PDF::loadView('admin.reports.exports.revenue_pdf', compact('data', 'startDate', 'endDate'));
return $pdf->download('revenue_report.pdf');
} elseif ($exportType == 'xlsx') {
return Excel::download(new RevenueExport(), 'revenue_report.xlsx');
}
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Review;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\ReviewRequest;
class ReviewController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$reviews = Review::with('product', 'user')->latest()->paginate(5);
return view('admin.reviews.index', compact('reviews'));
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Review $review)
{
return view('admin.reviews.show', compact('review'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(Review $review)
{
return view('admin.reviews.edit', compact('review'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(ReviewRequest $request,Review $review)
{
$review->update($request->validated());
return redirect()->route('admin.reviews.index')->with([
'message' => 'success updated !',
'alert-type' => 'info'
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Review $review)
{
$review->delete();
return redirect()->route('admin.reviews.index')->with([
'message' => 'success deleted !',
'alert-type' => 'danger'
]);
}
}

View File

@ -0,0 +1,136 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Schedule;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Gate;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Http\Request;
class ScheduleController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// abort_if(Gate::denies('schedule_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
//$schedules = Schedule::orderByRaw("CASE WHEN status = 'available' THEN 1 ELSE 2 END")->get();
$schedules = Schedule::all();
//return view('admin.index', compact('schedules'));
return view('admin.schedule.index', compact('schedules'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
// abort_if(Gate::denies('schedule_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.schedule.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//abort_if(Gate::denies('schedule_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
// Ubah format tanggal ke 'yyyy-mm-dd'
$date = \DateTime::createFromFormat('d-m-Y', $request->input('date'))->format('Y-m-d');
Schedule::create([
'date' => $date,
'start_time' => $request->input('start_time'),
'end_time' => $request->input('end_time'),
'max_slot' => $request->input('max_slot') // Tambahkan nilai 'max_slot'
]);
return redirect()->route('admin.schedule.index')->with('message', "Schedule Successfully Created !");
}
/**
* Display the specified resource.
*
* @param \App\Models\Schedule $schedule
* @return \Illuminate\Http\Response
*/
public function show(Schedule $schedule)
{
return redirect()->route('admin.schedule.index');
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Schedule $schedule
* @return \Illuminate\Http\Response
*/
public function edit(Schedule $schedule)
{
//abort_if(Gate::denies('schedule_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.schedule.edit', compact('schedule'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Schedule $schedule
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Schedule $schedule)
{
// Validasi input
$request->validate([
'date' => 'required',
'start_time' => 'required',
'end_time' => 'required',
'max_slot' => 'required'
]);
// Periksa apakah jumlah slot yang baru lebih besar dari jumlah slot yang sudah digunakan
if ($request->max_slot > $schedule->used_slot) {
// Jika lebih besar, maka ubah status menjadi "available"
$request->merge(['status' => 'available']);
}
// Update schedule
$schedule->update([
'date' => $request->date,
'start_time' => $request->start_time,
'end_time' => $request->end_time,
'max_slot' => $request->max_slot,
'status' => $request->status // Ubah status sesuai dengan logika di atas
]);
// Redirect ke halaman index dengan pesan sukses
return redirect()->route('admin.schedule.index')->with('message', "Schedule Successfully Updated !");
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Schedule $schedule
* @return \Illuminate\Http\Response
*/
public function destroy(Schedule $schedule)
{
//abort_if(Gate::denies('schedule_delete'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$schedule->delete();
return redirect()->route('admin.schedule.index')->with('message', "Schedule Successfully Deleted !");
}
}

View File

@ -0,0 +1,117 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\ServiceCategory;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Str;
class ServiceCategoryController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//abort_if(Gate::denies('category_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$serviceCategories = ServiceCategory::get();
return view('admin.servicecategory.index', compact('serviceCategories'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//abort_if(Gate::denies('category_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.servicecategory.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//abort_if(Gate::denies('category_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
ServiceCategory::create([
'name' => Str::ucfirst($request->get('name')),
'slug' => Str::slug($request->get('name'))
]);
return redirect()->route('admin.category.index')->with('message', "Service Category Successfully Created !");
}
/**
* Display the specified resource.
*
* @param \App\Models\ServiceCategory $serviceCategory
* @return \Illuminate\Http\Response
*/
public function show(ServiceCategory $serviceCategory)
{
return redirect()->route('admin.category.index');
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\ServiceCategory $serviceCategory
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//abort_if(Gate::denies('category_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$serviceCategory = ServiceCategory::findOrFail($id);
return view('admin.serviceCategory.edit', compact('serviceCategory'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\ServiceCategory $serviceCategory
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//abort_if(Gate::denies('category_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$serviceCategory = ServiceCategory::findOrFail($id);
$request->validate([
'name' => 'required'
]);
$serviceCategory->update([
'name' => Str::ucfirst($request->name),
'slug' => Str::slug($request->name)
]);
return redirect()->route('admin.category.index')->with('message', 'Service Category Successfully Updated !');
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\ServiceCategory $serviceCategory
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//abort_if(Gate::denies('category_delete'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$serviceCategory = ServiceCategory::findOrFail($id);
$serviceCategory->delete();
return redirect()->route('admin.category.index')->with('message', 'Category Service Successfully Deleted !');
}
}

View File

@ -0,0 +1,108 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Service;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\StoreServiceRequest;
use App\Http\Requests\Admin\UpdateServiceRequest;
use App\Models\Obtained;
use App\Models\ServiceCategory;
use Illuminate\Support\Facades\Gate;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Http\Request;
class ServiceController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$services = Service::paginate(5);
return view('admin.services.index', compact('services'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
$obtaineds = Obtained::pluck('name', 'id');
$serviceCategories = ServiceCategory::get();
return view('admin.services.create', compact('obtaineds', 'serviceCategories'));
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(StoreServiceRequest $request)
{
$service = Service::create($request->validated());
$service->obtaineds()->sync($request->input('obtaineds'));
return redirect()->route('admin.service.index')->with('message', "Service Successfully Created !");
}
/**
* Display the specified resource.
*
* @param \App\Models\Service $service
* @return \Illuminate\Http\Response
*/
public function show(Service $service)
{
return redirect()->route('admin.service.index');
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Service $service
* @return \Illuminate\Http\Response
*/
public function edit(Service $service)
{
$obtaineds = Obtained::pluck('name', 'id');
$serviceCategories = ServiceCategory::get();
return view('admin.services.edit', compact('service', 'obtaineds', 'serviceCategories'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Service $service
* @return \Illuminate\Http\Response
*/
public function update(UpdateServiceRequest $request, Service $service)
{
$service->update($request->validated());
$service->obtaineds()->sync($request->input('obtaineds'));
return redirect()->route('admin.service.index')->with('message', "Service Successfully Updated !");
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Service $service
* @return \Illuminate\Http\Response
*/
public function destroy(Service $service)
{
$service->delete();
return redirect()->route('admin.service.index')->with('message', "Service Successfully Deleted !");
}
}

View File

@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Order;
use App\Models\Shipment;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class ShipmentController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$shipments = Shipment::latest()->paginate(10);
return view('admin.shipments.index', compact('shipments'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(Shipment $shipment)
{
$provinces = $this->getProvinces();
$cities = isset($shipment->province_id) ? $this->getCities($shipment->province_id) : [];
return view('admin.shipments.edit', compact('shipment', 'provinces', 'cities'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Shipment $shipment)
{
$request->validate(
[
'track_number' => 'required|max:255',
]
);
$order = \DB::transaction(
function () use ($shipment, $request) {
$shipment->track_number = $request->input('track_number');
$shipment->status = Shipment::SHIPPED;
$shipment->shipped_at = now();
$shipment->shipped_by = auth()->id();
if ($shipment->save()) {
$shipment->order->status = Order::DELIVERED;
$shipment->order->save();
}
return $shipment->order;
}
);
return redirect()->route('admin.orders.show', $order->id)->with([
'message' => 'success updated shipment !',
'alert-type' => 'info'
]);
}
}

View File

@ -0,0 +1,185 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Slide;
use Illuminate\Http\Request;
use App\Traits\ImageUploadTrait;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\File;
use App\Http\Requests\Admin\SlideRequest;
class SlideController extends Controller
{
use ImageUploadTrait;
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$slides = Slide::latest()->paginate(5);
return view('admin.slides.index', compact('slides'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('admin.slides.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(SlideRequest $request)
{
$image = NULL;
if ($request->hasFile('cover')) {
$image = $this->uploadImage($request->title, $request->cover, 'slides', 500, 500);
}
Slide::create([
'title' => $request->title,
'url' => $request->url,
'body' => $request->body,
'cover' => $image,
'position' => Slide::max('position') + 1
]);
return redirect()->route('admin.slides.index')->with([
'message' => 'success created !',
'alert-type' => 'success'
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Slide $slide)
{
return view('admin.slides.show', compact('slide'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(Slide $slide)
{
return view('admin.slides.edit', compact('slide'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request,Slide $slide)
{
$image = $slide->cover;
if ($request->has('cover')) {
if ($slide->cover != null && File::exists('storage/images/slides/'. $slide->cover)) {
unlink('storage/images/slides/'. $slide->cover);
}
$image = $this->uploadImage($request->title, $request->cover, 'slides', 450, 450);
}
$slide->update([
'title' => $request->title,
'url' => $request->url,
'body' => $request->body,
'cover' => $image,
]);
return redirect()->route('admin.slides.index')->with([
'message' => 'success updated !',
'alert-type' => 'info'
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Slide $slide)
{
if ($slide->cover) {
if (File::exists('storage/images/slides/'. $slide->cover)) {
unlink('storage/images/slides/'. $slide->cover);
}
}
$slide->delete();
return redirect()->route('admin.slides.index')->with([
'message' => 'success deleted !',
'alert-type' => 'danger'
]);
}
public function moveUp($slideId){
$slide = Slide::findOrFail($slideId);
if (!$slide->prevSlide()) {
return redirect()->route('admin.slides.index');
}
\DB::transaction(
function () use ($slide) {
$currentPosition = $slide->position;
$prevPosition = $slide->prevSlide()->position;
$prevSlide = Slide::find($slide->prevSlide()->id);
$prevSlide->position = $currentPosition;
$prevSlide->save();
$slide->position = $prevPosition;
$slide->save();
}
);
return redirect()->route('admin.slides.index');
}
public function moveDown($slideId){
$slide = Slide::findOrFail($slideId);
if (!$slide->nextSlide()) {
return redirect()->route('admin.slides.index');
}
\DB::transaction(
function () use ($slide) {
$currentPosition = $slide->position;
$prevPosition = $slide->nextSlide()->position;
$prevSlide = Slide::find($slide->nextSlide()->id);
$prevSlide->position = $currentPosition;
$prevSlide->save();
$slide->position = $prevPosition;
$slide->save();
}
);
return redirect()->route('admin.slides.index');
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Tag;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Gate;
use App\Http\Requests\Admin\TagRequest;
use Symfony\Component\HttpFoundation\Response;
class TagController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//abort_if(Gate::denies('tag_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$tags = Tag::withCount('products')->latest()->paginate(5);
return view('admin.tags.index', compact('tags'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//abort_if(Gate::denies('tag_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.tags.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(TagRequest $request)
{
//abort_if(Gate::denies('tag_create'), Response::HTTP_FORBIDDEN, '403 Forbidden');
Tag::create($request->validated());
return redirect()->route('admin.tags.index')->with([
'message' => 'success created !',
'alert-type' => 'success'
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Tag $tag)
{
//abort_if(Gate::denies('tag_view'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.tags.show', compact('tag'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(Tag $tag)
{
//abort_if(Gate::denies('tag_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('admin.tags.edit', compact('tag'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(TagRequest $request, Tag $tag)
{
//abort_if(Gate::denies('tag_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$tag->update($request->validated());
return redirect()->route('admin.tags.index')->with([
'message' => 'success updated !',
'alert-type' => 'info'
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Tag $tag)
{
//abort_if(Gate::denies('tag_delete'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$tag->delete();
return redirect()->route('admin.tags.index')->with([
'message' => 'success deleted !',
'alert-type' => 'danger',
]);
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\Role;
use App\Models\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\StoreUserRequest;
use App\Http\Requests\Admin\UpdateUserRequest;
class UserController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$users = User::paginate(5);
return view('admin.users.index', compact('users'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('admin.users.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(StoreUserRequest $request)
{
$user = User::create($request->validated() + ['password' => bcrypt($request->password)]);
return redirect()->route('admin.users.index')->with('message', "Successfully Created !");
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$user = User::findOrFail($id);
//$roles = Role::all(); // Ganti Role dengan model yang sesuai dengan role Anda
return view('admin.users.edit', compact('user'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(UpdateUserRequest $request, $id)
{
$user = User::findOrFail($id);
$user->update($request->validated() + ['password' => bcrypt($request->password)]);
return redirect()->route('admin.users.index')->with('message', "Successfully Updated !");
}
// Methods for deleting users...
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\ConfirmsPasswords;
class ConfirmPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Confirm Password Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password confirmations and
| uses a simple trait to include the behavior. You're free to explore
| this trait and override any functions that require customization.
|
*/
use ConfirmsPasswords;
/**
* Where to redirect users when the intended url fails.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/
use SendsPasswordResetEmails;
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\ProfileRequest;
class ProfileController extends Controller
{
public function index()
{
$provinces = $this->getProvinces();
$cities = isset(auth()->user()->province_id) ? $this->getCities(auth()->user()->province_id) : [];
$user = auth()->user();
return view('frontend.users.profile', compact('provinces', 'cities','user'));
}
public function update(ProfileRequest $request){
$user = auth()->user();
$user->update($request->validated());
return redirect()->route('profile.index')->with(['message' => 'success updated']);
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'username' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
//'phone' => ['required', 'string'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\User
*/
protected function create(array $data)
{
$user = User::create([
'username' => $data['username'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
//'phone' => $data['phone'],
//'role' => 2, // Menetapkan peran secara langsung
]);
if ($user->id === 1) {
$user->role = 1; // ID 1 menjadi admin
} else {
$user->role = 2; // ID bukan 1, maka menjadi user biasa
}
$user->save();
return $user;
//return $user;
//$user->roles()->attach([2]);
//return $user;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Where to redirect users after resetting their password.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\VerifiesEmails;
class VerificationController extends Controller
{
/*
|--------------------------------------------------------------------------
| Email Verification Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling email verification for any
| user that recently registered with the application. Emails may also
| be re-sent if the user didn't receive the original email message.
|
*/
use VerifiesEmails;
/**
* Where to redirect users after verification.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
}

View File

@ -0,0 +1,179 @@
<?php
namespace App\Http\Controllers;
use App\Models\Booking;
use App\Models\Schedule;
use App\Models\Service;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class BookingController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'name' => 'required',
'handphone' => 'required|numeric',
'category' => 'required',
'schedule_id' => 'required|exists:schedules,id',
]);
$schedule = Schedule::find($request->schedule_id);
$scheduleId = $schedule->id;
$currentBookings = Booking::where('schedule_id', $request->schedule_id)->count();
if ($currentBookings >= $schedule->max_slot) {
return redirect()->back()->with('error', 'Schedule is fully booked');
}
$date = $schedule->date;
$time = $schedule->time;
$booking = Booking::create([
'service_name' => $request->service_name,
'name' => $request->name,
'handphone' => $request->handphone,
'category' => $request->category,
'date' => $date,
'time' => $time,
'total' => $request->price,
'status' => 'Unpaid',
'schedule_id' => $request->schedule_id, // Assign schedule_id here
]);
if ($request['cash'] === "on" && $request['cashless'] === "on") {
return '<script>alert("Choose one payment only!!!");window.location.href="/orders/checkout"</script>';
}
if ($currentBookings + 1 >= $schedule->max_slot) {
$schedule->status = 'not available';
$schedule->save();
}
if ($request['cash'] === "on") {
$booking->update(['status' => 'Cash']);
// $scheduleData->update(['status' => 'booked']);
return view('frontend.booking.paycash', compact('booking'));
}
// Set your Merchant Server Key
\Midtrans\Config::$serverKey = config('midtrans.serverKey');
// Set to Development/Sandbox Environment (default). Set to true for Production Environment (accept real transaction).
\Midtrans\Config::$isProduction = false;
// Set sanitization on (default)
\Midtrans\Config::$isSanitized = true;
// Set 3DS transaction for credit card to true
\Midtrans\Config::$is3ds = true;
$params = array(
'transaction_details' => array(
'order_id' => Str::random(15),
'gross_amount' => $request->price,
),
'customer_details' => array(
'name' => $request->name,
'handphone' => $request->handphone,
),
);
$snapToken = \Midtrans\Snap::getSnapToken($params);
return view('frontend.booking.detail', compact('snapToken', 'booking', 'scheduleId'));
}
/**
* Display the specified resource.
*
* @param \App\Models\Booking $booking
* @return \Illuminate\Http\Response
*/
public function show($serviceId)
{
$service = Service::findOrFail($serviceId);
$schedules = Schedule::where(['status' => 'available'])->get();
return view('frontend.booking.index', compact('service', 'schedules'));
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Booking $booking
* @return \Illuminate\Http\Response
*/
public function edit(Booking $booking)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Booking $booking
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Booking $booking)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Booking $booking
* @return \Illuminate\Http\Response
*/
public function destroy(Booking $booking)
{
//
}
public function midtrans_callback(Request $request)
{
$serverKey = config('midtrans.serverKey');
$hashed = hash('sha512', $request->order_id . $request->status_code . $request->gross_amount . $serverKey);
if ($hashed == $request->signature_key) {
if ($request->transaction_status == 'capture') {
$booking = Booking::find($request->order_id);
$booking->update(['status' => 'Paid']);
}
}
}
public function payment_success($bookingId, $scheduleId)
{
$booking = Booking::findOrFail($bookingId);
$booking->update(['status' => 'Paid']);
$schedule = Schedule::findOrFail($scheduleId);
//$schedule->update(['status' => 'booked']);
return redirect()->route('service.index');
}
}

View File

@ -0,0 +1,129 @@
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
use App\Exceptions\OutOfStockException;
class CartController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$carts = \Cart::getContent();
return view('frontend.cart.index', compact('carts'));
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$product = Product::findOrFail($request->product_id);
$carts = \Cart::getContent();
$itemQuantity = 0;
if ($carts) {
foreach ($carts as $cart) {
if ($cart->name == $product->name) {
$itemQuantity = $cart->quantity;
break;
}
}
}
$itemQuantity += $request->qty;
try {
if ($product->quantity < $itemQuantity) {
throw new OutOfStockException('produk '. $product->name .' kosong !');
}
} catch (\App\Exceptions\OutOfStockException $exception) {
return redirect()->back()->with([
'message' => $exception->getMessage(),
'alert-type' => 'danger',
]);
}
$item = [
'id' => md5($product->id),
'name' => $product->name,
'price' => $product->price,
'quantity' => $request->qty,
'associatedModel' => $product,
];
\Cart::add($item);
return redirect()->back()->with([
'message' => 'success added to cart !',
'alert-type' => 'success',
]);;
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request)
{
$params = $request->except('_token');
if($items = $params['items']){
foreach($items as $cartId => $item){
$carts = \Cart::getContent();
try {
if ($carts[$cartId]->associatedModel->quantity < $item['quantity']) {
throw new OutOfStockException('produk '. $carts[$cartId]->associatedModel->name .' tersisa ' . $carts[$cartId]->associatedModel->quantity);
}
} catch (\App\Exceptions\OutOfStockException $exception) {
return redirect()->back()->with([
'message' => $exception->getMessage(),
'alert-type' => 'danger',
]);
}
\Cart::update($cartId,[
'quantity' => [
'relative' => false,
'value' => $item['quantity'],
],
]);
}
return redirect()->back()->with([
'message' => 'success updated !',
'alert-type' => 'info'
]);
}
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($cartId)
{
\Cart::remove($cartId);
return redirect()->back()->with([
'message' => 'success deleted !',
'alert-type' => 'danger'
]);;
}
}

View File

@ -0,0 +1,142 @@
<?php
namespace App\Http\Controllers;
use Midtrans\Config;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
protected $data = [];
protected $uploadsFolder = 'uploads/';
protected $rajaOngkirApiKey = null;
protected $rajaOngkirBaseUrl = null;
protected $rajaOngkirOrigin = null;
protected $couriers = [
'jne' => 'JNE',
'pos' => 'POS Indonesia',
'tiki' => 'Titipan Kilat'
];
protected $provinces = [];
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->rajaOngkirApiKey = config('rajaongkir.api_key');
$this->rajaOngkirBaseUrl = config('rajaongkir.base_url');
$this->rajaOngkirOrigin = config('rajaongkir.origin');
}
/**
* Raja Ongkir Request (Shipping Cost Calculation)
*
* @param string $resource resource url
* @param array $params parameters
* @param string $method request method
*
* @return json
*/
protected function rajaOngkirRequest($resource, $params = [], $method = 'GET')
{
$client = new \GuzzleHttp\Client();
$headers = ['key' => $this->rajaOngkirApiKey];
$requestParams = [
'headers' => $headers,
];
$url = $this->rajaOngkirBaseUrl . $resource;
if ($params && $method == 'POST') {
$requestParams['form_params'] = $params;
} else if ($params && $method == 'GET') {
$query = is_array($params) ? '?'.http_build_query($params) : '';
$url = $this->rajaOngkirBaseUrl . $resource . $query;
}
$response = $client->request($method, $url, $requestParams);
return json_decode($response->getBody(), true);
}
/**
* Get provinces
*
* @return array
*/
protected function getProvinces()
{
$provinceFile = 'provinces.txt';
$provinceFilePath = $this->uploadsFolder. 'files/' . $provinceFile;
$isExistProvinceJson = \Storage::disk('local')->exists($provinceFilePath);
if (!$isExistProvinceJson) {
$response = $this->rajaOngkirRequest('province');
\Storage::disk('local')->put($provinceFilePath, serialize($response['rajaongkir']['results']));
}
$province = unserialize(\Storage::get($provinceFilePath));
$provinces = [];
if (!empty($province)) {
foreach ($province as $province) {
$provinces[$province['province_id']] = strtoupper($province['province']);
}
}
return $provinces;
}
/**
* Get cities by province ID
*
* @param int $provinceId province id
*
* @return array
*/
protected function getCities($provinceId)
{
$cityFile = 'cities_at_'. $provinceId .'.txt';
$cityFilePath = $this->uploadsFolder. 'files/' .$cityFile;
$isExistCitiesJson = \Storage::disk('local')->exists($cityFilePath);
if (!$isExistCitiesJson) {
$response = $this->rajaOngkirRequest('city', ['province' => $provinceId]);
\Storage::disk('local')->put($cityFilePath, serialize($response['rajaongkir']['results']));
}
$cityList = unserialize(\Storage::get($cityFilePath));
$cities = [];
if (!empty($cityList)) {
foreach ($cityList as $city) {
$cities[$city['city_id']] = strtoupper($city['type'].' '.$city['city_name']);
}
}
return $cities;
}
protected function initPaymentGateway()
{
// Set your Merchant Server Key
Config::$serverKey = config('midtrans.serverKey');
// Set to Development/Sandbox Environment (default). Set to true for Production Environment (accept real transaction).
Config::$isProduction = config('midtrans.isProduction');
// Set sanitization on (default)
Config::$isSanitized = config('midtrans.isSanitized');
// Set 3DS transaction for credit card to true
Config::$is3ds = config('midtrans.is3ds');
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use App\Models\Favorite;
use Illuminate\Http\Request;
class FavoriteController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$favorites = Favorite::where('user_id', auth()->id())
->paginate(10);
return view('frontend.favorites.index', compact('favorites'));
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
if(!auth()->check()){
return response('kamu harus login dulu !',200);
}
$request->validate(
[
'product_slug' => 'required',
]
);
$product = Product::where('slug', $request->get('product_slug'))->firstOrFail();
$favorite = Favorite::where('user_id', auth()->id())
->where('product_id', $product->id)
->first();
if ($favorite) {
return response('You have added this product to your favorite before', 422);
}
Favorite::create(
[
'user_id' => auth()->id(),
'product_id' => $product->id,
]
);
return response('The product has been added to your favorite', 200);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Favorite $favorite)
{
$favorite->delete();
return redirect()->back();
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\Product;
use App\Models\Slide;
use Illuminate\Http\Request;
use phpDocumentor\Reflection\Types\Null_;
class HomeController extends Controller
{
/**
* Show the application dashboard.
*
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
$products = Product::latest()->get();
$categories = Category::whereNull('category_id')->take(4)->get();
$slides = Slide::latest()->get();
return view('frontend.homepage', compact('products', 'categories','slides'));
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace App\Http\Controllers;
use App\Models\Obtained;
use Illuminate\Http\Request;
class ObtainedController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param \App\Models\Obtained $obtained
* @return \Illuminate\Http\Response
*/
public function show(Obtained $obtained)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Obtained $obtained
* @return \Illuminate\Http\Response
*/
public function edit(Obtained $obtained)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Obtained $obtained
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Obtained $obtained)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Obtained $obtained
* @return \Illuminate\Http\Response
*/
public function destroy(Obtained $obtained)
{
//
}
}

View File

@ -0,0 +1,432 @@
<?php
namespace App\Http\Controllers;
use Exception;
use Midtrans\Snap;
use App\Models\Order;
use App\Models\Payment;
use App\Models\Product;
use App\Models\Shipment;
use App\Models\OrderItem;
use FontLib\Table\Type\name;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class OrderController extends Controller
{
public function process()
{
if (\Cart::isEmpty()) {
return redirect()->route('cart.index');
}
// \Cart::removeConditionsByType('shipping');
$items = \Cart::getContent();
// $totalWeight = 0;
// foreach ($items as $item) {
// $totalWeight += ($item->quantity * $item->associatedModel->weight);
// }
// $provinces = $this->getProvinces();
// $cities = isset(auth()->user()->city_id) ? $this->getCities(auth()->user()->province_id) : [];
return view('frontend.orders.checkout', compact('items'));
}
public function cities(Request $request)
{
$cities = $this->getCities($request->query('province_id'));
return response()->json(['cities' => $cities]);
}
public function shippingCost(Request $request)
{
$items = \Cart::getContent();
$totalWeight = 0;
foreach ($items as $item) {
$totalWeight += ($item->quantity * $item->associatedModel->weight);
}
$destination = $request->input('city_id');
return $this->getShippingCost($destination, $totalWeight);
}
private function getShippingCost($destination, $weight)
{
$params = [
'origin' => env('RAJAONGKIR_ORIGIN'),
'destination' => $destination,
'weight' => $weight,
];
$results = [];
foreach ($this->couriers as $code => $courier) {
$params['courier'] = $code;
$response = $this->rajaOngkirRequest('cost', $params, 'POST');
if (!empty($response['rajaongkir']['results'])) {
foreach ($response['rajaongkir']['results'] as $cost) {
if (!empty($cost['costs'])) {
foreach ($cost['costs'] as $costDetail) {
$serviceName = strtoupper($cost['code']) . ' - ' . $costDetail['service'];
$costAmount = $costDetail['cost'][0]['value'];
$etd = $costDetail['cost'][0]['etd'];
$result = [
'service' => $serviceName,
'cost' => $costAmount,
'etd' => $etd,
'courier' => $code,
];
$results[] = $result;
}
}
}
}
}
$response = [
'origin' => $params['origin'],
'destination' => $destination,
'weight' => $weight,
'results' => $results,
];
return $response;
}
public function setShipping(Request $request)
{
\Cart::removeConditionsByType('shipping');
$items = \Cart::getContent();
$totalWeight = 0;
foreach ($items as $item) {
$totalWeight += ($item->quantity * $item->associatedModel->weight);
}
$shippingService = $request->get('shipping_service');
$destination = $request->get('city_id');
$shippingOptions = $this->getShippingCost($destination, $totalWeight);
$selectedShipping = null;
if ($shippingOptions['results']) {
foreach ($shippingOptions['results'] as $shippingOption) {
if (str_replace(' ', '', $shippingOption['service']) == $shippingService) {
$selectedShipping = $shippingOption;
break;
}
}
}
$status = null;
$message = null;
$data = [];
if ($selectedShipping) {
$status = 200;
$message = 'Success set shipping cost';
$this->addShippingCostToCart($selectedShipping['service'], $selectedShipping['cost']);
$data['total'] = number_format(\Cart::getTotal());
} else {
$status = 400;
$message = 'Failed to set shipping cost';
}
$response = [
'status' => $status,
'message' => $message
];
if ($data) {
$response['data'] = $data;
}
return $response;
}
private function addShippingCostToCart($serviceName, $cost)
{
$condition = new \Darryldecode\Cart\CartCondition(
[
'name' => $serviceName,
'type' => 'shipping',
'target' => 'total',
'value' => '+' . $cost,
]
);
\Cart::condition($condition);
}
private function getSelectedShipping($destination, $totalWeight, $shippingService)
{
$shippingOptions = $this->getShippingCost($destination, $totalWeight);
$selectedShipping = null;
if ($shippingOptions['results']) {
foreach ($shippingOptions['results'] as $shippingOption) {
if (str_replace(' ', '', $shippingOption['service']) == $shippingService) {
$selectedShipping = $shippingOption;
break;
}
}
}
return $selectedShipping;
}
public function checkout(Request $request)
{
$token = $request->except('_token');
$order = \DB::transaction(function () use ($token) {
// $destination = isset($params['ship_to']) ? $params['shipping_city_id'] : $params['city_id'];
// $items = \Cart::getContent();
// $totalWeight = 0;
// foreach ($items as $item) {
// $totalWeight += ($item->quantity * $item->associatedModel->weight);
// }
// $selectedShipping = $this->getSelectedShipping($destination, $totalWeight, $params['shipping_service']);
$baseTotalPrice = \Cart::getSubTotal();
// $shippingCost = $selectedShipping['cost'];
// $discountAmount = 0;
// $discountPercent = 0;
// $grandTotal = ($baseTotalPrice + $shippingCost) - $discountAmount;
$orderDate = date('Y-m-d H:i:s');
$paymentDue = (new \DateTime($orderDate))->modify('+3 day')->format('Y-m-d H:i:s');
// $user_profile = [
// 'username' => $params['username'],
// 'first_name' => $params['first_name'],
// 'last_name' => $params['last_name'],
// 'address1' => $params['address1'],
// 'address2' => $params['address2'],
// 'province_id' => $params['province_id'],
// 'city_id' => $params['city_id'],
// 'postcode' => $params['postcode'],
// 'phone' => $params['phone'],
// 'email' => $params['email'],
// ];
// auth()->user()->update($user_profile);
$orderParams = [
'user_id' => auth()->id(),
'code' => Order::generateCode(),
'status' => Order::CREATED,
'order_date' => $orderDate,
'payment_due' => $paymentDue,
'payment_status' => Order::UNPAID,
'base_total_price' => $baseTotalPrice,
// 'discount_amount' => $discountAmount,
// 'discount_percent' => $discountPercent,
// 'shipping_cost' => $shippingCost,
// 'grand_total' => $grandTotal,
'customer_first_name' => $token['username'],
// 'customer_last_name' => $params['last_name'],
// 'customer_address1' => $params['address1'],
// 'customer_address2' => $params['address2'],
'customer_phone' => $token['phone'],
// 'customer_email' => $params['email'],
// 'customer_city_id' => $params['city_id'],
// 'customer_province_id' => $params['province_id'],
// 'customer_postcode' => $params['postcode'],
'note' => $token['note'],
// 'shipping_courier' => $selectedShipping['courier'],
// 'shipping_service_name' => $selectedShipping['service'],
];
$order = Order::create($orderParams);
$cartItems = \Cart::getContent();
if ($order && $cartItems) {
foreach ($cartItems as $item) {
$itemDiscountAmount = 0;
$itemDiscountPercent = 0;
$itemBaseTotal = $item->quantity * $item->price;
$itemSubTotal = $itemBaseTotal - $itemDiscountAmount;
$product = $item->associatedModel;
$orderItemParams = [
'order_id' => $order->id,
'product_id' => $item->associatedModel->id,
'qty' => $item->quantity,
'base_price' => $item->price,
'base_total' => $itemBaseTotal,
'discount_amount' => $itemDiscountAmount,
'discount_percent' => $itemDiscountPercent,
'sub_total' => $itemSubTotal,
'name' => $item->name,
'weight' => $item->associatedModel->weight,
];
$orderItem = OrderItem::create($orderItemParams);
if ($orderItem) {
$product = Product::findOrFail($product->id);
$product->quantity -= $item->quantity;
$product->save();
}
}
}
// $shippingFirstName = isset($params['ship_to']) ? $params['shipping_first_name'] : $params['first_name'];
// $shippingLastName = isset($params['ship_to']) ? $params['shipping_last_name'] : $params['last_name'];
// $shippingAddress1 = isset($params['ship_to']) ? $params['shipping_address1'] : $params['address1'];
// $shippingAddress2 = isset($params['ship_to']) ? $params['shipping_address2'] : $params['address2'];
// $shippingPhone = isset($params['ship_to']) ? $params['shipping_phone'] : $params['phone'];
// $shippingEmail = isset($params['ship_to']) ? $params['shipping_email'] : $params['email'];
// $shippingCityId = isset($params['ship_to']) ? $params['shipping_city_id'] : $params['city_id'];
// $shippingProvinceId = isset($params['ship_to']) ? $params['shipping_province_id'] : $params['province_id'];
// $shippingPostcode = isset($params['ship_to']) ? $params['shipping_postcode'] : $params['postcode'];
// $shipmentParams = [
// 'user_id' => auth()->id(),
// 'order_id' => $order->id,
// 'status' => Shipment::PENDING,
// 'total_qty' => \Cart::getTotalQuantity(),
// 'total_weight' => $totalWeight,
// 'first_name' => $shippingFirstName,
// 'last_name' => $shippingLastName,
// 'address1' => $shippingAddress1,
// 'address2' => $shippingAddress2,
// 'phone' => $shippingPhone,
// 'email' => $shippingEmail,
// 'city_id' => $shippingCityId,
// 'province_id' => $shippingProvinceId,
// 'postcode' => $shippingPostcode,
// ];
// Shipment::create($shipmentParams);
return $order;
});
if (!isset($order)) {
return redirect()->back()->with([
'message' => 'something went wrong !',
'alert-type' => 'danger'
]);
// return redirect()->route('checkout.received', $order->id);
}
if ($request['cash'] === "on" && $request['cashless'] === "on") {
return '<script>alert("Choose one payment only!!!");window.location.href="/orders/checkout"</script>';
}
if ($request['cash'] === "on") {
\Cart::clear();
$order->update(['payment_status' => 'cash']);
return view('frontend.orders.cash', compact('order'));
}
// Set your Merchant Server Key
\Midtrans\Config::$serverKey = config('midtrans.serverKey');
// Set to Development/Sandbox Environment (default). Set to true for Production Environment (accept real transaction).
\Midtrans\Config::$isProduction = false;
// Set sanitization on (default)
\Midtrans\Config::$isSanitized = true;
// Set 3DS transaction for credit card to true
\Midtrans\Config::$is3ds = true;
$params = array(
'transaction_details' => array(
'order_id' => Str::random(15),
'gross_amount' => $order->base_total_price,
),
'customer_details' => array(
'name' => $request->username,
'handphone' => $request->phone,
),
);
$snapToken = \Midtrans\Snap::getSnapToken($params);
return view('frontend.orders.confirmation', compact('snapToken', 'order'));
// $this->initPaymentGateway();
// $customerDetails = [
// 'first_name' => $order->customer_first_name,
// 'last_name' => $order->customer_last_name,
// 'email' => $order->customer_email,
// 'phone' => $order->customer_phone,
// ];
// $transaction_details = [
// 'enable_payments' => Payment::PAYMENT_CHANNELS,
// 'transaction_details' => [
// 'order_id' => $order->code,
// 'gross_amount' => $order->grand_total,
// ],
// 'customer_details' => $customerDetails,
// 'expiry' => [
// 'start_time' => date('Y-m-d H:i:s T'),
// 'unit' => Payment::EXPIRY_UNIT,
// 'duration' => Payment::EXPIRY_DURATION,
// ]
// ];
// try {
// $snap = Snap::createTransaction($transaction_details);
// $order->payment_token = $snap->token;
// $order->payment_url = $snap->redirect_url;
// $order->save();
// header('Location: ' . $order->payment_url);
// exit;
// } catch (Exception $e) {
// echo $e->getMessage();
// }
}
public function order_success($orderId)
{
$order = Order::find($orderId);
$order->update(['payment_status' => 'paid']);
\Cart::clear();
return redirect()->route('homepage');
}
public function received($orderId)
{
$order = Order::where('id', $orderId)
->where('user_id', auth()->id())
->firstOrFail();
return view('frontend.orders.received', compact('order'));
}
public function index()
{
$orders = Order::where('user_id', auth()->id())
->paginate(10);
return view('frontend.orders.index', compact('orders'));
}
public function show($id)
{
$order = Order::where('user_id', auth()->id())->findOrFail($id);
return view('frontend.orders.show', compact('order'));
}
}

View File

@ -0,0 +1,137 @@
<?php
namespace App\Http\Controllers;
use App\Models\Order;
use App\Models\Payment;
use Illuminate\Http\Request;
class PaymentController extends Controller
{
public function notification(Request $request){
$payload = $request->getContent();
$notification = json_decode($payload);
$validSignatureKey = hash("sha512", $notification->order_id . $notification->status_code . $notification->gross_amount . 'SB-Mid-server-qfmZPQ6-2OoutunOib_XJpl3');
if ($notification->signature_key != $validSignatureKey) {
return response(['message' => 'Invalid signature'], 403);
}
$this->initPaymentGateway();
$statusCode = null;
$paymentNotification = new \Midtrans\Notification();
$order = Order::where('code', $paymentNotification->order_id)->firstOrFail();
if ($order->isPaid()) {
return response(['message' => 'The order has been paid before'], 422);
}
$transaction = $paymentNotification->transaction_status;
$type = $paymentNotification->payment_type;
$orderId = $paymentNotification->order_id;
$fraud = $paymentNotification->fraud_status;
$vaNumber = null;
$vendorName = null;
if (!empty($paymentNotification->va_numbers[0])) {
$vaNumber = $paymentNotification->va_numbers[0]->va_number;
$vendorName = $paymentNotification->va_numbers[0]->bank;
}
$paymentStatus = null;
if ($transaction == 'capture') {
// For credit card transaction, we need to check whether transaction is challenge by FDS or not
if ($type == 'credit_card') {
if ($fraud == 'challenge') {
// TODO set payment status in merchant's database to 'Challenge by FDS'
// TODO merchant should decide whether this transaction is authorized or not in MAP
$paymentStatus = Payment::CHALLENGE;
} else {
// TODO set payment status in merchant's database to 'Success'
$paymentStatus = Payment::SUCCESS;
}
}
} else if ($transaction == 'settlement') {
// TODO set payment status in merchant's database to 'Settlement'
$paymentStatus = Payment::SETTLEMENT;
} else if ($transaction == 'pending') {
// TODO set payment status in merchant's database to 'Pending'
$paymentStatus = Payment::PENDING;
} else if ($transaction == 'deny') {
// TODO set payment status in merchant's database to 'Denied'
$paymentStatus = PAYMENT::DENY;
} else if ($transaction == 'expire') {
// TODO set payment status in merchant's database to 'expire'
$paymentStatus = PAYMENT::EXPIRE;
} else if ($transaction == 'cancel') {
// TODO set payment status in merchant's database to 'Denied'
$paymentStatus = PAYMENT::CANCEL;
}
$paymentParams = [
'order_id' => $order->id,
'number' => Payment::generateCode(),
'amount' => $paymentNotification->gross_amount,
'method' => 'midtrans',
'status' => $paymentStatus,
'token' => $paymentNotification->transaction_id,
'payloads' => $payload,
'payment_type' => $paymentNotification->payment_type,
'va_number' => $vaNumber,
'vendor_name' => $vendorName,
'biller_code' => $paymentNotification->biller_code,
'bill_key' => $paymentNotification->bill_key,
];
$payment = Payment::create($paymentParams);
if ($paymentStatus && $payment) {
\DB::transaction(
function () use ($order, $payment) {
if (in_array($payment->status, [Payment::SUCCESS, Payment::SETTLEMENT])) {
$order->payment_status = Order::PAID;
$order->status = Order::CONFIRMED;
$order->save();
}
}
);
}
$message = 'Payment status is : '. $paymentStatus;
$response = [
'code' => 200,
'message' => $message,
];
return response($response, 200);
}
public function completed(Request $request){
$code = $request->query('order_id');
$order = Order::where('code', $code)->firstOrFail();
if ($order->payment_status == Order::UNPAID) {
return redirect('payments/failed?order_id='. $code);
}
return view('frontend.payments.success');
}
public function failed(Request $request){
$code = $request->query('order_id');
$order = Order::where('code', $code)->firstOrFail();
return redirect('orders/received/'. $order->id);
}
public function unfinish(Request $request){
$code = $request->query('order_id');
$order = Order::where('code', $code)->firstOrFail();
return redirect('orders/received/'. $order->id);
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function show($slug)
{
$product = Product::with('media', 'category', 'tags')
->where('slug', $slug)
->withCount('media','approvedReviews')
->withAvg('approvedReviews', 'rating')
->active()
->hasQuantity()
->firstOrFail();
$relatedProducts = Product::with('firstMedia')->whereHas('category', function ($query) use ($product) {
$query->whereId($product->category_id);
})
->where('id', '<>', $product->id)
->inRandomOrder()
->active()
->hasQuantity()
->take(4)
->get(['id', 'slug', 'name', 'price']);
return view('frontend.product.show', compact('product', 'relatedProducts'));
}
}

View File

@ -0,0 +1,92 @@
<?php
namespace App\Http\Controllers;
use App\Models\Obtained;
use App\Models\Service;
use App\Models\ServiceCategory;
use App\Models\ServiceObtained;
use Illuminate\Http\Request;
class ServiceController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$serviceCategories = ServiceCategory::get();
return view('frontend.service.index', compact('serviceCategories'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param \App\Models\Service $service
* @return \Illuminate\Http\Response
*/
public function show($serviceCategory)
{
$services = Service::where(['name' => $serviceCategory])->get();
$ser = Service::where(['name' => $serviceCategory])->get()->first();
return view('frontend.service.detail', compact('services', 'ser'));
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Service $service
* @return \Illuminate\Http\Response
*/
public function edit(Service $service)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Service $service
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Service $service)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Service $service
* @return \Illuminate\Http\Response
*/
public function destroy(Service $service)
{
//
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ShopController extends Controller
{
public function index($slug = null)
{
return view('frontend.shop.index', compact('slug'));
}
public function tag($slug)
{
return view('frontend.shop.tag', compact('slug'));
}
public function search(Request $request)
{
$data = Product::select('slug', 'name')
->where('name', 'LIKE', '%'.$request->productName. '%')
->take(5)
->get();
return response()->json($data);
}
}

74
app/Http/Kernel.php Normal file
View File

@ -0,0 +1,74 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Laravel\Passport\Http\Middleware\CheckClientCredentials;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array<int, class-string|string>
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'sessions' => [
\Illuminate\Session\Middleware\StartSession::class,
]
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array<string, class-string|string>
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'isAdmin' => \App\Http\Middleware\AdminMiddleware::class,
'client' => CheckClientCredentials::class,
];
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Http\Livewire\Shop;
use App\Models\Product;
use Livewire\Component;
use App\Models\Category;
use Livewire\WithPagination;
class ProductComponent extends Component
{
use WithPagination;
protected $paginationTheme = 'bootstrap';
public $paginationLimit = 12;
public $slug;
public $sortingBy = 'default';
public function render()
{
switch ($this->sortingBy) {
case 'popularity':
$sortField = 'id';
$sortType = 'desc';
break;
case 'low-high':
$sortField = 'price';
$sortType = 'asc';
break;
case 'high-low':
$sortField = 'price';
$sortType = 'desc';
break;
default:
$sortField = 'id';
$sortType = 'asc';
}
$products = Product::with('firstMedia');
if ($this->slug == '') {
$products = $products;
} else {
$category = Category::whereSlug($this->slug)->first();
if (is_null($category->category_id)) {
$categoriesIds = Category::whereCategoryId($category->id)->pluck('id')->toArray();
$categoriesIds[] = $category->id;
$products = $products->whereHas('category', function ($query) use ($categoriesIds) {
$query->whereIn('id', $categoriesIds);
});
} else {
$products = $products->with('category')
->whereHas('category', function ($query) {
$query->where([
'slug' => $this->slug,
]);
});
}
}
$products = $products
->active()
->orderBy($sortField, $sortType)
->paginate($this->paginationLimit);
return view('livewire.shop.product-component', compact('products'));
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Http\Livewire\Shop;
use App\Models\Product;
use Livewire\Component;
use App\Models\Category;
use Livewire\WithPagination;
class ProductTagComponent extends Component
{
use WithPagination;
protected $paginationTheme = 'bootstrap';
public $paginationLimit = 12;
public $slug;
public $sortingBy = 'default';
public function render()
{
switch ($this->sortingBy) {
case 'popularity':
$sortField = 'id';
$sortType = 'desc';
break;
case 'low-high':
$sortField = 'price';
$sortType = 'asc';
break;
case 'high-low':
$sortField = 'price';
$sortType = 'desc';
break;
default:
$sortField = 'id';
$sortType = 'asc';
}
$products = Product::with('media');
$products = $products->with('tags')->whereHas('tags', function ($query) {
$query->where([
'slug' => $this->slug,
]);
})
->orderBy($sortField, $sortType)
->paginate($this->paginationLimit);
return view('livewire.shop.product-component', compact('products'));
}
}

View File

@ -0,0 +1,110 @@
<?php
namespace App\Http\Livewire\Shop;
use App\Models\Order;
use App\Models\Review;
use Illuminate\Http\Request;
use Livewire\Component;
class SingleProductReviewComponent extends Component
{
public $showForm = true;
public $canRate = false;
public $product;
public $content;
public $rating;
public $checkProduct;
public $currentRatingId;
protected $listeners = [
'update_rating' => 'mount',
];
public function mount()
{
$this->checkProduct = Order::whereHas('orderItems', function ($query) {
$query->where('product_id', $this->product->id);
})->where('user_id', auth()->id())->where('status', Order::COMPLETED)->first();
if ($this->checkProduct) {
$this->canRate = true;
}
if(auth()->user()){
$rating = Review::where('user_id', auth()->id())->where('product_id', $this->product->id)->first();
if (!empty($rating)) {
$this->rating = $rating->rating;
$this->content = $rating->content;
$this->currentRatingId = $rating->id;
}
}
}
public function rules()
{
return [
'rating' => ['required'],
'content' => ['required', 'string']
];
}
public function rate(Request $request)
{
if (!$this->checkProduct){
$this->alert('error', 'You must buy this item first');
return false;
}
$rating = Review::where('user_id', auth()->id())->where('product_id', $this->product->id)->first();
$this->validate();
if (empty($rating)) {
$rating = new Review();
$rating->user_id = auth()->id();
$rating->product_id = $this->product->id;
$rating->rating = $this->rating;
$rating->content = $this->content;
$rating->status = 1;
$rating->save();
} else {
if ($rating->status == 'Inactive'){
$this->alert('error', 'already rating this item');
return false;
}
$rating->user_id = auth()->id();
$rating->product_id = $this->product->id;
$rating->rating = $this->rating;
$rating->content = $this->content;
$rating->ip_address = $request->ip();
$rating->status = 1;
$rating->update();
}
$this->showForm = false;
$this->emit('update_rating');
}
public function delete($id)
{
$rating = Review::where('id', $id)->first();
if ($rating && ($rating->user_id == auth()->id())) {
$rating->delete();
}
if ($this->currentRatingId) {
$this->currentRatingId = '';
$this->rating = '';
$this->content = '';
}
$this->emit('update_rating');
$this->showForm = true;
}
public function render()
{
return view('livewire.shop.single-product-review-component');
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class AdminMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
// Jika Anda tidak menggunakan tabel roles, Anda bisa langsung mengecek apakah pengguna adalah admin berdasarkan kebijakan aplikasi
if (!auth()->user()->isAdmin()) {
return redirect('/');
}
return $next($request);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array<int, string>
*/
protected $except = [
//
];
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
class PreventRequestsDuringMaintenance extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array<int, string>
*/
protected $except = [
//
];
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @param string|null ...$guards
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
}
return $next($request);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array<int, string>
*/
protected $except = [
'current_password',
'password',
'password_confirmation',
];
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustHosts as Middleware;
class TrustHosts extends Middleware
{
/**
* Get the host patterns that should be trusted.
*
* @return array<int, string|null>
*/
public function hosts()
{
return [
$this->allSubdomainsOfApplicationUrl(),
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array<int, string>|string|null
*/
protected $proxies;
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
*/
protected $except = [
'payments/notification'
];
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class CategoryRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
switch ($this->method()) {
case 'POST':
{
return [
'name' => ['required', 'max:255', 'unique:categories'],
'category_id' => ['nullable'],
'cover' => ['nullable','mimes:jpg,jpeg,png,gif', 'max:20000'],
];
}
case 'PUT':
case 'PATCH':
{
return [
'name' => ['required', 'max:255', 'unique:categories,name,'.$this->route()->category->id],
'category_id' => ['nullable'],
'cover' => ['mimes:jpg,jpeg,png,gif', 'max:20000'],
];
}
default: break;
}
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
switch ($this->method()) {
case 'POST':
{
return [
'name' => ['required', 'max:255', 'unique:products'],
'price' => ['required', 'numeric'],
'quantity' => ['required', 'numeric'],
'category_id' => ['required'],
'tags.*' => ['required'],
'status' => ['required'],
'weight' => ['required', 'numeric'],
'description' => ['required', 'max:1000'],
'details' => ['required', 'max:10000'],
'images' => ['required'],
'images.*' => ['mimes:jpg,jpeg,png,gif', 'max:4000']
];
}
case 'PUT':
case 'PATCH':
{
return [
'name' => ['required', 'max:255', 'unique:products,name,'.$this->route()->product->id],
'description' => ['required', 'max:1000'],
'price' => ['required', 'numeric'],
'quantity' => ['required', 'numeric'],
'category_id' => ['required'],
'tags.*' => ['required'],
'details' => ['required', 'max:10000'],
'review_able' => ['nullable'],
'status' => ['required'],
'images' => ['nullable'],
'images.*' => ['mimes:jpg,jpeg,png,gif', 'max:4000']
];
}
default: break;
}
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ReviewRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'status' => ['required'],
];
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class SlideRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
switch ($this->method()) {
case 'POST':
{
return [
'title' => ['required', 'max:255'],
'url' => ['required', 'max:255'],
'body' => ['required', 'max:255'],
'cover' => ['required','mimes:jpg,jpeg,png,gif', 'max:3000']
];
}
case 'PUT':
case 'PATCH':
{
return [
'title' => ['required', 'max:255'],
'url' => ['required', 'max:255'],
'body' => ['required', 'max:255'],
'cover' => ['mimes:jpg,jpeg,png,gif', 'max:3000']
];
}
default: break;
}
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class StoreObtainedRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required'
];
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class StoreRoleRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required',
'permissions.*' => [
'integer',
],
'permissions' => [
'required',
'array',
],
];
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class StoreServiceRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required',
'price' => 'required|numeric',
'obtaineds.*' => [
'integer',
],
'obtaineds' => [
'required',
'array',
],
];
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class StoreUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'username' => ['required'],
'email' => ['required', 'unique:users',],
'roles.*' => ['integer',],
'roles' => ['required', 'array',],
];
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class TagRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
switch ($this->method()) {
case 'POST':
{
return [
'name' => ['required', 'max:255', 'unique:tags'],
];
}
case 'PUT':
case 'PATCH':
{
return [
'name' => ['required', 'max:255', 'unique:tags,name,'.$this->route()->tag->id],
];
}
default: break;
}
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class UpdateObtainedRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required'
];
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class UpdatePermissionRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required'
];
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class UpdateRoleRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required',
'permissions.*' => [
'integer',
],
'permissions' => [
'required',
'array',
],
];
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class UpdateServiceRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required',
'price' => 'required|numeric',
'obtaineds.*' => [
'integer',
],
'obtaineds' => [
'required',
'array',
],
];
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class UpdateUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'username' => [
'required',
],
'email' => [
'required',
'unique:users,email,' . request()->route('user')->id,
],
'roles.*' => [
'integer',
],
'roles' => [
'required',
'array',
],
];
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ProfileRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'username' => ['required',],
'first_name' => ['required'],
'last_name' => ['required'],
'address1' => ['required'],
'address2' => ['required'],
'province_id' => ['required'],
'city_id' => ['required'],
'postcode' => ['required'],
'phone' => ['required'],
'email' => ['required', 'string', 'max:255', 'unique:users,email,' . auth()->id()],
];
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Item extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
$items = [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'quantity' => $this->quantity,
'attributes' => $this->attributes,
'conditions' => $this->conditions,
'product' => new Product($this->associatedModel),
];
return $items;
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ItemResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Product extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
$image = $this->firstMedia ? asset('storage/images/products/' . $this->firstMedia->file_name) : null;
return [
'name' => $this->name,
'slug' => $this->slug,
'price' => $this->price,
'quantity' => $this->quantity,
'description' => $this->description,
'details' => $this->details,
'image' => $image,
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ProductCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

17
app/Models/Booking.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Booking extends Model
{
use HasFactory;
protected $guarded = ['id'];
public function schedule()
{
return $this->belongsTo(Schedule::class);
}
}

42
app/Models/Category.php Normal file
View File

@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Category extends Model
{
use HasFactory,Sluggable;
protected $guarded = ['id', 'created_at', 'updated_at'];
/**
* Return the sluggable configuration array for this model.
*
* @return array
*/
public function sluggable(): array
{
return [
'slug' => [
'source' => 'name',
'onUpdate' => true
]
];
}
public function parent(){
return $this->belongsTo(Category::class, 'category_id');
}
public function children(){
return $this->hasMany(Category::class);
}
public function products()
{
return $this->hasMany(Product::class);
}
}

17
app/Models/Favorite.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Favorite extends Model
{
use HasFactory;
protected $guarded = ['id','created_at','updated_at'];
public function product(){
return $this->belongsTo(Product::class);
}
}

19
app/Models/Media.php Normal file
View File

@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Media extends Model
{
use HasFactory;
protected $guarded = [];
public function mediable(): MorphTo
{
return $this->morphTo();
}
}

13
app/Models/Obtained.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Obtained extends Model
{
use HasFactory;
protected $guarded = ['id'];
}

119
app/Models/Order.php Normal file
View File

@ -0,0 +1,119 @@
<?php
namespace App\Models;
use App\Helpers\General;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Order extends Model
{
use HasFactory;
protected $guarded = ['id', 'created_at', 'updated_at'];
public const ORDERCODE = 'INV';
public const PAID = 'paid';
public const UNPAID = 'unpaid';
public const CREATED = 'created';
public const CONFIRMED = 'confirmed';
public const DELIVERED = 'delivered';
public const COMPLETED = 'completed';
public const CANCELLED = 'cancelled';
public const STATUSES = [
self::CREATED => 'Created',
self::CONFIRMED => 'Confirmed',
self::DELIVERED => 'Delivered',
self::COMPLETED => 'Completed',
self::CANCELLED => 'Cancelled',
];
/**
* Generate order code
*
* @return string
*/
public static function generateCode()
{
$dateCode = self::ORDERCODE . '/' . date('Ymd') . '/' . General::integerToRoman(date('m')). '/' . General::integerToRoman(date('d')). '/';
$lastOrder = self::select([\DB::raw('MAX(orders.code) AS last_code')])
->where('code', 'like', $dateCode . '%')
->first();
$lastOrderCode = !empty($lastOrder) ? $lastOrder['last_code'] : null;
$orderCode = $dateCode . '00001';
if ($lastOrderCode) {
$lastOrderNumber = str_replace($dateCode, '', $lastOrderCode);
$nextOrderNumber = sprintf('%05d', (int)$lastOrderNumber + 1);
$orderCode = $dateCode . $nextOrderNumber;
}
if (self::_isOrderCodeExists($orderCode)) {
return generateOrderCode();
}
return $orderCode;
}
/**
* Check if the generated order code is exists
*
* @param string $orderCode order code
*
* @return void
*/
private static function _isOrderCodeExists($orderCode)
{
return Order::where('code', '=', $orderCode)->exists();
}
public function orderItems()
{
return $this->hasMany(OrderItem::class);
}
public function shipment(){
return $this->hasOne(Shipment::class);
}
public function isPaid()
{
return $this->payment_status == self::PAID;
}
public function isCreated()
{
return $this->status == self::CREATED;
}
public function isConfirmed()
{
return $this->status == self::CONFIRMED;
}
public function isDelivered()
{
return $this->status == self::DELIVERED;
}
public function isCancelled(){
return $this->status == self::CANCELLED ;
}
/**
* Add full_name custom attribute to order object
*
* @return boolean
*/
public function getCustomerFullNameAttribute()
{
return "{$this->customer_first_name} {$this->customer_last_name}";
}
}

23
app/Models/OrderItem.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class OrderItem extends Model
{
use HasFactory;
protected $guarded = ['id', 'created_at', 'updated_at'];
/**
* Define relationship with the Product
*
* @return void
*/
public function product()
{
return $this->belongsTo(Product::class);
}
}

81
app/Models/Payment.php Normal file
View File

@ -0,0 +1,81 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Payment extends Model
{
use HasFactory;
protected $guarded = [];
public const PAYMENT_CHANNELS = ['credit_card', 'mandiri_clickpay', 'cimb_clicks',
'bca_klikbca', 'bca_klikpay', 'bri_epay', 'echannel', 'permata_va',
'bca_va', 'bni_va', 'other_va', 'gopay', 'indomaret',
'danamon_online', 'akulaku'];
public const EXPIRY_DURATION = 1;
public const EXPIRY_UNIT = 'days';
public const CHALLENGE = 'challenge';
public const SUCCESS = 'success';
public const SETTLEMENT = 'settlement';
public const PENDING = 'pending';
public const DENY = 'deny';
public const EXPIRE = 'expire';
public const CANCEL = 'cancel';
public const PAYMENTCODE = 'PAY';
public static function integerToRoman($integer)
{
$integer = intval($integer);
$result = '';
// Create a lookup array that contains all of the Roman numerals.
$lookup = ['M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1];
foreach ($lookup as $roman => $value) {
$matches = intval($integer/$value);
$result .= str_repeat($roman, $matches);
$integer = $integer % $value;
}
return $result;
}
public static function generateCode()
{
$dateCode = self::PAYMENTCODE . '/' . date('Ymd') . '/' . self::integerToRoman(date('m')). '/' . self::integerToRoman(date('d')). '/';
$lastOrder = self::select([\DB::raw('MAX(payments.number) AS last_code')])
->where('number', 'like', $dateCode . '%')
->first();
$lastOrderCode = !empty($lastOrder) ? $lastOrder['last_code'] : null;
$orderCode = $dateCode . '00001';
if ($lastOrderCode) {
$lastOrderNumber = str_replace($dateCode, '', $lastOrderCode);
$nextOrderNumber = sprintf('%05d', (int)$lastOrderNumber + 1);
$orderCode = $dateCode . $nextOrderNumber;
}
if (self::_isOrderCodeExists($orderCode)) {
return generateOrderCode();
}
return $orderCode;
}
private static function _isOrderCodeExists($orderCode)
{
return Order::where('code', '=', $orderCode)->exists();
}
}

86
app/Models/Product.php Normal file
View File

@ -0,0 +1,86 @@
<?php
namespace App\Models;
use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Product extends Model
{
use HasFactory, Sluggable;
protected $guarded = ['id', 'updated_at', 'created_at'];
/**
* Return the sluggable configuration array for this model.
*
* @return array
*/
public function sluggable(): array
{
return [
'slug' => [
'source' => 'name',
'onUpdate' => true
]
];
}
public function getStatusAttribute(): string
{
return $this->attributes['status'] == 0 ? 'Inactive' : 'Active';
}
public function scopeActive($query)
{
return $query->whereStatus(true);
}
public function scopeHasQuantity($query)
{
return $query->where('quantity', '>', 0);
}
public function category(){
return $this->belongsTo(Category::class);
}
public function tags(){
return $this->belongsToMany(Tag::class, 'product_tags');
}
public function media(): MorphMany
{
return $this->morphMany(Media::class, 'mediable');
}
public function firstMedia(): MorphOne
{
return $this->morphOne(Media::class, 'mediable')
->orderBy('file_sort', 'asc');
}
public function reviews()
{
return $this->hasMany(Review::class);
}
public function approvedReviews()
{
return $this->hasMany(Review::class)->whereStatus(1);
}
public function ratings()
{
return $this->hasMany(Rating::class);
}
public function rate()
{
return $this->ratings->isNotEmpty() ? $this->ratings()->sum('value') / $this->ratings()->count() : 0;
}
}

11
app/Models/Rating.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Rating extends Model
{
use HasFactory;
}

27
app/Models/Review.php Normal file
View File

@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
use HasFactory;
protected $guarded = ['id','created_at','updated_at'];
public function getStatusAttribute()
{
return $this->attributes['status'] == 0 ? 'Inactive' : 'Active';
}
public function user(){
return $this->belongsTo(User::class);
}
public function product()
{
return $this->belongsTo(Product::class);
}
}

18
app/Models/Schedule.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Schedule extends Model
{
use HasFactory;
protected $guarded = ['id'];
public function bookings()
{
return $this->hasMany(Booking::class);
}
}

18
app/Models/Service.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Service extends Model
{
use HasFactory;
protected $guarded = ['id'];
public function obtaineds()
{
return $this->belongsToMany(Obtained::class, 'service_obtained');
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ServiceCategory extends Model
{
use HasFactory;
protected $guarded = ['id'];
}

View File

@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ServiceObtained extends Model
{
use HasFactory;
protected $table = 'service_obtained';
protected $guarded = ['id'];
}

26
app/Models/Shipment.php Normal file
View File

@ -0,0 +1,26 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Shipment extends Model
{
use HasFactory;
protected $guarded = ['id', 'created_at', 'updated_at'];
public const PENDING = 'pending';
public const SHIPPED = 'shipped';
/**
* Relationship to the order model
*
* @return void
*/
public function order()
{
return $this->belongsTo(Order::class);
}
}

27
app/Models/Slide.php Normal file
View File

@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Slide extends Model
{
use HasFactory;
protected $guarded = ['id', 'created_at', 'updated_at'];
public function prevSlide()
{
return self::where('position', '<', $this->position)
->orderBy('position', 'DESC')
->first();
}
public function nextSlide()
{
return self::where('position', '>', $this->position)
->orderBy('position', 'ASC')
->first();
}
}

33
app/Models/Tag.php Normal file
View File

@ -0,0 +1,33 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Tag extends Model
{
use HasFactory,Sluggable;
protected $guarded = ['id', 'created_at', 'updated_at'];
/**
* Return the sluggable configuration array for this model.
*
* @return array
*/
public function sluggable(): array
{
return [
'slug' => [
'source' => 'name'
]
];
}
public function products(){
return $this->belongsToMany(Tag::class, 'product_tags');
}
}

56
app/Models/User.php Normal file
View File

@ -0,0 +1,56 @@
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'username',
'email',
'password',
'role', // Add the role attribute here
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Check if the user is an admin.
*
* @return bool
*/
public function isAdmin(): bool
{
return $this->role === 'admin';
}
}

Some files were not shown because too many files have changed in this diff Show More