Compare commits
94 Commits
master
...
feature-pr
| Author | SHA1 | Date |
|---|---|---|
|
|
c6298206d2 | |
|
|
e173b611e3 | |
|
|
c69e9b8407 | |
|
|
00a3db901e | |
|
|
3e7a62be44 | |
|
|
cecc894944 | |
|
|
e12f00cf96 | |
|
|
06ab0f42a5 | |
|
|
0f6dbb95e7 | |
|
|
089308d86c | |
|
|
479eeafaaa | |
|
|
484c2c23c5 | |
|
|
f93d237c79 | |
|
|
3c38abfd6a | |
|
|
06285fc533 | |
|
|
0aec36908b | |
|
|
f78819c9b9 | |
|
|
f2c2cf11ed | |
|
|
8ef3a2783a | |
|
|
a60ca44ca1 | |
|
|
0dfdfb2912 | |
|
|
f24e86061e | |
|
|
f05b7378dc | |
|
|
ca4b0f15d8 | |
|
|
65367bd8dc | |
|
|
aba2dcb939 | |
|
|
459172dc73 | |
|
|
0ca2f2d15a | |
|
|
7e544e2f30 | |
|
|
2ffe527661 | |
|
|
08f79062e9 | |
|
|
5b54da590c | |
|
|
b3630efd2e | |
|
|
7e820e7b45 | |
|
|
e3b9dbea60 | |
|
|
ffdf041acf | |
|
|
a733b90d46 | |
|
|
7baffc9cb5 | |
|
|
87096be7cc | |
|
|
7017d38f12 | |
|
|
91e325b248 | |
|
|
b3f3c2b115 | |
|
|
be7aabbcb3 | |
|
|
d58c8d7ca2 | |
|
|
9ec2918fb4 | |
|
|
e23744e810 | |
|
|
097c9f12ee | |
|
|
f547c6e158 | |
|
|
9288a13e07 | |
|
|
ce5580acd7 | |
|
|
6e546098b7 | |
|
|
835148d78c | |
|
|
8f40ce9ea8 | |
|
|
e56dca452b | |
|
|
f1e0577bef | |
|
|
fa00ee377a | |
|
|
d80b42c297 | |
|
|
d298649398 | |
|
|
9a23e75f5b | |
|
|
156978e669 | |
|
|
8c21d4dc7c | |
|
|
a86ba91db7 | |
|
|
10f3abc047 | |
|
|
a2caec5b74 | |
|
|
b0eda5e389 | |
|
|
b8bc23ee1f | |
|
|
2f293642ea | |
|
|
f8af8541f6 | |
|
|
7c322017da | |
|
|
d21b26a5d2 | |
|
|
9c8ebdfabe | |
|
|
b8c34bf00a | |
|
|
faf6e4df07 | |
|
|
36a763d6c0 | |
|
|
3a66f08579 | |
|
|
3b91c813da | |
|
|
6117a3580a | |
|
|
c7eba16c5f | |
|
|
c71b7ff5c2 | |
|
|
80f6dc8612 | |
|
|
8548016200 | |
|
|
4a32c25337 | |
|
|
e0e853e2b8 | |
|
|
64892821d9 | |
|
|
ddcea440af | |
|
|
695494a2d9 | |
|
|
7173d2c117 | |
|
|
c8c96556c0 | |
|
|
7b38c511ce | |
|
|
2ab0549f02 | |
|
|
a3675b87c9 | |
|
|
496f7a9179 | |
|
|
b00378ba8f | |
|
|
c384576119 |
35
.env.example
35
.env.example
|
|
@ -1,8 +1,9 @@
|
||||||
APP_NAME=Laravel
|
APP_NAME=AsiaGolf
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_URL=http://localhost
|
APP_URL=http://localhost
|
||||||
|
APP_TAGLINE=Tagline
|
||||||
|
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en
|
||||||
APP_FALLBACK_LOCALE=en
|
APP_FALLBACK_LOCALE=en
|
||||||
|
|
@ -20,14 +21,14 @@ LOG_STACK=single
|
||||||
LOG_DEPRECATIONS_CHANNEL=null
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
DB_CONNECTION=sqlite
|
DB_CONNECTION=pgsql
|
||||||
# DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
# DB_PORT=3306
|
DB_PORT=5432
|
||||||
# DB_DATABASE=laravel
|
DB_DATABASE=asiagolf
|
||||||
# DB_USERNAME=root
|
DB_USERNAME=postgres
|
||||||
# DB_PASSWORD=
|
DB_PASSWORD=12345678
|
||||||
|
|
||||||
SESSION_DRIVER=database
|
SESSION_DRIVER=file
|
||||||
SESSION_LIFETIME=120
|
SESSION_LIFETIME=120
|
||||||
SESSION_ENCRYPT=false
|
SESSION_ENCRYPT=false
|
||||||
SESSION_PATH=/
|
SESSION_PATH=/
|
||||||
|
|
@ -37,7 +38,7 @@ BROADCAST_CONNECTION=log
|
||||||
FILESYSTEM_DISK=local
|
FILESYSTEM_DISK=local
|
||||||
QUEUE_CONNECTION=database
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
CACHE_STORE=database
|
CACHE_STORE=file
|
||||||
# CACHE_PREFIX=
|
# CACHE_PREFIX=
|
||||||
|
|
||||||
MEMCACHED_HOST=127.0.0.1
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
@ -63,3 +64,19 @@ AWS_BUCKET=
|
||||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
VITE_APP_NAME="${APP_NAME}"
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
|
||||||
|
WMS_ASSET_URL="https://dev.smgdev.top/api/storage"
|
||||||
|
|
||||||
|
|
||||||
|
BITESHIP_URL=
|
||||||
|
BITESHIP_KEY=
|
||||||
|
BITESHIP_COURIER=grab,gojek,tiki,jnt,anteraja
|
||||||
|
|
||||||
|
|
||||||
|
GOOGLE_CLIENT_ID=1023147148625-3igh5253tr1lkflmbfj76iopvp2n52od.apps.googleusercontent.com
|
||||||
|
GOOGLE_CLIENT_SECRET=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
|
||||||
|
GOOGLE_REDIRECT_URI=http://localhost:8000/login/google/callback
|
||||||
|
|
||||||
|
|
||||||
|
XENDIT_PRIVATE_KEY=
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
8.4
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class AutoNumbering
|
||||||
|
{
|
||||||
|
|
||||||
|
function __construct($params){
|
||||||
|
$this->type = @$params["type"];
|
||||||
|
$this->prefix = @$params["prefix"];
|
||||||
|
$this->location_id = (int) @$params["location_id"];
|
||||||
|
$this->pad = @$params["pad"] ?? 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrent(){
|
||||||
|
|
||||||
|
$numbering = (array) @DB::select("SELECT id, transaction, location_id, prefix, pad, current
|
||||||
|
FROM numbering
|
||||||
|
WHERE transaction = ? AND location_id = ?
|
||||||
|
FOR UPDATE
|
||||||
|
", [$this->type, $this->location_id])[0];
|
||||||
|
|
||||||
|
if ($numbering == null) {
|
||||||
|
$numbering = DB::table("numbering")->insert([
|
||||||
|
"transaction" => $this->type,
|
||||||
|
"location_id" => $this->location_id,
|
||||||
|
"prefix" => $this->prefix,
|
||||||
|
"pad" => $this->pad,
|
||||||
|
"current" => 0
|
||||||
|
]);
|
||||||
|
|
||||||
|
$numbering = (array) DB::select("SELECT id, transaction, location_id, prefix, pad, current
|
||||||
|
FROM numbering
|
||||||
|
WHERE id = ?
|
||||||
|
FOR UPDATE
|
||||||
|
", [DB::getPdo()->lastInsertId()])[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefix_number = $numbering["prefix"];
|
||||||
|
$next_number = $numbering["current"] + 1;
|
||||||
|
$pad_number = $numbering["pad"] - strlen($prefix_number);
|
||||||
|
$number = $prefix_number . str_pad($next_number, $pad_number, 0, STR_PAD_LEFT);
|
||||||
|
|
||||||
|
$this->id = $numbering["id"];
|
||||||
|
|
||||||
|
DB::statement("UPDATE numbering SET current = current+1 WHERE id = ?", [$this->id]);
|
||||||
|
|
||||||
|
return $number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,218 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Province;
|
||||||
|
use App\Models\District;
|
||||||
|
use App\Models\Subdistrict;
|
||||||
|
use App\Models\City;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class AddressController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$addresses = auth()->user()->addresses()->orderBy('is_primary', 'desc')->get();
|
||||||
|
|
||||||
|
// If AJAX request, return JSON
|
||||||
|
if ($request->ajax() || $request->wantsJson()) {
|
||||||
|
$addressesData = $addresses->map(function ($address) {
|
||||||
|
return [
|
||||||
|
'id' => $address->id,
|
||||||
|
'label' => $address->label,
|
||||||
|
'name' => $address->name,
|
||||||
|
'location' => $address->location,
|
||||||
|
'address' => $address->address,
|
||||||
|
'is_primary' => $address->is_primary,
|
||||||
|
'province_id' => $address->province_id,
|
||||||
|
'city_id' => $address->city_id,
|
||||||
|
'district_id' => $address->district_id,
|
||||||
|
'subdistrict_id' => $address->subdistrict_id,
|
||||||
|
'postal_code' => $address->postal_code,
|
||||||
|
'latitude' => $address->latitude,
|
||||||
|
'longitude' => $address->longitude,
|
||||||
|
'phone' => $address->phone,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'addresses' => $addressesData
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For regular page load, return view
|
||||||
|
return view('account.addresses', compact('addresses'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provinces()
|
||||||
|
{
|
||||||
|
$provinces = Province::orderBy('name')->get();
|
||||||
|
|
||||||
|
|
||||||
|
return [
|
||||||
|
'data' => $provinces,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cities($provinceId)
|
||||||
|
{
|
||||||
|
$cities = City::where('province_id', $provinceId)->orderBy('name')->get();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'data' => $cities,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function districts($city_id)
|
||||||
|
{
|
||||||
|
$districts = District::where('city_id', $city_id)->orderBy('name')->get();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'data' => $districts,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function villages($districtId)
|
||||||
|
{
|
||||||
|
$villages = Subdistrict::where('district_id', $districtId)->orderBy('name')->get();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'data' => $villages,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'label' => 'required|string|max:255',
|
||||||
|
'name' => 'required|string|max:255',
|
||||||
|
'phone' => 'required|string|max:255',
|
||||||
|
'province_id' => 'required|exists:provinces,id',
|
||||||
|
'city_id' => 'required|exists:cities,id',
|
||||||
|
'district_id' => 'required|exists:districts,id',
|
||||||
|
'subdistrict_id' => 'required|exists:subdistricts,id',
|
||||||
|
'postal_code' => 'required|string|max:10',
|
||||||
|
'address' => 'required|string|max:255',
|
||||||
|
'latitude' => 'required|numeric|between:-90,90',
|
||||||
|
'longitude' => 'required|numeric|between:-180,180',
|
||||||
|
'is_primary' => 'boolean'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$address = auth()->user()->addresses()->findOrFail($id);
|
||||||
|
|
||||||
|
$address->update([
|
||||||
|
'label' => $request->label,
|
||||||
|
'name' => $request->name,
|
||||||
|
'phone' => $request->phone,
|
||||||
|
'province_id' => $request->province_id,
|
||||||
|
'city_id' => $request->city_id,
|
||||||
|
'district_id' => $request->district_id,
|
||||||
|
'subdistrict_id' => $request->subdistrict_id,
|
||||||
|
'postal_code' => $request->postal_code,
|
||||||
|
'address' => $request->address,
|
||||||
|
'latitude' => $request->latitude,
|
||||||
|
'longitude' => $request->longitude,
|
||||||
|
'is_primary' => $request->is_primary ?? $address->is_primary,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Update location names based on selected IDs
|
||||||
|
$province = Province::find($request->province_id);
|
||||||
|
$city = City::find($request->city_id);
|
||||||
|
$district = District::find($request->district_id);
|
||||||
|
$subdistrict = Subdistrict::find($request->subdistrict_id);
|
||||||
|
|
||||||
|
$address->update([
|
||||||
|
'province_name' => $province?->name,
|
||||||
|
'regency_name' => $city?->name,
|
||||||
|
'district_name' => $district?->name,
|
||||||
|
'village_name' => $subdistrict?->name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// If set as primary, unset other primary addresses
|
||||||
|
if ($request->boolean('is_primary')) {
|
||||||
|
auth()->user()->addresses()
|
||||||
|
->where('id', '!=', $address->id)
|
||||||
|
->update(['is_primary' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => __('addresses.address_updated_successfully'),
|
||||||
|
'address' => $address->fresh()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'label' => 'required|string|max:255',
|
||||||
|
'name' => 'required|string|max:255',
|
||||||
|
'phone' => 'required|string|max:255',
|
||||||
|
'province_id' => 'required|exists:provinces,id',
|
||||||
|
'city_id' => 'required|exists:cities,id',
|
||||||
|
'district_id' => 'required|exists:districts,id',
|
||||||
|
'subdistrict_id' => 'required|exists:subdistricts,id',
|
||||||
|
'address' => 'required|string|max:255',
|
||||||
|
'postal_code' => 'required|string|max:10',
|
||||||
|
'latitude' => 'nullable|numeric|between:-90,90',
|
||||||
|
'longitude' => 'nullable|numeric|between:-180,180',
|
||||||
|
'is_primary' => 'boolean'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Get location names
|
||||||
|
$province = Province::find($request->province_id);
|
||||||
|
$city = City::find($request->city_id);
|
||||||
|
$district = District::find($request->district_id);
|
||||||
|
$subdistrict = Subdistrict::find($request->subdistrict_id);
|
||||||
|
|
||||||
|
$address = auth()->user()->addresses()->create([
|
||||||
|
'label' => $request->label,
|
||||||
|
'name' => $request->name,
|
||||||
|
'phone' => $request->phone,
|
||||||
|
'province_id' => $request->province_id,
|
||||||
|
'city_id' => $request->city_id,
|
||||||
|
'district_id' => $request->district_id,
|
||||||
|
'subdistrict_id' => $request->subdistrict_id,
|
||||||
|
'address' => $request->address,
|
||||||
|
'postal_code' => $request->postal_code,
|
||||||
|
'latitude' => $request->latitude,
|
||||||
|
'longitude' => $request->longitude,
|
||||||
|
'is_primary' => $request->is_primary ?? false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// If set as primary, unset other primary addresses
|
||||||
|
if ($request->boolean('is_primary')) {
|
||||||
|
auth()->user()->addresses()
|
||||||
|
->where('id', '!=', $address->id)
|
||||||
|
->update(['is_primary' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => __('addresses.address_created_successfully'),
|
||||||
|
'address' => $address
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
$address = auth()->user()->addresses()->findOrFail($id);
|
||||||
|
|
||||||
|
// Don't allow deletion if it's the only address
|
||||||
|
if (auth()->user()->addresses()->count() === 1) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('addresses.cannot_delete_only_address')
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$address->delete();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => __('addresses.address_deleted_successfully')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Laravel\Socialite\Facades\Socialite;
|
||||||
|
use App\Repositories\Member\Auth\MemberAuthRepository;
|
||||||
|
|
||||||
|
class GoogleController extends Controller
|
||||||
|
{
|
||||||
|
protected $memberAuthRepository;
|
||||||
|
|
||||||
|
public function __construct(MemberAuthRepository $memberAuthRepository)
|
||||||
|
{
|
||||||
|
$this->memberAuthRepository = $memberAuthRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect the user to the Google authentication page.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function redirectToGoogle()
|
||||||
|
{
|
||||||
|
return Socialite::driver('google')->redirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the user information from Google.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function handleGoogleCallback()
|
||||||
|
{
|
||||||
|
try{
|
||||||
|
$googleUser = Socialite::driver('google')->stateless()->user();
|
||||||
|
// Log::info($googleUser);
|
||||||
|
|
||||||
|
$email = $googleUser->email;
|
||||||
|
$name = $googleUser->name;
|
||||||
|
$google_id = $googleUser->id;
|
||||||
|
$avatar = $googleUser->avatar;
|
||||||
|
|
||||||
|
// $user = User::updateOrCreate(
|
||||||
|
// ['email' => $googleUser->email],
|
||||||
|
// [
|
||||||
|
// 'name' => $googleUser->name,
|
||||||
|
// 'google_id' => $googleUser->id,
|
||||||
|
// 'avatar' => $googleUser->avatar,
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
|
||||||
|
$user = $this->memberAuthRepository->check(['email' => $email]);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
// auto register
|
||||||
|
$user = $this->memberAuthRepository->loginGoogle($name, $email, $avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Auth::login($user, true);
|
||||||
|
|
||||||
|
return redirect()->route('home')->with('info', __('signin.google_coming_soon'));
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Google callback failed: '.$e->getMessage());
|
||||||
|
Log::info($e);
|
||||||
|
|
||||||
|
return redirect()->route('login')->with('error', __('signin.google_failed'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Repositories\Member\Auth\MemberAuthRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class LoginEmailController extends Controller
|
||||||
|
{
|
||||||
|
protected $memberAuthRepository;
|
||||||
|
|
||||||
|
public function __construct(MemberAuthRepository $memberAuthRepository)
|
||||||
|
{
|
||||||
|
$this->memberAuthRepository = $memberAuthRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('account.signin',[
|
||||||
|
'type' => 'email',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function otp(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'identity' => 'required|email',
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
$email = $request->identity;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Find user by email
|
||||||
|
$user = $this->memberAuthRepository->check(['email' => $email]);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('signin.user_not_found'),
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Use MemberAuthRepository to generate OTP
|
||||||
|
$otp = $this->memberAuthRepository->emailOtp(['email' => $email]);
|
||||||
|
|
||||||
|
// TODO: Integrate with WhatsApp API to send OTP
|
||||||
|
// For now, we'll just log it (remove in production)
|
||||||
|
Log::info("OTP for {$email}: {$otp->otp}");
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => __('otp.sent'),
|
||||||
|
'redirect' => route('login-email.otp.view', ['identity' => $email]),
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('OTP generation failed: '.$e->getMessage());
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('otp.generate_failed'),
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Email login failed: ' . $e->getMessage());
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('signin.login_failed')
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function otpView($identity)
|
||||||
|
{
|
||||||
|
return view('account.otp', [
|
||||||
|
'identity' => $identity,
|
||||||
|
'type' => 'email'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verify(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'identity' => 'required|email',
|
||||||
|
'otp' => 'required|string|size:6',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return back()
|
||||||
|
->withErrors($validator)
|
||||||
|
->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
$identity = $request->identity;
|
||||||
|
$otp = $request->otp;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use MemberAuthRepository to verify OTP for email
|
||||||
|
$result = $this->memberAuthRepository->emailOtpConfirm([
|
||||||
|
'email' => $identity,
|
||||||
|
'otp' => $otp,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$check = $this->memberAuthRepository->check(['email' => $identity]);
|
||||||
|
|
||||||
|
$loginData = [
|
||||||
|
'fcm_token' => null,
|
||||||
|
'device' => 'web',
|
||||||
|
];
|
||||||
|
$this->memberAuthRepository->getAuth([
|
||||||
|
'user_id' => $check->id,
|
||||||
|
'device' => 'web',
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
Auth::login($check, true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return redirect()->route('home')->with('success', __('otp.login_success'));
|
||||||
|
|
||||||
|
} catch (\Illuminate\Validation\ValidationException $e) {
|
||||||
|
return back()
|
||||||
|
->withErrors(['otp' => $e->getMessage()])
|
||||||
|
->withInput();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Email OTP verification failed: '.$e->getMessage());
|
||||||
|
|
||||||
|
return back()
|
||||||
|
->withErrors(['otp' => __('otp.verification_failed')])
|
||||||
|
->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Repositories\Member\Auth\MemberAuthRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class LoginWaController extends Controller
|
||||||
|
{
|
||||||
|
protected $memberAuthRepository;
|
||||||
|
|
||||||
|
public function __construct(MemberAuthRepository $memberAuthRepository)
|
||||||
|
{
|
||||||
|
$this->memberAuthRepository = $memberAuthRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('account.signin', [
|
||||||
|
'type' => 'phone',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function otp(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'identity' => 'required|string|min:10|max:15',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('otp.invalid_phone'),
|
||||||
|
'errors' => $validator->errors(),
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$identity = $request->identity;
|
||||||
|
|
||||||
|
// Find or create user by phone number
|
||||||
|
$user = $this->memberAuthRepository->check(['phone' => $identity]);
|
||||||
|
if (! $user) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('otp.user_not_found'),
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Use MemberAuthRepository to generate OTP
|
||||||
|
$otp = $this->memberAuthRepository->waOtp(['phone' => $identity]);
|
||||||
|
|
||||||
|
// TODO: Integrate with WhatsApp API to send OTP
|
||||||
|
// For now, we'll just log it (remove in production)
|
||||||
|
Log::info("OTP for {$identity}: {$otp->otp}");
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => __('otp.sent'),
|
||||||
|
|
||||||
|
'redirect' => route('login-phone.otp.view', ['identity' => $identity]),
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('OTP generation failed: '.$e->getMessage());
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('otp.generate_failed'),
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function otpView($identity)
|
||||||
|
{
|
||||||
|
return view('account.otp', [
|
||||||
|
'identity' => $identity,
|
||||||
|
'type' => 'phone',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verify(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'identity' => 'required|string|min:10|max:15',
|
||||||
|
'otp' => 'required|string|size:6',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return back()
|
||||||
|
->withErrors($validator)
|
||||||
|
->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
$identity = $request->identity;
|
||||||
|
$otp = $request->otp;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use MemberAuthRepository to verify OTP
|
||||||
|
$result = $this->memberAuthRepository->waOtpConfirm([
|
||||||
|
'phone' => $identity,
|
||||||
|
'otp' => $otp,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$check = $this->memberAuthRepository->check(['phone' => $identity]);
|
||||||
|
|
||||||
|
$loginData = [
|
||||||
|
'fcm_token' => null,
|
||||||
|
'device' => 'web',
|
||||||
|
];
|
||||||
|
$this->memberAuthRepository->getAuth([
|
||||||
|
'user_id' => $check->id,
|
||||||
|
'device' => 'web',
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
Auth::login($check, true);
|
||||||
|
|
||||||
|
return redirect()->route('home')->with('success', __('otp.login_success'));
|
||||||
|
|
||||||
|
} catch (\Illuminate\Validation\ValidationException $e) {
|
||||||
|
return back()
|
||||||
|
->withErrors(['otp' => $e->getMessage()])
|
||||||
|
->withInput();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('OTP verification failed: '.$e->getMessage());
|
||||||
|
|
||||||
|
return back()
|
||||||
|
->withErrors(['otp' => __('otp.verification_failed')])
|
||||||
|
->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Helpers\AutoNumbering;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Intervention\Image\Drivers\Imagick\Driver;
|
||||||
|
use Intervention\Image\ImageManager;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
if (! auth()->check()) {
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('account.info');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'name' => 'required|string|max:255',
|
||||||
|
'birth_date' => 'nullable|date',
|
||||||
|
'email' => 'required|email|max:255',
|
||||||
|
'phone' => 'required|string|max:255',
|
||||||
|
'photo' => 'required|image|mimes:jpg,jpeg,png,webp|max:2048',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
$user->name = $request->name;
|
||||||
|
$user->email = $request->email;
|
||||||
|
$user->phone = $request->phone;
|
||||||
|
|
||||||
|
// Handle avatar upload
|
||||||
|
if ($request->hasFile('photo')) {
|
||||||
|
$ext = $request->file('photo')->extension();
|
||||||
|
$filename = $request->file('photo')->storeAs("profile", $user->id.".".$ext, "public");
|
||||||
|
$user->photo = asset('storage/' . $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$customer = $user->customer;
|
||||||
|
if ($user->customer == null) {
|
||||||
|
$customer = new Customer;
|
||||||
|
|
||||||
|
$autoNumbering = new AutoNumbering([
|
||||||
|
'type' => 'CUST',
|
||||||
|
'prefix' => 'CAPP',
|
||||||
|
'location_id' => 0,
|
||||||
|
'pad' => 9,
|
||||||
|
]);
|
||||||
|
do {
|
||||||
|
$number = $autoNumbering->getCurrent();
|
||||||
|
$count = Customer::where('number', $number)->count();
|
||||||
|
} while ($count > 0);
|
||||||
|
|
||||||
|
$customer->number = $number;
|
||||||
|
$customer->user_id = $user->id;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->name){
|
||||||
|
$customer->name = $request->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->email) {
|
||||||
|
$customer->email = $request->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->phone) {
|
||||||
|
$customer->phone = $request->phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->birth_date != null) {
|
||||||
|
$customer->date_of_birth = $request->birth_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
$customer->save();
|
||||||
|
|
||||||
|
return back()->with('success', 'Profile updated successfully!');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error($e);
|
||||||
|
return back()->with('error', $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function updatePassword(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'current_password' => 'required|string',
|
||||||
|
'password' => 'required|string|min:8|confirmed',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
// Verify current password
|
||||||
|
if (!Hash::check($request->current_password, $user->password)) {
|
||||||
|
return back()->with('error', 'Current password is incorrect.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->password = bcrypt($request->password);
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return back()->with('success', 'Password updated successfully!');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return back()->with('error', $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function logout(Request $request)
|
||||||
|
{
|
||||||
|
Auth::logout();
|
||||||
|
$request->session()->invalidate();
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Repositories\Member\Auth\MemberAuthRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class RegisterController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('account.signup');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function register(Request $request, MemberAuthRepository $memberAuthRepository)
|
||||||
|
{
|
||||||
|
$validated = $request->validate([
|
||||||
|
'name' => 'required|string',
|
||||||
|
'referral' => 'nullable|string',
|
||||||
|
'phone' => 'string',
|
||||||
|
'email' => 'nullable|email',
|
||||||
|
'gender' => 'nullable|in:LAKI-LAKI,PEREMPUAN',
|
||||||
|
'date_of_birth' => 'nullable|date'
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$customer = $memberAuthRepository->register($validated);
|
||||||
|
|
||||||
|
$check = $request->all();
|
||||||
|
$check["user_id"] = $customer->user_id;
|
||||||
|
|
||||||
|
$auth = $memberAuthRepository->getAuth($check);
|
||||||
|
|
||||||
|
return redirect('/')->with('success', 'Registration successful!');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::info($e);
|
||||||
|
return redirect()->back()->with('error', $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\Member\Cart\MemberCartRequest;
|
||||||
|
use App\Http\Requests\Member\Cart\UpdateMemberCartRequest;
|
||||||
|
use App\Models\Cart;
|
||||||
|
use App\Repositories\Member\Cart\MemberCartRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class CartController extends Controller
|
||||||
|
{
|
||||||
|
public function count(Request $request, MemberCartRepository $repository)
|
||||||
|
{
|
||||||
|
$count = $repository->getCount($request->input('location_id'));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'count' => $count,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request, MemberCartRepository $repository)
|
||||||
|
{
|
||||||
|
|
||||||
|
$request->merge(['location_id' => $request->input('location_id', session('location_id', 22))]);
|
||||||
|
|
||||||
|
$carts = $repository->getList($request);
|
||||||
|
|
||||||
|
// Log::info($items);
|
||||||
|
return view('checkout.v1-cart',[
|
||||||
|
'carts' => $carts
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add(MemberCartRequest $request, MemberCartRepository $repository)
|
||||||
|
{
|
||||||
|
// Log::info($request->all());
|
||||||
|
$data = $request->validated();
|
||||||
|
$item = $repository->create($data);
|
||||||
|
|
||||||
|
if ($request->expectsJson()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Item added to cart successfully',
|
||||||
|
'item' => $item
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('cart.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($cart_id, UpdateMemberCartRequest $request, MemberCartRepository $repository)
|
||||||
|
{
|
||||||
|
$data = $request->validated();
|
||||||
|
$item = $repository->update($cart_id, $data);
|
||||||
|
|
||||||
|
if ($request->expectsJson()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Cart updated successfully',
|
||||||
|
'item' => $item
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('cart.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($cart_id, MemberCartRepository $repository)
|
||||||
|
{
|
||||||
|
$repository->delete($cart_id);
|
||||||
|
|
||||||
|
if (request()->expectsJson()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Item removed from cart successfully'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('cart.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear(MemberCartRepository $repository)
|
||||||
|
{
|
||||||
|
$repository->clearAll();
|
||||||
|
|
||||||
|
if (request()->expectsJson()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Cart cleared successfully'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('cart.index');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,319 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Address;
|
||||||
|
use App\Models\Location;
|
||||||
|
use App\Repositories\Member\Cart\MemberCartRepository;
|
||||||
|
use App\Repositories\Member\ShippingRepository;
|
||||||
|
use App\Repositories\Member\Transaction\TransactionRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class CheckoutController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request, MemberCartRepository $memberCartRepository)
|
||||||
|
{
|
||||||
|
$request->merge(['location_id' => $request->input('location_id', session('location_id', 22))]);
|
||||||
|
|
||||||
|
$store = Location::find($request->input('location_id'));
|
||||||
|
|
||||||
|
$subtotal = $memberCartRepository->getSubtotal($request->input('location_id'));
|
||||||
|
|
||||||
|
$address_list = Address::where('user_id', auth()->user()->id)->orderBy('is_primary', 'desc')->get();
|
||||||
|
|
||||||
|
$total = $subtotal;
|
||||||
|
|
||||||
|
$carts = $memberCartRepository->getList($request);
|
||||||
|
|
||||||
|
return view('checkout.v1-delivery-1', [
|
||||||
|
'carts' => $carts,
|
||||||
|
'subtotal' => $subtotal,
|
||||||
|
'total' => $total,
|
||||||
|
'store' => $store,
|
||||||
|
'address_list' => $address_list,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexProcess(Request $request)
|
||||||
|
{
|
||||||
|
$delivery_method = $request->input('delivery_method') ?? 'shipping';
|
||||||
|
$address_id = $request->input('address_id');
|
||||||
|
|
||||||
|
if ($address_id == null) {
|
||||||
|
$address_list = Address::where('user_id', $request->user()->id)->orderBy('is_primary', 'desc')->get();
|
||||||
|
$address_id = $address_list->first()->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($delivery_method == null || $address_id == null) {
|
||||||
|
|
||||||
|
return redirect()->back()->with('error', 'Delivery method or address is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($delivery_method == 'shipping') {
|
||||||
|
session(['checkout_delivery_method' => $delivery_method]);
|
||||||
|
session(['checkout_address_id' => $address_id]);
|
||||||
|
|
||||||
|
return redirect()->route('checkout.shipping');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($delivery_method == 'pickup') {
|
||||||
|
session(['checkout_delivery_method' => $delivery_method]);
|
||||||
|
session(['checkout_address_id' => null]);
|
||||||
|
|
||||||
|
return redirect()->route('checkout.payment');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->back()->with('error', 'Delivery method is not valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function chooseShipping(Request $request, MemberCartRepository $memberCartRepository, ShippingRepository $shippingRepository)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$delivery_method = session('checkout_delivery_method');
|
||||||
|
$address_id = session('checkout_address_id');
|
||||||
|
|
||||||
|
$location_id = session('location_id', 22);
|
||||||
|
|
||||||
|
if ($delivery_method == null || $address_id == null || $location_id == null) {
|
||||||
|
|
||||||
|
return redirect()->route('checkout.delivery');
|
||||||
|
}
|
||||||
|
|
||||||
|
$subtotal = $memberCartRepository->getSubtotal($location_id);
|
||||||
|
$total = $subtotal;
|
||||||
|
|
||||||
|
$request->merge(['location_id' => $location_id]);
|
||||||
|
$carts = $memberCartRepository->getList($request);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$shipping_list = collect($shippingRepository->getList([
|
||||||
|
'location_id' => $location_id,
|
||||||
|
'address_id' => $address_id,
|
||||||
|
'items' => $carts,
|
||||||
|
])['pricing'] ?? [])->map(function ($row) {
|
||||||
|
return [
|
||||||
|
'courier' => $row['courier_code'],
|
||||||
|
'service' => $row['courier_service_code'],
|
||||||
|
'title' => $row['courier_name'].' - '.$row['courier_service_name'],
|
||||||
|
'description' => $row['duration'],
|
||||||
|
'cost' => $row['shipping_fee'],
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (count($shipping_list) == 0) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'message' => 'Tidak dapat menghitung ongkir',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
|
||||||
|
// if contain Failed due to invalid or missing postal code
|
||||||
|
if (str_contains($message, 'Failed due to invalid or missing postal code')) {
|
||||||
|
$message = 'Kode pos tidak valid atau tidak ditemukan';
|
||||||
|
} else if (str_contains($message, 'support@biteship.com')) {
|
||||||
|
$message = 'Layanan pengiriman tidak tersedia untuk alamat ini';
|
||||||
|
}
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'message' => $message,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('checkout.v1-delivery-1-shipping', [
|
||||||
|
'carts' => $request->user()->carts,
|
||||||
|
'subtotal' => $subtotal,
|
||||||
|
'total' => $total,
|
||||||
|
'delivery_method' => $delivery_method,
|
||||||
|
'address_id' => $address_id,
|
||||||
|
'address' => Address::find($address_id),
|
||||||
|
'shipping_list' => $shipping_list,
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::info($e);
|
||||||
|
|
||||||
|
return redirect()->route('checkout.delivery')->with('error', $e->getMessage() ?? 'Invalid checkout data');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function chooseShippingProcess(Request $request)
|
||||||
|
{
|
||||||
|
$shipping_option = $request->input('shipping_option');
|
||||||
|
|
||||||
|
// Parse shipping option (format: courier|service|cost)
|
||||||
|
$shipping_data = explode('|', $shipping_option);
|
||||||
|
$courier = $shipping_data[0] ?? '';
|
||||||
|
$service = $shipping_data[1] ?? '';
|
||||||
|
$cost = $shipping_data[2] ?? 0;
|
||||||
|
|
||||||
|
session(['checkout_courier' => $courier]);
|
||||||
|
session(['checkout_service' => $service]);
|
||||||
|
// session(['checkout_shipping_cost' => $cost]);
|
||||||
|
|
||||||
|
return redirect()->route('checkout.payment');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function choosePayment(Request $request, TransactionRepository $repository, MemberCartRepository $memberCartRepository)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
$address_id = session('checkout_address_id');
|
||||||
|
|
||||||
|
$courier = session('checkout_courier');
|
||||||
|
$service = session('checkout_service');
|
||||||
|
|
||||||
|
$location_id = session('location_id', 22);
|
||||||
|
|
||||||
|
$use_point = session('use_point') ?? 0;
|
||||||
|
|
||||||
|
$items = [];
|
||||||
|
|
||||||
|
$request->merge(['location_id' => $location_id]);
|
||||||
|
$carts = $memberCartRepository->getList($request);
|
||||||
|
|
||||||
|
if (count($carts) == 0) {
|
||||||
|
return redirect()->route('checkout.delivery')->with('error', 'No items in cart');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($carts as $cart) {
|
||||||
|
$items[] = [
|
||||||
|
'item_reference_id' => $cart->item_reference_id,
|
||||||
|
'qty' => $cart->qty,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'address_id' => $address_id,
|
||||||
|
'note' => '',
|
||||||
|
'courier_company' => $courier,
|
||||||
|
'courier_type' => $service,
|
||||||
|
'location_id' => $location_id,
|
||||||
|
'items' => $items,
|
||||||
|
'vouchers' => [],
|
||||||
|
'use_customer_points' => $use_point ?? 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
dd($data);
|
||||||
|
|
||||||
|
$item = $repository->create($data);
|
||||||
|
|
||||||
|
$notification = new \App\Notifications\Member\Transaction\OrderWaitPayment($item);
|
||||||
|
$user = auth()->user();
|
||||||
|
$user->notify($notification->delay(now()->addMinutes(1)));
|
||||||
|
|
||||||
|
// return new CheckoutResource($item);
|
||||||
|
|
||||||
|
// proses payment
|
||||||
|
|
||||||
|
$payment = $item->payments()->where('method_type', 'App\Models\XenditLink')
|
||||||
|
->where('status', 'PENDING')
|
||||||
|
->first();
|
||||||
|
$invoice_url = $payment ? @$payment->method->invoice_url : '';
|
||||||
|
|
||||||
|
|
||||||
|
// reset state session
|
||||||
|
session()->forget(['checkout_delivery_method', 'checkout_address_id', 'checkout_courier', 'checkout_service', 'use_point']);
|
||||||
|
|
||||||
|
return redirect()->to($invoice_url)->withHeaders([
|
||||||
|
'Cache-Control' => 'no-cache, no-store, must-revalidate',
|
||||||
|
'Pragma' => 'no-cache',
|
||||||
|
'Expires' => '0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
Log::info($e);
|
||||||
|
|
||||||
|
return redirect()->route('checkout.delivery')->with('error', 'Invalid checkout data');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply points to session
|
||||||
|
*/
|
||||||
|
public function applyPoint(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$usePoint = $request->input('use_point');
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if (!$usePoint || !is_numeric($usePoint) || $usePoint < 0) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Invalid points value'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$usePoint = (int) $usePoint;
|
||||||
|
|
||||||
|
// Get user's available points
|
||||||
|
$userPoints = auth()->user()->customer->point ?? 0;
|
||||||
|
|
||||||
|
// Check if user has enough points
|
||||||
|
if ($usePoint > $userPoints) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'You cannot use more points than available'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set points in session
|
||||||
|
session(['use_point' => $usePoint]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Points applied successfully',
|
||||||
|
'points_applied' => $usePoint,
|
||||||
|
'remaining_points' => $userPoints - $usePoint
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error applying points: ' . $e->getMessage());
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'An error occurred while applying points'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove points from session
|
||||||
|
*/
|
||||||
|
public function removePoint(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Check if points are currently applied
|
||||||
|
$currentPoints = session('use_point', 0);
|
||||||
|
|
||||||
|
if ($currentPoints <= 0) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'No points are currently applied'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove points from session
|
||||||
|
session()->forget('use_point');
|
||||||
|
|
||||||
|
// Get user's available points
|
||||||
|
$userPoints = auth()->user()->customer->point ?? 0;
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Points removed successfully',
|
||||||
|
'points_removed' => $currentPoints,
|
||||||
|
'available_points' => $userPoints
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error removing points: ' . $e->getMessage());
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'An error occurred while removing points'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ComponentController extends Controller
|
||||||
|
{
|
||||||
|
public function load(Request $request, $component)
|
||||||
|
{
|
||||||
|
$template = $request->get('template');
|
||||||
|
|
||||||
|
// Map component names to their blade views
|
||||||
|
$componentMap = [
|
||||||
|
'home-popular-products' => 'components.home.home-popular-products',
|
||||||
|
'product-highlight' => 'components.home.product-highlight',
|
||||||
|
'new-arrivals' => 'components.home.new-arrivals',
|
||||||
|
'brand-home' => 'components.home.brand-home-' . ($template ?? 'fashion-v1'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$view = $componentMap[$component] ?? null;
|
||||||
|
|
||||||
|
if (!$view) {
|
||||||
|
return response()->json(['error' => 'Component not found'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For brand-home component, we need to pass the template parameter
|
||||||
|
if ($component === 'brand-home') {
|
||||||
|
return view($view, ['template' => $template]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view($view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ContactController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
return view('contact.v1');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class HelpController extends Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('help.topics-v2');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class HomeController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public function fashion(Request $request)
|
||||||
|
{
|
||||||
|
return view('home.fashion-v1');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
return view('home.grocery');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
|
class LocaleController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle language switching request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function switch(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$locale = $request->input('locale');
|
||||||
|
|
||||||
|
// Validate locale
|
||||||
|
if (in_array($locale, ['en', 'id'])) {
|
||||||
|
App::setLocale($locale);
|
||||||
|
Session::put('locale', $locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(['success' => true]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
class LocationController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle location selection request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function select(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$locationId = $request->input('location_id');
|
||||||
|
|
||||||
|
// Store location ID in session
|
||||||
|
session(['location_id' => $locationId]);
|
||||||
|
|
||||||
|
return response()->json(['success' => true]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Transaction;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class OrderController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$orders = Transaction::where('user_id', auth()->user()->id)
|
||||||
|
->orderBy('id','desc')
|
||||||
|
->paginate();
|
||||||
|
|
||||||
|
return view('account.orders', compact('orders'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,554 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Gender;
|
||||||
|
use App\Models\StoreCategory;
|
||||||
|
use App\Repositories\Catalog\CategoryRepository;
|
||||||
|
use App\Repositories\Catalog\GenderRepository;
|
||||||
|
use App\Repositories\AnalyticsProductVisitRepository;
|
||||||
|
use App\Repositories\Catalog\ProductRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class ProductController extends Controller
|
||||||
|
{
|
||||||
|
public function genders(Request $request)
|
||||||
|
{
|
||||||
|
$genderRepository = new GenderRepository;
|
||||||
|
$genders = $genderRepository->getList([]);
|
||||||
|
|
||||||
|
// Render gender links HTML
|
||||||
|
$genderHtml = '';
|
||||||
|
$currentGenderId = $request->input('current_gender');
|
||||||
|
|
||||||
|
foreach ($genders as $gender) {
|
||||||
|
$isActive = $currentGenderId == $gender->id;
|
||||||
|
$genderHtml .= '<li class="nav-item mb-1">';
|
||||||
|
$genderHtml .= '<a class="nav-link d-block fw-normal p-0 '.($isActive ? 'active text-primary' : '').'" ';
|
||||||
|
$genderHtml .= 'href="#" data-gender-id="'.$gender->id.'">';
|
||||||
|
$genderHtml .= $gender->name;
|
||||||
|
$genderHtml .= '</a></li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'genders' => $genderHtml,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function categories(Request $request)
|
||||||
|
{
|
||||||
|
$categoryRepository = new CategoryRepository;
|
||||||
|
$categories = $categoryRepository->getList([]);
|
||||||
|
|
||||||
|
// Render category links HTML
|
||||||
|
$categoryHtml = '';
|
||||||
|
$currentCategoryId = $request->input('current_category');
|
||||||
|
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$isActive = $currentCategoryId == $category->id;
|
||||||
|
$categoryHtml .= '<li class="nav-item mb-1">';
|
||||||
|
$categoryHtml .= '<a class="nav-link d-block fw-normal p-0 '.($isActive ? 'active text-primary' : '').'" ';
|
||||||
|
$categoryHtml .= 'href="#" data-category-id="'.$category->id.'">';
|
||||||
|
$categoryHtml .= $category->name;
|
||||||
|
$categoryHtml .= '</a></li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'categories' => $categoryHtml,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ajax(Request $request)
|
||||||
|
{
|
||||||
|
$limit = 20;
|
||||||
|
$page = $request->page ?? 1;
|
||||||
|
|
||||||
|
$search = $request->search;
|
||||||
|
|
||||||
|
$filter = $request->filter ?? [];
|
||||||
|
$sortBy = $request->sort_by ?? 'relevance';
|
||||||
|
|
||||||
|
$price_range_start = $request->price_range_start ?? null;
|
||||||
|
$price_range_end = $request->price_range_end ?? null;
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
$userId = $user ? $user->id : 0;
|
||||||
|
[$location_id, $is_consignment] = Cache::remember('employee_user_'.$userId, 60 * 60 * 24, function () use ($user) {
|
||||||
|
|
||||||
|
if ($user == null) {
|
||||||
|
return [10, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = @$user->employee;
|
||||||
|
$location_id = @$employee->location_id;
|
||||||
|
$location = @$employee->location;
|
||||||
|
$is_consignment = (bool) @$location->is_consignment;
|
||||||
|
|
||||||
|
return [$location_id, $is_consignment];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$productRepository = new ProductRepository;
|
||||||
|
$products = $productRepository->getList([
|
||||||
|
'limit' => $page * $limit,
|
||||||
|
'sort' => $sortBy,
|
||||||
|
'category_id' => $filter['category'] ?? null,
|
||||||
|
'gender_id' => $filter['gender'] ?? null,
|
||||||
|
'brand_id' => $filter['brand'] ?? null,
|
||||||
|
'search' => $search,
|
||||||
|
'location_id' => $location_id,
|
||||||
|
'is_consignment' => $is_consignment,
|
||||||
|
'price_range_start' => $price_range_start,
|
||||||
|
'price_range_end' => $price_range_end,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Check if there are more products
|
||||||
|
$hasMore = count($products) >= $limit;
|
||||||
|
|
||||||
|
// Render product cards HTML
|
||||||
|
$productHtml = '';
|
||||||
|
if (count($products) == 0) {
|
||||||
|
$productHtml = '<div class="col-12">';
|
||||||
|
$productHtml .= 'Pencarian tidak ditemukan';
|
||||||
|
$productHtml .= '</div>';
|
||||||
|
} else {
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$productHtml .= '<div class="col">';
|
||||||
|
$productHtml .= view('components.home.product-card', ['product' => $product])->render();
|
||||||
|
$productHtml .= '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter
|
||||||
|
$filter = $request->filter ?? [];
|
||||||
|
if (isset($filter['category']) && $filter['category']) {
|
||||||
|
$category = StoreCategory::find($filter['category']);
|
||||||
|
|
||||||
|
if ($category) {
|
||||||
|
$filter['category'] = $category->name;
|
||||||
|
} else {
|
||||||
|
unset($filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filter['gender']) && $filter['gender']) {
|
||||||
|
$gender = Gender::find($filter['gender']);
|
||||||
|
|
||||||
|
if ($gender) {
|
||||||
|
$filter['gender'] = $gender->name;
|
||||||
|
} else {
|
||||||
|
unset($filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filter['brand']) && $filter['brand']) {
|
||||||
|
$brand = \App\Models\Brand::find($filter['brand']);
|
||||||
|
|
||||||
|
if ($brand) {
|
||||||
|
$filter['brand'] = $brand->name;
|
||||||
|
} else {
|
||||||
|
unset($filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$filters = $filter;
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'filters' => $filters,
|
||||||
|
'products' => $productHtml,
|
||||||
|
'count' => count($products),
|
||||||
|
'has_more' => $hasMore,
|
||||||
|
'current_page' => $page,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$productRepository = new ProductRepository;
|
||||||
|
$products = [];
|
||||||
|
|
||||||
|
$filters = [];
|
||||||
|
|
||||||
|
$min_max_price = $productRepository->getMinMaxPrice();
|
||||||
|
|
||||||
|
return view('shop.catalog-fashion', [
|
||||||
|
|
||||||
|
'products' => $products,
|
||||||
|
'min_max_price' => $min_max_price,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function brands(Request $request)
|
||||||
|
{
|
||||||
|
$brandRepository = new \App\Repositories\Catalog\BrandRepository;
|
||||||
|
$brands = $brandRepository->getList([]);
|
||||||
|
|
||||||
|
// Render brand links HTML
|
||||||
|
$brandHtml = '';
|
||||||
|
$currentBrandId = $request->input('current_brand');
|
||||||
|
|
||||||
|
foreach ($brands as $brand) {
|
||||||
|
$isActive = $currentBrandId == $brand->id;
|
||||||
|
$brandHtml .= '<li class="nav-item mb-1">';
|
||||||
|
$brandHtml .= '<a class="nav-link d-block fw-normal p-0 '.($isActive ? 'active text-primary' : '').'" ';
|
||||||
|
$brandHtml .= 'href="#" data-brand-id="'.$brand->id.'">';
|
||||||
|
$brandHtml .= $brand->name;
|
||||||
|
$brandHtml .= '</a></li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'brands' => $brandHtml,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function brandsWithImages(Request $request)
|
||||||
|
{
|
||||||
|
$brandRepository = new \App\Repositories\Catalog\BrandRepository;
|
||||||
|
$brands = $brandRepository->getList([]);
|
||||||
|
|
||||||
|
// Render brand links HTML with images as swiper slides
|
||||||
|
$brandHtml = '';
|
||||||
|
$currentBrandId = $request->input('current_brand');
|
||||||
|
|
||||||
|
foreach ($brands as $brand) {
|
||||||
|
$isActive = $currentBrandId == $brand->id;
|
||||||
|
// Only show brands that have images
|
||||||
|
if ($brand->image_url) {
|
||||||
|
$brandHtml .= '<a class="swiper-slide text-body" href="#!" aria-label="'.$brand->name.'" role="group" style="width: 170.2px; margin-right: 20px;">';
|
||||||
|
$brandHtml .= '<img src="'.$brand->image_url.'" alt="'.$brand->name.'" class="me-2" width="100" height="100">';
|
||||||
|
$brandHtml .= '</a>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'brands' => $brandHtml,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function announcements(Request $request)
|
||||||
|
{
|
||||||
|
// Static announcements for now - can be moved to database later
|
||||||
|
$announcements = [
|
||||||
|
// [
|
||||||
|
// 'icon' => '🎉',
|
||||||
|
// 'message' => 'Free Shipping on orders over $250',
|
||||||
|
// 'detail' => "Don't miss a discount!",
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'icon' => 'đź’°',
|
||||||
|
// 'message' => 'Money back guarantee',
|
||||||
|
// 'detail' => 'We return money within 30 days',
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'icon' => 'đź’Ş',
|
||||||
|
// 'message' => 'Friendly 24/7 customer support',
|
||||||
|
// 'detail' => "We've got you covered!",
|
||||||
|
// ],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Render announcement slides HTML
|
||||||
|
$announcementHtml = '';
|
||||||
|
foreach ($announcements as $announcement) {
|
||||||
|
$announcementHtml .= '<div class="swiper-slide text-truncate text-center">';
|
||||||
|
$announcementHtml .= $announcement['icon'].' '.$announcement['message'].' <span class="d-none d-sm-inline">'.$announcement['detail'].'</span>';
|
||||||
|
$announcementHtml .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'announcements' => $announcementHtml,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function highlights(Request $request)
|
||||||
|
{
|
||||||
|
$type = $request->input('type', 'new');
|
||||||
|
$limit = 8;
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
$userId = $user ? $user->id : 0;
|
||||||
|
[$location_id, $is_consignment] = Cache::remember('employee_user_'.$userId, 60 * 60 * 24, function () use ($user) {
|
||||||
|
|
||||||
|
if ($user == null) {
|
||||||
|
return [10, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = @$user->employee;
|
||||||
|
$location_id = @$employee->location_id;
|
||||||
|
$location = @$employee->location;
|
||||||
|
$is_consignment = (bool) @$location->is_consignment;
|
||||||
|
|
||||||
|
return [$location_id, $is_consignment];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$productRepository = new ProductRepository;
|
||||||
|
|
||||||
|
// Set parameters based on type
|
||||||
|
$params = [
|
||||||
|
'limit' => $limit,
|
||||||
|
'location_id' => $location_id,
|
||||||
|
'is_consignment' => $is_consignment,
|
||||||
|
];
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'best_sellers':
|
||||||
|
$params['sort'] = 'random';
|
||||||
|
break;
|
||||||
|
case 'new_arrivals':
|
||||||
|
$params['sort'] = 'new';
|
||||||
|
break;
|
||||||
|
case 'sale_items':
|
||||||
|
$params['event'] = 'special-offer';
|
||||||
|
break;
|
||||||
|
case 'top_rated':
|
||||||
|
$params['sort'] = 'random';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$params['sort'] = 'new';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params['limit'] = 10;
|
||||||
|
|
||||||
|
$products = $productRepository->getList($params);
|
||||||
|
|
||||||
|
// Render product cards HTML
|
||||||
|
$productHtml = '';
|
||||||
|
if (count($products) == 0) {
|
||||||
|
$productHtml = '<div class="col-12 text-center py-4">';
|
||||||
|
$productHtml .= 'No products found';
|
||||||
|
$productHtml .= '</div>';
|
||||||
|
} else {
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$productHtml .= '<div class="col">';
|
||||||
|
$productHtml .= view('components.home.product-card', ['product' => $product])->render();
|
||||||
|
$productHtml .= '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'products' => $productHtml,
|
||||||
|
'count' => count($products),
|
||||||
|
'type' => $type,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function populers(Request $request)
|
||||||
|
{
|
||||||
|
$type = $request->input('type', 'new');
|
||||||
|
$limit = 6;
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
$userId = $user ? $user->id : 0;
|
||||||
|
[$location_id, $is_consignment] = Cache::remember('employee_user_'.$userId, 60 * 60 * 24, function () use ($user) {
|
||||||
|
|
||||||
|
if ($user == null) {
|
||||||
|
return [10, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = @$user->employee;
|
||||||
|
$location_id = @$employee->location_id;
|
||||||
|
$location = @$employee->location;
|
||||||
|
$is_consignment = (bool) @$location->is_consignment;
|
||||||
|
|
||||||
|
return [$location_id, $is_consignment];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$productRepository = new ProductRepository;
|
||||||
|
|
||||||
|
// Set parameters based on type
|
||||||
|
$params = [
|
||||||
|
'limit' => $limit,
|
||||||
|
'location_id' => $location_id,
|
||||||
|
'is_consignment' => $is_consignment,
|
||||||
|
];
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'new':
|
||||||
|
$params['sort'] = 'new';
|
||||||
|
break;
|
||||||
|
case 'best_sellers':
|
||||||
|
$params['sort'] = 'best_sellers';
|
||||||
|
break;
|
||||||
|
case 'special-offer':
|
||||||
|
$params['event'] = 'special-offer';
|
||||||
|
break;
|
||||||
|
case 'top_rated':
|
||||||
|
$params['sort'] = 'random';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$params['sort'] = 'new';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = $productRepository->getList($params);
|
||||||
|
|
||||||
|
// Render product cards HTML
|
||||||
|
$productHtml = '';
|
||||||
|
if (count($products) == 0) {
|
||||||
|
$productHtml = '<div class="col-12 text-center py-4">';
|
||||||
|
$productHtml .= 'No products found';
|
||||||
|
$productHtml .= '</div>';
|
||||||
|
} else {
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$productHtml .= '<div class="col">';
|
||||||
|
$productHtml .= view('components.home.product-card', ['product' => $product])->render();
|
||||||
|
$productHtml .= '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'products' => $productHtml,
|
||||||
|
'count' => count($products),
|
||||||
|
'type' => $type,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function populersJson(Request $request)
|
||||||
|
{
|
||||||
|
$type = $request->input('type', 'new');
|
||||||
|
$limit = 6;
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
$userId = $user ? $user->id : 0;
|
||||||
|
[$location_id, $is_consignment] = Cache::remember('employee_user_'.$userId, 60 * 60 * 24, function () use ($user) {
|
||||||
|
|
||||||
|
if ($user == null) {
|
||||||
|
return [10, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = @$user->employee;
|
||||||
|
$location_id = @$employee->location_id;
|
||||||
|
$location = @$employee->location;
|
||||||
|
$is_consignment = (bool) @$location->is_consignment;
|
||||||
|
|
||||||
|
return [$location_id, $is_consignment];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$productRepository = new ProductRepository;
|
||||||
|
|
||||||
|
// Set parameters based on type
|
||||||
|
$params = [
|
||||||
|
'limit' => $limit,
|
||||||
|
'location_id' => $location_id,
|
||||||
|
'is_consignment' => $is_consignment,
|
||||||
|
];
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'new':
|
||||||
|
$params['sort'] = 'new';
|
||||||
|
break;
|
||||||
|
case 'best_sellers':
|
||||||
|
$params['sort'] = 'best_sellers';
|
||||||
|
break;
|
||||||
|
case 'special-offer':
|
||||||
|
$params['event'] = 'special-offer';
|
||||||
|
break;
|
||||||
|
case 'top_rated':
|
||||||
|
$params['sort'] = 'random';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$params['sort'] = 'new';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params['limit'] = 10;
|
||||||
|
|
||||||
|
$products = $productRepository->getList($params);
|
||||||
|
|
||||||
|
|
||||||
|
$p = $products->map(function($row){
|
||||||
|
$row->image_url = $row->image_url;
|
||||||
|
return $row;
|
||||||
|
});
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'data' =>$p,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track product visit analytics
|
||||||
|
*/
|
||||||
|
private function trackProductVisit(int $productId, Request $request): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$analyticsRepository = new AnalyticsProductVisitRepository();
|
||||||
|
|
||||||
|
$visitData = [
|
||||||
|
'item_id' => $productId,
|
||||||
|
'user_id' => auth()->id(),
|
||||||
|
'session_id' => session()->getId(),
|
||||||
|
'ip_address' => $request->ip(),
|
||||||
|
'user_agent' => $request->userAgent(),
|
||||||
|
'started_at' => now(),
|
||||||
|
'duration_seconds' => 0, // Will be updated when user leaves
|
||||||
|
'device_type' => $this->getDeviceType($request->userAgent()),
|
||||||
|
];
|
||||||
|
|
||||||
|
$analyticsRepository->create($visitData);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// Log error but don't break the application
|
||||||
|
\Log::error('Failed to track product visit: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect device type from user agent
|
||||||
|
*/
|
||||||
|
private function getDeviceType(string $userAgent): string
|
||||||
|
{
|
||||||
|
$userAgent = strtolower($userAgent);
|
||||||
|
|
||||||
|
if (strpos($userAgent, 'mobile') !== false) {
|
||||||
|
return 'Mobile';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($userAgent, 'tablet') !== false) {
|
||||||
|
return 'Tablet';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Desktop';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detailFashion($slug, Request $request, ProductRepository $productRepository)
|
||||||
|
{
|
||||||
|
$product = $productRepository->show($slug);
|
||||||
|
|
||||||
|
// Track product visit analytics
|
||||||
|
$this->trackProductVisit($product->id, $request);
|
||||||
|
|
||||||
|
$complete_look_products_data = $productRepository->getList([
|
||||||
|
'category_id' => $product->category1_id,
|
||||||
|
'limit' => 4,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$complete_look_products = collect($complete_look_products_data->items())->chunk(2);
|
||||||
|
|
||||||
|
$variants = $product->publishedItemVariants ?? [];
|
||||||
|
|
||||||
|
if (count($variants) == 0) {
|
||||||
|
$variants = collect([$product]);
|
||||||
|
}
|
||||||
|
return view('shop.product-fashion', [
|
||||||
|
'product' => $product,
|
||||||
|
'variants' => $variants,
|
||||||
|
'complete_look_products' => $complete_look_products,
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Repositories\Crm\SurveyFeedbackRepository;
|
||||||
|
|
||||||
|
class ReviewController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request, SurveyFeedbackRepository $surveyFeedbackRepository)
|
||||||
|
{
|
||||||
|
|
||||||
|
$list = $surveyFeedbackRepository->getList([]);
|
||||||
|
|
||||||
|
// dd($list);
|
||||||
|
|
||||||
|
return view('account.reviews',[
|
||||||
|
'list' => $list
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Items;
|
||||||
|
use App\Models\StoreCategory;
|
||||||
|
use App\Models\Gender;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class SearchController extends Controller
|
||||||
|
{
|
||||||
|
public function search(Request $request)
|
||||||
|
{
|
||||||
|
$query = $request->get('q');
|
||||||
|
|
||||||
|
if (empty($query) || strlen($query) < 2) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'results' => [],
|
||||||
|
'message' => 'Please enter at least 2 characters'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search products
|
||||||
|
$products = Items::where('is_publish', true)
|
||||||
|
->where('deleted_at', null)
|
||||||
|
->where(function($q) use ($query) {
|
||||||
|
$q->where('name', 'ILIKE', "%{$query}%")
|
||||||
|
->orWhere('number', 'ILIKE', "%{$query}%")
|
||||||
|
->orWhere('description', 'ILIKE', "%{$query}%");
|
||||||
|
})
|
||||||
|
->select('id', 'name', 'number', 'slug')
|
||||||
|
->limit(8)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Search categories
|
||||||
|
$categories = StoreCategory::where('name', 'ILIKE', "%{$query}%")
|
||||||
|
->select('id', 'name')
|
||||||
|
->limit(3)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Search genders
|
||||||
|
$genders = Gender::where('name', 'ILIKE', "%{$query}%")
|
||||||
|
->select('id', 'name')
|
||||||
|
->limit(3)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Format results
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
if ($products->isNotEmpty()) {
|
||||||
|
$results['products'] = $products->map(function($product) {
|
||||||
|
$price = $product->display_price;
|
||||||
|
return [
|
||||||
|
'id' => $product->id,
|
||||||
|
'name' => $product->name,
|
||||||
|
'number' => $product->number,
|
||||||
|
'slug' => $product->slug ?? $product->id,
|
||||||
|
'type' => 'product',
|
||||||
|
'route' => route('product.detail', $product->slug)
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($categories->isNotEmpty()) {
|
||||||
|
$results['categories'] = $categories->map(function($category) {
|
||||||
|
return [
|
||||||
|
'id' => $category->id,
|
||||||
|
'name' => $category->name,
|
||||||
|
'slug' => $category->slug,
|
||||||
|
'type' => 'category',
|
||||||
|
'route' => route('product.index',['filter[category]'=>$category->id])
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($genders->isNotEmpty()) {
|
||||||
|
$results['genders'] = $genders->map(function($gender) {
|
||||||
|
return [
|
||||||
|
'id' => $gender->id,
|
||||||
|
'name' => $gender->name,
|
||||||
|
'slug' => $gender->slug,
|
||||||
|
'type' => 'gender',
|
||||||
|
'route' => route('product.index',['filter[gender]'=>$gender->id])
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'results' => $results,
|
||||||
|
'query' => $query
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class TncController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
return view('terms-and-conditions');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Repositories\Member\VoucherEvent\VoucherEventRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class VoucherEventController extends Controller
|
||||||
|
{
|
||||||
|
protected $voucherEventRepository;
|
||||||
|
|
||||||
|
public function __construct(VoucherEventRepository $voucherEventRepository)
|
||||||
|
{
|
||||||
|
$this->voucherEventRepository = $voucherEventRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redeem a voucher event
|
||||||
|
*
|
||||||
|
* @param int $voucherEvent
|
||||||
|
* @param Request $request
|
||||||
|
* @return JsonResponse
|
||||||
|
*/
|
||||||
|
public function redeem($voucherEvent, Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Get the authenticated user
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'User not authenticated'
|
||||||
|
], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the repository's redeem method
|
||||||
|
$result = $this->voucherEventRepository->redeem($voucherEvent, $user);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => $result['message'] ?? 'Voucher redeemed successfully!',
|
||||||
|
'data' => $result['data'] ?? null
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => $result['message'] ?? 'Failed to redeem voucher'
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error($e);
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Repositories\Member\WishlistRepository;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class WishController extends Controller
|
||||||
|
{
|
||||||
|
protected $wishlistRepository;
|
||||||
|
|
||||||
|
public function __construct(WishlistRepository $wishlistRepository)
|
||||||
|
{
|
||||||
|
$this->wishlistRepository = $wishlistRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the wishlist page
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$wishlists = $this->wishlistRepository->getList($request);
|
||||||
|
|
||||||
|
return view('account.wishlist', [
|
||||||
|
'wishlists' => $wishlists,
|
||||||
|
'user' => Auth::user()
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return redirect()->back()->with('error', 'Failed to load wishlist: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add item to wishlist
|
||||||
|
*/
|
||||||
|
public function store(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'item_id' => 'required|exists:items,id'
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$wishlist = $this->wishlistRepository->create([
|
||||||
|
'item_id' => $request->item_id
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Item added to wishlist successfully',
|
||||||
|
'wishlist' => $wishlist
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Failed to add item to wishlist: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove item from wishlist
|
||||||
|
*/
|
||||||
|
public function destroy(Request $request, $id): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
|
||||||
|
$this->wishlistRepository->delete($id);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Item removed from wishlist successfully'
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Failed to remove item from wishlist: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
|
class SetLocale
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
// Check if locale is in request
|
||||||
|
if ($request->has('locale')) {
|
||||||
|
$locale = $request->get('locale');
|
||||||
|
|
||||||
|
// Validate locale
|
||||||
|
if (in_array($locale, ['en', 'id'])) {
|
||||||
|
App::setLocale($locale);
|
||||||
|
Session::put('locale', $locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if locale is in session
|
||||||
|
elseif (Session::has('locale')) {
|
||||||
|
$locale = Session::get('locale');
|
||||||
|
|
||||||
|
if (in_array($locale, ['en', 'id'])) {
|
||||||
|
App::setLocale($locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default locale to 'id' if not set
|
||||||
|
else {
|
||||||
|
$locale = 'id';
|
||||||
|
App::setLocale($locale);
|
||||||
|
Session::put('locale', $locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Member\Cart;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class MemberCartRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'item_reference_id' => 'required|integer|exists:item_reference,id',
|
||||||
|
'qty' => 'required|numeric|min:0',
|
||||||
|
'location_id' => 'required|numeric',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Member\Cart;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UpdateMemberCartRequest 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 [
|
||||||
|
'qty' => 'required|numeric|min:0'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class CancelRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
$transaction = $this->transaction;
|
||||||
|
$user = auth()->user();
|
||||||
|
$isAdmin = auth()->user()->role->permissions->contains(function($value){
|
||||||
|
return $value->code == "transaction.online";
|
||||||
|
});
|
||||||
|
$isOwner = (@$transaction->customer->user->id == @$user->id) && ($transaction->status == 'WAIT_PAYMENT' || $transaction->status == 'WAIT_PROCESS');
|
||||||
|
return $isAdmin || $isOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'note' => 'nullable|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class CloseRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
$transaction = $this->transaction;
|
||||||
|
$user = auth()->user();
|
||||||
|
$isAdmin = auth()->user()->role->permissions->contains(function($value){
|
||||||
|
return $value->code == "transaction.online";
|
||||||
|
});
|
||||||
|
$isOwner = (@$transaction->customer->user->id == @$user->id) && ($transaction->status == 'WAIT_PAYMENT' || $transaction->status == 'WAIT_PROCESS');
|
||||||
|
return $isAdmin || $isOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'note' => 'nullable|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class DeliverRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
$transaction = $this->transaction;
|
||||||
|
$user = auth()->user();
|
||||||
|
$isAdmin = auth()->user()->role->permissions->contains(function($value){
|
||||||
|
return $value->code == "transaction.online";
|
||||||
|
});
|
||||||
|
return $isAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'note' => 'nullable|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class DetailRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
$transaction = $this->transaction;
|
||||||
|
$user = auth()->user();
|
||||||
|
$isAdmin = auth()->user()->role->permissions->contains(function($value){
|
||||||
|
return $value->code == "transaction.online";
|
||||||
|
});
|
||||||
|
$isOwner = (@$transaction->customer->user->id == @$user->id);
|
||||||
|
return $isAdmin || $isOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'note' => 'nullable|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class ProcessRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
$transaction = $this->transaction;
|
||||||
|
$user = auth()->user();
|
||||||
|
$isAdmin = auth()->user()->role->permissions->contains(function($value){
|
||||||
|
return $value->code == "transaction.online";
|
||||||
|
});
|
||||||
|
return $isAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'note' => 'nullable|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class TransactionRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'address_id' => 'required|integer|exists:address,id',
|
||||||
|
'location_id' => 'required|integer',
|
||||||
|
'courier_company' => 'required|string',
|
||||||
|
'courier_type' => 'required|string',
|
||||||
|
'vouchers' => 'nullable|array',
|
||||||
|
'vouchers.*' => 'required|integer',
|
||||||
|
'items' => 'nullable|array',
|
||||||
|
'items.*.item_reference_id' => 'required|integer',
|
||||||
|
'items.*.qty' => 'required|integer',
|
||||||
|
'use_customer_points' => 'nullable|integer',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Address extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use SoftDeletes;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'address';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'label',
|
||||||
|
'name',
|
||||||
|
'address',
|
||||||
|
'province_id',
|
||||||
|
'city_id',
|
||||||
|
'district_id',
|
||||||
|
'subdistrict_id',
|
||||||
|
'province_name',
|
||||||
|
'city_name',
|
||||||
|
'district_name',
|
||||||
|
'subdistrict_name',
|
||||||
|
'postal_code',
|
||||||
|
'phone',
|
||||||
|
'longitude',
|
||||||
|
'latitude',
|
||||||
|
'user_id',
|
||||||
|
'is_primary'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function province()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Province::class, 'province_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function city()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(City::class, 'city_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function district()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(District::class, 'district_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subdistrict()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Subdistrict::class, 'subdistrict_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getLocationAttribute()
|
||||||
|
{
|
||||||
|
$province = $this->province?->name;
|
||||||
|
$city = $this->city?->name;
|
||||||
|
$district = $this->district?->name;
|
||||||
|
$subdistrict = $this->subdistrict?->name;
|
||||||
|
$postalCode = $this->postal_code;
|
||||||
|
|
||||||
|
return "{$province}, {$city}, {$district}, {$subdistrict}, {$postalCode}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Affiliator extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
|
||||||
|
public static $STATUS_PENDING = 'pending';
|
||||||
|
public static $STATUS_APPROVED = 'approved';
|
||||||
|
public static $STATUS_REJECTED = 'rejected';
|
||||||
|
public static $STATUS_CANCELLED = 'cancelled';
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'code',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'user_id',
|
||||||
|
'bank',
|
||||||
|
'account_name',
|
||||||
|
'account_number',
|
||||||
|
'fee_percentage',
|
||||||
|
'dob',
|
||||||
|
'coaching_status',
|
||||||
|
'coaching_area',
|
||||||
|
'caddy_area',
|
||||||
|
'caddy_los',
|
||||||
|
'trainee_count',
|
||||||
|
'instagram',
|
||||||
|
'youtube',
|
||||||
|
'tiktok',
|
||||||
|
'type',
|
||||||
|
'verified_at',
|
||||||
|
'status'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'dob' => 'date',
|
||||||
|
'verified_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function withdraws()
|
||||||
|
{
|
||||||
|
return $this->hasMany(AffiliatorWithdraw::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function feeLedgers()
|
||||||
|
{
|
||||||
|
return $this->hasMany(AffiliatorFeeLedger::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getBalanceAttribute() : float
|
||||||
|
{
|
||||||
|
return $this->feeLedgers()->sum('amount');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function routeNotificationForEmail()
|
||||||
|
{
|
||||||
|
$email = $this->email;
|
||||||
|
return $email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class AffiliatorFeeLedger extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
|
||||||
|
protected $table = 'affiliator_fee_ledgers';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'affiliator_id',
|
||||||
|
'amount',
|
||||||
|
'status',
|
||||||
|
'time',
|
||||||
|
'transaction_type',
|
||||||
|
'transaction_id'
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'amount' => 'integer',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function affiliator()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Affiliator::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function transaction()
|
||||||
|
{
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getTitleAttribute()
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($this->transaction_type == "App\Models\AffiliatorWithdraw") {
|
||||||
|
return "Penarikan Saldo";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class AffiliatorItem extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $table = 'affiliator_items';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
public $incrementing = true;
|
||||||
|
protected $keyType = 'int';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'item_reference_id',
|
||||||
|
'discount',
|
||||||
|
'fee',
|
||||||
|
'qty',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemReference::class, 'item_reference_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class AffiliatorItemCode extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'affiliator_item_codes';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
public $incrementing = true;
|
||||||
|
protected $keyType = 'int';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'code',
|
||||||
|
'codeable_id',
|
||||||
|
'codeable_type',
|
||||||
|
'affiliator_item_id',
|
||||||
|
'affiliator_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function affiliator()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Affiliator::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function affiliatorItem()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(AffiliatorItem::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function codeable()
|
||||||
|
{
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class AffiliatorWithdraw extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'affiliator_withdraws';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'affiliator_id',
|
||||||
|
'amount',
|
||||||
|
'status',
|
||||||
|
'time',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function affiliator()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Affiliator::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function feeLedger()
|
||||||
|
{
|
||||||
|
return $this->morphOne(AffiliatorFeeLedger::class, 'transaction');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class AnalyticsProductVisit extends Model
|
||||||
|
{
|
||||||
|
protected $connection = 'ecommerce';
|
||||||
|
protected $table = 'analytics_product_visits';
|
||||||
|
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'item_id',
|
||||||
|
'user_id',
|
||||||
|
'session_id',
|
||||||
|
'started_at',
|
||||||
|
'ended_at',
|
||||||
|
'duration_seconds',
|
||||||
|
'ip_address',
|
||||||
|
'device_type',
|
||||||
|
'user_agent',
|
||||||
|
'referrer',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'started_at' => 'datetime',
|
||||||
|
'ended_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
public function calculateDuration(): void
|
||||||
|
{
|
||||||
|
if ($this->started_at && $this->ended_at) {
|
||||||
|
$this->duration_seconds =
|
||||||
|
$this->ended_at->diffInSeconds($this->started_at);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Storage;
|
||||||
|
|
||||||
|
class Banner extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = ["filename","content_id","content_type","caption","is_active"];
|
||||||
|
|
||||||
|
public $appends = ['url'];
|
||||||
|
|
||||||
|
public function getUrlAttribute(){
|
||||||
|
return ($this->filename) ? Storage::disk("public")->url($this->filename): null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Brand extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'brands';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'code',
|
||||||
|
'image',
|
||||||
|
'hide_point',
|
||||||
|
'priority'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function items()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Items::class, 'brand_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImageUrlAttribute()
|
||||||
|
{
|
||||||
|
return $this->image ? Storage::disk('wms')->url($this->image) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getImageDarkUrlAttribute()
|
||||||
|
{
|
||||||
|
return $this->image ? Storage::disk('wms')->url($this->image) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Cart extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['item_id', 'price','is_checked', 'item_variant_id', 'item_reference_id', 'user_id', 'qty','location_id'];
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Items::class,"item_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function itemVariant()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemVariant::class, 'item_variant_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function itemReference()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemReference::class, 'item_reference_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getDisplayPriceAttribute()
|
||||||
|
{
|
||||||
|
return $this->itemReference->item->display_price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Categories extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'categories';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'code',
|
||||||
|
'name',
|
||||||
|
'image',
|
||||||
|
'is_publish'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class City extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['province_id', 'name'];
|
||||||
|
|
||||||
|
public function province()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Province::class, 'province_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Cviebrock\EloquentSluggable\Sluggable;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
|
class Customer extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes, Sluggable, Notifiable;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'customers';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'number',
|
||||||
|
'name',
|
||||||
|
'phone',
|
||||||
|
'email',
|
||||||
|
'address',
|
||||||
|
'country',
|
||||||
|
'province_id',
|
||||||
|
'city_id',
|
||||||
|
'district_id',
|
||||||
|
'village_id',
|
||||||
|
'postal_code',
|
||||||
|
'customer_group_id',
|
||||||
|
'location_id',
|
||||||
|
'referal',
|
||||||
|
'is_active',
|
||||||
|
'verified_at',
|
||||||
|
'user_id',
|
||||||
|
'organization',
|
||||||
|
'prefix',
|
||||||
|
'channel',
|
||||||
|
'creator_id',
|
||||||
|
'gender',
|
||||||
|
'date_of_birth',
|
||||||
|
'profilling_id'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function sluggable(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'number' => [
|
||||||
|
'source' => 'number'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeFilter(Builder $query, array $filters)
|
||||||
|
{
|
||||||
|
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||||
|
return $query
|
||||||
|
->where('name', 'iLIKE', '%' . $search . '%')
|
||||||
|
->orWhere('phone', 'LIKE', '%' . $search . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function locations()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Location::class, 'location_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customerGroup()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(CustomerGroup::class, 'customer_group_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// public function proffiling()
|
||||||
|
// {
|
||||||
|
// return $this->hasMany(FittingOrderCustomer::class);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public function chat()
|
||||||
|
// {
|
||||||
|
// return $this->hasMany(Chat::class);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function profillings()
|
||||||
|
// {
|
||||||
|
// return $this->hasMany(Profilling::class);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function clubMembers()
|
||||||
|
// {
|
||||||
|
// return $this->hasMany(ClubMember::class, 'customer_id', 'id');
|
||||||
|
// }
|
||||||
|
|
||||||
|
public function getPointAttribute()
|
||||||
|
{
|
||||||
|
return $this->hasMany(CustomerPoint::class)->sum("point");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routeNotificationForEmail()
|
||||||
|
{
|
||||||
|
$email = $this->email;
|
||||||
|
return $email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class CustomerGroup extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'customer_groups';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'code',
|
||||||
|
'name'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function scopeFilter(Builder $query, array $filters)
|
||||||
|
{
|
||||||
|
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||||
|
return $query
|
||||||
|
->where('name', 'iLIKE', '%' . $search . '%')
|
||||||
|
->orWhere('code', 'LIKE', '%' . $search . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class CustomerPoint extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"point",
|
||||||
|
"customer_id",
|
||||||
|
"description",
|
||||||
|
"reference_type",
|
||||||
|
"reference_id",
|
||||||
|
"description"
|
||||||
|
];
|
||||||
|
|
||||||
|
public function reference() {
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customer() {
|
||||||
|
return $this->belongsTo(Customer::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Discount extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $fillable = ['name', 'valid_at', 'expired_at', 'customer_group_id', 'discount_percent','location_id', 'type', 'apply_point', 'apply_incentive'];
|
||||||
|
|
||||||
|
public function discountItems() {
|
||||||
|
return $this->hasMany(DiscountItem::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customerGroup() {
|
||||||
|
return $this->belongsTo(CustomerGroup::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function location() {
|
||||||
|
return $this->belongsTo(Location::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DiscountItem extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['item_reference_id', 'price', 'discount_id', 'percent', 'original_price'];
|
||||||
|
|
||||||
|
public function itemReference()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemReference::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function discount()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Discount::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class District extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['city_id', 'name'];
|
||||||
|
|
||||||
|
public function city()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(City::class, 'city_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Gender extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'genders';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = ['name', 'image'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function items()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Items::class, 'gender_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function productCount()
|
||||||
|
{
|
||||||
|
return $this->items()->count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ItemImage extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ["filename", "item_id", "item_reference_id", "item_variant_id", "is_main"];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,204 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Awobaz\Compoships\Compoships;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
|
||||||
|
class ItemReference extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, Compoships;
|
||||||
|
|
||||||
|
protected $table = 'item_reference';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
protected $fillable = ['item_id','item_variant_id','number','unit'];
|
||||||
|
|
||||||
|
public function images()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ItemImage::class, 'item_id', 'item_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Items::class)->with("brand", "gender", "category");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function itemVariant()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemVariant::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function variants()
|
||||||
|
{
|
||||||
|
$model = ItemVariant::where('item_id', $this->item_id)->get();
|
||||||
|
return $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function location()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Location::class, "location_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stocks()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Stock::class, ["item_id", "item_variant_id"], ["item_id", "item_variant_id"])
|
||||||
|
->with("location");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bucketStocks()
|
||||||
|
{
|
||||||
|
return $this->hasMany(BucketStock::class)->with("bucket");
|
||||||
|
// ->where("quantity",">",0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function promotion()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Promotion::class, "promotion_item", "item_id", "promotion_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function price()
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
[$location_id, $is_consignment] = Cache::remember(
|
||||||
|
"employee_user_" . optional($user)->id,
|
||||||
|
60,
|
||||||
|
function () use ($user) {
|
||||||
|
if (!$user) {
|
||||||
|
return [10, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = $user->employee;
|
||||||
|
$location_id = $employee->location_id ?? 10;
|
||||||
|
$location = $employee->location;
|
||||||
|
|
||||||
|
$is_consignment = (bool) optional($location)->is_consignment
|
||||||
|
&& optional($location)->id != 9;
|
||||||
|
|
||||||
|
return [$location_id, $is_consignment];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->hasOne(Discount::class, 'id', 'item_reference_id')
|
||||||
|
->leftJoin('discount_items', 'discount_items.discount_id', '=', 'discounts.id')
|
||||||
|
->where('discounts.type', 'price')
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->where('valid_at', '<=', now())
|
||||||
|
->orWhereNull('valid_at');
|
||||||
|
})
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->where('expired_at', '>', now())
|
||||||
|
->orWhereNull('expired_at');
|
||||||
|
})
|
||||||
|
->where(function ($query) use ($location_id, $is_consignment) {
|
||||||
|
if (!$is_consignment) {
|
||||||
|
$query->whereNull('discounts.location_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($location_id) {
|
||||||
|
$query->orWhere('discounts.location_id', $location_id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->orderByDesc('discounts.created_at')
|
||||||
|
->select([
|
||||||
|
'discount_items.item_reference_id',
|
||||||
|
'discount_items.price',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function discount()
|
||||||
|
{
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
list($location_id, $is_consignment) = Cache::remember("employee_user_".$user->id, 60 * 60 * 24, function(){
|
||||||
|
|
||||||
|
$employee = @$user->employee;
|
||||||
|
$location_id = @$employee->location_id ?? 10;
|
||||||
|
$location = @$employee->location;
|
||||||
|
$is_consignment = (boolean) @$location->is_consignment && $location->id != 9;
|
||||||
|
return [$location_id, $is_consignment];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->hasOne(Discount::class, 'id', 'item_reference_id')
|
||||||
|
->leftJoin("discount_items","discounts.id","=","discount_id")
|
||||||
|
->where("discounts.type","discount")
|
||||||
|
->orderBy("discounts.created_at","desc")
|
||||||
|
->where(function($query){
|
||||||
|
$query->where("valid_at", "<=", Carbon::now())
|
||||||
|
->orWhereNull("valid_at");
|
||||||
|
})
|
||||||
|
->where(function($query){
|
||||||
|
$query->where("expired_at", ">", Carbon::now())
|
||||||
|
->orWhereNull("expired_at");
|
||||||
|
})
|
||||||
|
|
||||||
|
->where(function($query) use ($location_id, $is_consignment){
|
||||||
|
if (!$is_consignment)
|
||||||
|
$query->whereNull("discounts.location_id");
|
||||||
|
if ($location_id)
|
||||||
|
$query->orWhere("discounts.location_id", $location_id);
|
||||||
|
})
|
||||||
|
->select("item_reference_id","price");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function point()
|
||||||
|
{
|
||||||
|
return $this->hasOne(CustomerPointRule::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function promotion3()
|
||||||
|
{
|
||||||
|
$now = Carbon::now()->format('Y-m-d');
|
||||||
|
$promotions = "select DISTINCT ON (item_id) item_id as item_reference_id, name, note from
|
||||||
|
promotions left join promotion_item on promotions.id = promotion_id
|
||||||
|
where (valid_date is null or valid_date::date <= '$now')
|
||||||
|
and (expired_date is null or expired_date::date >= '$now')
|
||||||
|
and type <> 'POINT'";
|
||||||
|
|
||||||
|
$points = "select item_reference_id, array_agg((case when qty is null then '' else (qty || ': ') end) || point || ' Point' order by point asc) as name
|
||||||
|
from customer_point_rules
|
||||||
|
group by item_reference_id";
|
||||||
|
|
||||||
|
return $this->hasOne(ItemReference::class,"id")
|
||||||
|
->select('item_reference.id as item_reference_id',DB::raw("(case when points.name is null then promotions.name else array_to_string(points.name,', ') end) as promotion"),'promotions.note as promotion_note')
|
||||||
|
->leftJoin(DB::raw("(" . $promotions . ") as promotions"), "promotions.item_reference_id", "=", "item_reference.id")
|
||||||
|
->leftJoin(DB::raw("(" . $points . ") as points"), "points.item_reference_id", "=", "item_reference.id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function promotion2()
|
||||||
|
{
|
||||||
|
$now = Carbon::now()->format('Y-m-d');
|
||||||
|
$promotions = "select DISTINCT ON (item_id) item_id, name, note from
|
||||||
|
promotions left join promotion_item on promotions.id = promotion_id
|
||||||
|
where (valid_date is null or valid_date::date <= '$now')
|
||||||
|
and (expired_date is null or expired_date::date >= '$now')
|
||||||
|
and item_id = $this->id
|
||||||
|
and type <> 'POINT'";
|
||||||
|
|
||||||
|
$points = "select item_reference_id, array_agg((case when qty is null then '' else (qty || ': ') end) || point || ' Point' order by point asc) as name
|
||||||
|
from customer_point_rules
|
||||||
|
where item_reference_id = $this->id
|
||||||
|
group by item_reference_id";
|
||||||
|
|
||||||
|
$result = DB::table('item_reference')
|
||||||
|
->select(DB::raw("(case when points.name is null then promotions.name else array_to_string(points.name,', ') end) as promotion"),
|
||||||
|
'promotions.note as promotion_note')
|
||||||
|
->leftJoin(DB::raw("(" . $promotions . ") as promotions"), "promotions.item_id", "=", "item_reference.id")
|
||||||
|
->leftJoin(DB::raw("(" . $points . ") as points"), "points.item_reference_id", "=", "item_reference.id")
|
||||||
|
->where('item_reference.id', $this->id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Awobaz\Compoships\Compoships;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class ItemVariant extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
use Compoships;
|
||||||
|
|
||||||
|
protected $table = 'item_variants';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'code',
|
||||||
|
'description',
|
||||||
|
'item_id',
|
||||||
|
'display_name',
|
||||||
|
'is_publish',
|
||||||
|
'barcode',
|
||||||
|
'variant_name',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function reference()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemReference::class, ["item_id", "id"], ["item_id", "item_variant_id"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function variables()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Variant::class, "variant_value")->select("id", "name", "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function image()
|
||||||
|
{
|
||||||
|
return $this->hasOne(ItemImage::class)->where('item_id', $this->item_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function images()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ItemImage::class)->where('item_id', $this->item_id);
|
||||||
|
}
|
||||||
|
public function variantValue()
|
||||||
|
{
|
||||||
|
return $this->hasMany(\App\Models\VariantValue::class, 'item_variant_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImageUrlAttribute()
|
||||||
|
{
|
||||||
|
$image = $this->images->first()->filename ?? null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (str_contains($image,"http")) {
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $image ? Storage::disk('wms')->url($image) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Items::class, 'item_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayPriceAttribute()
|
||||||
|
{
|
||||||
|
return $this->reference->item->display_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,364 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Awobaz\Compoships\Compoships;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Items extends Model
|
||||||
|
{
|
||||||
|
use Compoships;
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
// protected $with = ['brands', 'categories'];
|
||||||
|
protected $table = 'items';
|
||||||
|
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'number',
|
||||||
|
'name',
|
||||||
|
'brand_id',
|
||||||
|
'category_id',
|
||||||
|
'image',
|
||||||
|
'description',
|
||||||
|
'weight',
|
||||||
|
'is_publish',
|
||||||
|
|
||||||
|
// BC data
|
||||||
|
'type',
|
||||||
|
'unit',
|
||||||
|
'display_unit',
|
||||||
|
'unit_cost',
|
||||||
|
'costing_method',
|
||||||
|
'last_direct_cost',
|
||||||
|
'unit_price',
|
||||||
|
'price_include_vat',
|
||||||
|
'sales_blocked',
|
||||||
|
'purchasing_blocked',
|
||||||
|
'profit_percent',
|
||||||
|
'net_weight',
|
||||||
|
'gross_weight',
|
||||||
|
'unit_volume',
|
||||||
|
'net_price',
|
||||||
|
'ref_id',
|
||||||
|
|
||||||
|
// purchase,
|
||||||
|
'alias_name',
|
||||||
|
'group_type',
|
||||||
|
'model_type',
|
||||||
|
|
||||||
|
'slug',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function scopeFilter(Builder $query, array $filters)
|
||||||
|
{
|
||||||
|
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||||
|
return $query
|
||||||
|
->where('number', 'iLIKE', '%'.$search.'%')
|
||||||
|
->orWhere('name', 'iLIKE', '%'.$search.'%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function order()
|
||||||
|
{
|
||||||
|
return $this->hasMany(SaleOrderDetail::class, 'item_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dimension()
|
||||||
|
{
|
||||||
|
return $this->hasOne(ItemDimension::class, 'no', 'number');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reference()
|
||||||
|
{
|
||||||
|
return $this->hasOne(ItemReference::class, 'item_id')
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->whereNull('item_variant_id')->orWhere('item_variant_id', 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function variants()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ItemVariant::class, 'item_id')
|
||||||
|
->leftJoin('stocks', 'item_variant_id', '=', 'item_variants.id')
|
||||||
|
->select('item_variants.id', 'item_variants.code', 'item_variants.display_name', 'item_variants.is_publish', DB::raw('SUM(quantity) as stock'), 'description', 'item_variants.item_id')
|
||||||
|
->groupBy('item_variants.id', 'item_variants.code', 'description', 'item_variants.item_id', 'item_variants.display_name', 'item_variants.is_publish');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function images()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ItemImage::class, 'item_id')->whereNull('item_variant_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function itemVariants()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ItemVariant::class, 'item_id')->with('reference');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function publishedItemVariants()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ItemVariant::class, 'item_id')->with('reference')->where('is_publish', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function brands()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Brand::class, 'brand_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function categories()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Categories::class, 'categories_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function brand()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Brand::class, 'brand_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gender()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Gender::class, 'gender_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function category()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Categories::class, 'category_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function discount()
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
[$location_id, $is_consignment] = Cache::remember(
|
||||||
|
'employee_user_'.optional($user)->id,
|
||||||
|
60 * 60 * 24,
|
||||||
|
function () use ($user) {
|
||||||
|
if (! $user) {
|
||||||
|
return [10, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = $user->employee;
|
||||||
|
$location = $employee?->location;
|
||||||
|
|
||||||
|
return [
|
||||||
|
$employee?->location_id,
|
||||||
|
(bool) optional($location)->is_consignment,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// return $this->hasOne(Discount::class,DB::raw("item_reference.item_id"))
|
||||||
|
// ->leftJoin('discount_items', 'discount_items.discount_id', '=', 'discounts.id')
|
||||||
|
// ->leftJoin('item_reference', 'item_reference.id', '=', 'discount_items.item_reference_id')
|
||||||
|
// ->where('discounts.type', 'discount')
|
||||||
|
// ->where(function ($query) {
|
||||||
|
// $query->whereNull('valid_at')
|
||||||
|
// ->orWhere('valid_at', '<=', now());
|
||||||
|
// })
|
||||||
|
// ->where(function ($query) {
|
||||||
|
// $query->whereNull('expired_at')
|
||||||
|
// ->orWhere('expired_at', '>=', now());
|
||||||
|
// })
|
||||||
|
// ->where(function ($query) use ($location_id, $is_consignment) {
|
||||||
|
// if (!$is_consignment) {
|
||||||
|
// $query->whereNull('discounts.location_id');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if ($location_id) {
|
||||||
|
// $query->orWhere('discounts.location_id', $location_id);
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// ->orderByDesc('discounts.created_at')
|
||||||
|
// ->select([
|
||||||
|
// 'item_reference.item_id',
|
||||||
|
// 'discount_items.price',
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
return $this->hasOne(DiscountItem::class, 'item_reference_id', 'id')
|
||||||
|
->leftJoin('discounts', 'discounts.id', '=', 'discount_items.discount_id')
|
||||||
|
->leftJoin('item_reference', 'item_reference.id', '=', 'discount_items.item_reference_id')
|
||||||
|
->where('discounts.type', 'discount')
|
||||||
|
->where(function ($q) {
|
||||||
|
$q->whereNull('discounts.valid_at')
|
||||||
|
->orWhere('discounts.valid_at', '<=', now());
|
||||||
|
})
|
||||||
|
->where(function ($q) {
|
||||||
|
$q->whereNull('discounts.expired_at')
|
||||||
|
->orWhere('discounts.expired_at', '>=', now());
|
||||||
|
})
|
||||||
|
->where(function ($q) use ($location_id, $is_consignment) {
|
||||||
|
if (! $is_consignment) {
|
||||||
|
$q->whereNull('discounts.location_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($location_id) {
|
||||||
|
$q->orWhere('discounts.location_id', $location_id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->orderByDesc('discounts.created_at')
|
||||||
|
->select([
|
||||||
|
'item_reference.item_id',
|
||||||
|
'discount_items.price',
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function price()
|
||||||
|
{
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
$userId = $user ? $user->id : 0;
|
||||||
|
[$location_id, $is_consignment] = Cache::remember('employee_user_'.$userId, 60 * 60 * 24, function () use ($user) {
|
||||||
|
|
||||||
|
if ($user == null) {
|
||||||
|
return [10, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = @$user->employee;
|
||||||
|
$location_id = @$employee->location_id;
|
||||||
|
$location = @$employee->location;
|
||||||
|
$is_consignment = (bool) @$location->is_consignment;
|
||||||
|
|
||||||
|
return [$location_id, $is_consignment];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->hasOne(Discount::class, 'id', 'item_reference_id')
|
||||||
|
->leftJoin('discount_items', 'discount_items.discount_id', '=', 'discounts.id')
|
||||||
|
->where('discounts.type', 'price')
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->where('valid_at', '<=', now())
|
||||||
|
->orWhereNull('valid_at');
|
||||||
|
})
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->where('expired_at', '>', now())
|
||||||
|
->orWhereNull('expired_at');
|
||||||
|
})
|
||||||
|
->where(function ($query) use ($location_id, $is_consignment) {
|
||||||
|
if (! $is_consignment) {
|
||||||
|
$query->whereNull('discounts.location_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($location_id) {
|
||||||
|
$query->orWhere('discounts.location_id', $location_id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->orderByDesc('discounts.created_at')
|
||||||
|
->select([
|
||||||
|
'discount_items.item_reference_id',
|
||||||
|
'discount_items.price',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stock()
|
||||||
|
{
|
||||||
|
return $this->hasOne(Stock::class, 'item_id')
|
||||||
|
->leftJoin('locations', 'locations.id', '=', 'location_id')
|
||||||
|
->whereNotNull('locations.display_name')
|
||||||
|
->where('locations.display_name', '<>', '')
|
||||||
|
->where('quantity', '>', '0')
|
||||||
|
->groupBy('item_id')
|
||||||
|
->select('item_id', DB::raw('SUM(quantity) as quantity'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attributes()
|
||||||
|
{
|
||||||
|
return $this->hasMany(ItemAttribute::class, 'item_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImageUrlAttribute()
|
||||||
|
{
|
||||||
|
$image = $this->images->first()->filename ?? null;
|
||||||
|
|
||||||
|
if (str_contains($image, 'http')) {
|
||||||
|
return $image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $image ? Storage::disk('wms')->url($image) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImageUrlsAttribute()
|
||||||
|
{
|
||||||
|
$images = $this->images ?? [];
|
||||||
|
|
||||||
|
$imgs = [];
|
||||||
|
|
||||||
|
foreach ($images as $img) {
|
||||||
|
$image = $img->filename;
|
||||||
|
|
||||||
|
if (str_contains($image, 'http')) {
|
||||||
|
$imgs[] = $image;
|
||||||
|
} else {
|
||||||
|
$imgs[] = $image ? Storage::disk('wms')->url($image) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $imgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function conversion_value()
|
||||||
|
{
|
||||||
|
$convertion = 1;
|
||||||
|
if (($this->display_unit != $this->unit) and ($this->display_unit)) {
|
||||||
|
$convertions = DB::select('select to_qty / from_qty as conv
|
||||||
|
from item_convertions where from_unit = ? and to_unit = ?',
|
||||||
|
[$this->display_unit, $this->unit]);
|
||||||
|
$convertion = max((float) @$convertions[0]->conv, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $convertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayPriceAttribute()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$convertion = $this->conversion_value();
|
||||||
|
|
||||||
|
$price = @$this->variants->first()->reference->price->price ?? null;
|
||||||
|
$price = $price ? $price : $this->net_price;
|
||||||
|
|
||||||
|
return (float) $price * $convertion;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayPriceCurrencyAttribute()
|
||||||
|
{
|
||||||
|
return 'Rp ' . number_format($this->display_price, 0, ',', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayDiscountPriceAttribute()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$convertion = $this->conversion_value();
|
||||||
|
|
||||||
|
$discountPrice = @$this->discount->price ?? 0;
|
||||||
|
|
||||||
|
return (float) $discountPrice * $convertion;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function isWishlist() : bool
|
||||||
|
{
|
||||||
|
return $this->hasOne(Wishlist::class, 'item_id', 'id')->where('customer_id', auth()->user()->customer->id)->exists();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Location extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'locations';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'code',
|
||||||
|
'name',
|
||||||
|
'address',
|
||||||
|
'city',
|
||||||
|
'phone',
|
||||||
|
'longitude',
|
||||||
|
'latitude',
|
||||||
|
'md_id',
|
||||||
|
'display_name',
|
||||||
|
'is_consignment',
|
||||||
|
'postal_code'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function scopeFilter(Builder $query, array $filters)
|
||||||
|
{
|
||||||
|
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||||
|
return $query
|
||||||
|
->where('name', 'iLIKE', '%' . $search . '%')
|
||||||
|
->orWhere('code', 'LIKE', '%' . $search . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function md()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Employee::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function storeCategory()
|
||||||
|
{
|
||||||
|
return $this->hasMany(StoreCapacity::class, "location_id", "id")
|
||||||
|
->selectRaw("
|
||||||
|
store_category.id,
|
||||||
|
store_category.name,
|
||||||
|
store_capacity.max::int,
|
||||||
|
COALESCE(b.qty, 0)::int as qty,
|
||||||
|
COALESCE(b.sku, 0)::int as sku,
|
||||||
|
(CASE WHEN COALESCE(b.qty, 0) = 0 OR store_capacity.max = 0 THEN 0 ELSE (qty / max * 100) END) as percentage
|
||||||
|
")
|
||||||
|
->leftJoin("store_category", "store_capacity.store_category_id", "store_category.id")
|
||||||
|
->leftJoin(DB::raw("(SELECT
|
||||||
|
c.store_category_id,
|
||||||
|
SUM(stocks.quantity) as qty,
|
||||||
|
count(distinct item_reference.number) as sku
|
||||||
|
FROM (SELECT item_dimension.no, store_category_map.store_category_id FROM store_category_map
|
||||||
|
LEFT JOIN item_dimension
|
||||||
|
ON (store_category_map.category1 = item_dimension.category1 OR store_category_map.category1 is null)
|
||||||
|
AND (store_category_map.category2 = item_dimension.category2 OR store_category_map.category2 is null)
|
||||||
|
AND (store_category_map.category3 = item_dimension.category3 OR store_category_map.category3 is null)
|
||||||
|
AND (store_category_map.category4 = item_dimension.category4 OR store_category_map.category4 is null)
|
||||||
|
GROUP BY item_dimension.no, store_category_map.store_category_id
|
||||||
|
) c
|
||||||
|
LEFT JOIN items
|
||||||
|
ON items.number = c.no
|
||||||
|
LEFT JOIN item_reference
|
||||||
|
ON items.id = item_reference.item_id
|
||||||
|
LEFT JOIN stocks
|
||||||
|
ON stocks.item_id = item_reference.item_id AND stocks.item_variant_id = item_reference.item_variant_id
|
||||||
|
WHERE stocks.location_id = $this->id and stocks.quantity > 0
|
||||||
|
GROUP BY c.store_category_id
|
||||||
|
) b"), "store_capacity.store_category_id", "b.store_category_id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class LuckyWheel extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
public function prizes(){
|
||||||
|
return $this->hasMany(LuckyWheelPrize::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gets(){
|
||||||
|
return $this->hasMany(LuckyWheelGet::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tickets(){
|
||||||
|
return $this->hasMany(LuckyWheelTicket::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class LuckyWheelGet extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['prize_id','lucky_wheel_id','voucher_id','nominal','redeem_at'];
|
||||||
|
|
||||||
|
public function prize(){
|
||||||
|
return $this->belongsTo(LuckyWheelPrize::class,'prize_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function voucher(){
|
||||||
|
return $this->belongsTo(Voucher::class,'voucher_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class LuckyWheelPrize extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['name','voucher_event_id'];
|
||||||
|
|
||||||
|
public function voucher(){
|
||||||
|
return $this->belongsTo(Voucher::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function voucherEvent(){
|
||||||
|
return $this->belongsTo(VoucherEvent::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gets(){
|
||||||
|
return $this->hasMany(LuckyWheelGet::class,"prize_id")
|
||||||
|
->whereDate("created_at", Carbon::now());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class LuckyWheelTicket extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['customer_id','invoice_id','max_times'];
|
||||||
|
|
||||||
|
public function luckyWheel()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(LuckyWheel::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customer()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Customer::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prize()
|
||||||
|
{
|
||||||
|
return $this->hasOne(LuckyWheelPrize::class,"ticket_id")->with('voucher');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gets()
|
||||||
|
{
|
||||||
|
return $this->hasMany(LuckyWheelGet::class,"ticket_id")->with("prize","voucher")->orderBy("created_at","desc");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get()
|
||||||
|
{
|
||||||
|
return $this->hasOne(LuckyWheelGet::class,"ticket_id")->whereNotNull("redeem_at")->with("voucher","prize");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PosCode extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'code',
|
||||||
|
'village',
|
||||||
|
'district',
|
||||||
|
'regency',
|
||||||
|
'province',
|
||||||
|
'latitude',
|
||||||
|
'longitude',
|
||||||
|
'elevation',
|
||||||
|
'timezone',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function provinceRef(){
|
||||||
|
return $this->belongsTo(Province::class,"provice_id","id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cityRef(){
|
||||||
|
return $this->belongsTo(City::class,"city_id","id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function districtRef(){
|
||||||
|
return $this->belongsTo(City::class,"district_id","id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function subdistrictRef(){
|
||||||
|
return $this->belongsTo(City::class,"subdistrict_id","id");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class PosInvoice extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $fillable = ["location_id","customer_id","sales_id","sales2_id",
|
||||||
|
"user_id","time","number",
|
||||||
|
"note","subtotal", "voucher", "discount","tax","total",
|
||||||
|
"vouchers","canceled_at","canceled_note","canceled_by", "note_internal"];
|
||||||
|
|
||||||
|
public function ticket()
|
||||||
|
{
|
||||||
|
return $this->hasOne(LuckyWheelTicket::class, 'invoice_id')->with("prize","gets");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customer(){
|
||||||
|
return $this->belongsTo(Customer::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sales(){
|
||||||
|
return $this->belongsTo(Sales::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sales2(){
|
||||||
|
return $this->belongsTo(Sales::class, 'sales2_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function location(){
|
||||||
|
return $this->belongsTo(Location::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(){
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function details(){
|
||||||
|
return $this->hasMany(PosInvoiceDetail::class,"invoice_id")
|
||||||
|
->orderBy("line_no","asc");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function payments(){
|
||||||
|
return $this->hasMany(PosInvoicePayment::class,"invoice_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canceledBy(){
|
||||||
|
return $this->belongsTo(User::class,"canceled_by");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function vouchers(){
|
||||||
|
return $this->morphMany(Voucher::class,'reference_used');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function discountVouchers(){
|
||||||
|
return $this->hasMany(PosInvoiceVoucher::class, 'pos_invoice_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPoint() {
|
||||||
|
$total = CustomerPoint::where('reference_type', 'App\Models\PosInvoice')
|
||||||
|
->where('reference_id', $this->id)
|
||||||
|
->sum('point');
|
||||||
|
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function feedback(){
|
||||||
|
return $this->hasOne(SurveyFeedback::class,"invoice_id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PosInvoiceDetail extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['item_reference_id','point', 'invoice_id', 'item_id','item_variant_id','note','qty','unit_price','unit','reference','discount','vat','total','unit_cost','line_no',
|
||||||
|
'description','item_number','variant_code','invoice_discount', 'line_discount', 'net_price', 'pricelist_discount','serial_number'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function itemReference()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemReference::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Items::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function itemVariant()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemVariant::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoice()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PosInvoice::class, 'invoice_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PosInvoicePayment extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['method', 'amount', 'bank', 'card_number', 'remarks', 'installment', 'bank_id'];
|
||||||
|
|
||||||
|
public function bank_raw()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Bank::class, 'bank_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PosInvoiceVoucher extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'pos_invoice_vouchers';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'pos_invoice_id',
|
||||||
|
'voucher_id',
|
||||||
|
'nominal'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function invoice()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PosInvoice::class, 'pos_invoice_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function voucher()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Voucher::class, 'voucher_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Province extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['name'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Role extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function permissions(){
|
||||||
|
return $this->belongsToMany(Permission::class, "role_permission")
|
||||||
|
->select("id","code","name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function users(){
|
||||||
|
return $this->hasMany(User::class,"role_id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class RolePermission extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'role_permission';
|
||||||
|
protected $primaryKey = null;
|
||||||
|
public $incrementing = false;
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'role_id',
|
||||||
|
'permission_id'
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Cviebrock\EloquentSluggable\Sluggable;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Sales extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes, Sluggable;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'sales';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id',
|
||||||
|
'number',
|
||||||
|
'name',
|
||||||
|
'phone',
|
||||||
|
'email',
|
||||||
|
'address',
|
||||||
|
'country',
|
||||||
|
'province_id',
|
||||||
|
'city_id',
|
||||||
|
'district_id',
|
||||||
|
'village_id',
|
||||||
|
'postal_code',
|
||||||
|
'customer_group_id',
|
||||||
|
'location_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function sluggable(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'number' => [
|
||||||
|
'source' => 'number'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeFilter(Builder $query, array $filters)
|
||||||
|
{
|
||||||
|
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||||
|
return $query
|
||||||
|
->where('name', 'iLIKE', '%' . $search . '%')
|
||||||
|
->orWhere('phone', 'LIKE', '%' . $search . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function locations()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Location::class, 'location_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customerGroup()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(CustomerGroup::class, 'customer_group_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class SerialNumber extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $table = 'sn_batches';
|
||||||
|
|
||||||
|
protected $fillable = ['item_reference_id', 'reference_number', 'item_number', 'variant_code',
|
||||||
|
'description', 'user_id', 'qty','status','closed_at'];
|
||||||
|
|
||||||
|
public function details() {
|
||||||
|
return $this->hasMany(SerialNumberDetail::class, 'sn_batch_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user() {
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class SerialNumberDetail extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'sn_batch_details';
|
||||||
|
|
||||||
|
protected $fillable = ['sn_batch_id', 'number','activated_at','invoice_id','activated_by'];
|
||||||
|
|
||||||
|
public function data(){
|
||||||
|
return $this->belongsTo(SerialNumber::class,"sn_batch_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoice(){
|
||||||
|
return $this->belongsTo(PosInvoice::class,"invoice_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function activatedBy(){
|
||||||
|
return $this->belongsTo(User::class,"activated_by");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class SerialNumberLog extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = ['reference_number','item_number','variant_code','description','brand','activated_at','invoice_no'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class StoreCapacity extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'store_capacity';
|
||||||
|
|
||||||
|
protected $fillable = ['store_category_id', 'location_id', 'max'];
|
||||||
|
|
||||||
|
public function location() {
|
||||||
|
return $this->belongsTo(Location::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class StoreCategory extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'store_category';
|
||||||
|
|
||||||
|
protected $fillable = ['name', 'image'];
|
||||||
|
|
||||||
|
public function categories()
|
||||||
|
{
|
||||||
|
return $this->hasMany(StoreCategoryMap::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function locations()
|
||||||
|
{
|
||||||
|
return $this->hasMany(StoreCapacity::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function items()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Items::class, 'category_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function productCount()
|
||||||
|
{
|
||||||
|
return $this->items()->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getImageUrlAttribute()
|
||||||
|
{
|
||||||
|
return $this->image ? Storage::disk('wms')->url($this->image) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class StoreCategoryMap extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = "store_category_map";
|
||||||
|
|
||||||
|
protected $fillable = ['store_category_id', 'category1', 'category2', 'category3', 'category4'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Subdistrict extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['district_id', 'name'];
|
||||||
|
|
||||||
|
public function district()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(District::class, 'district_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Survey extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $table = 'survey';
|
||||||
|
|
||||||
|
protected $fillable = ['code', 'name', 'title', 'content', 'voucher_event_id'];
|
||||||
|
|
||||||
|
public function detail() {
|
||||||
|
return $this->hasMany(SurveyQuestion::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function voucherEvent() {
|
||||||
|
return $this->belongsTo(VoucherEvent::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class SurveyFeedback extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['code','survey_id', 'channel', 'time', 'customer_id', 'invoice_id', 'ip_address', 'agent'];
|
||||||
|
|
||||||
|
public function detail() {
|
||||||
|
return $this->hasMany(SurveyFeedbackDetail::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function survey() {
|
||||||
|
return $this->belongsTo(Survey::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customer() {
|
||||||
|
return $this->belongsTo(Customer::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoice() {
|
||||||
|
return $this->belongsTo(PosInvoice::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class SurveyFeedbackDetail extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['survey_question_id', 'survey_feedback_id', 'value', 'description'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class SurveyQuestion extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = ['survey_id', 'type', 'data', 'description', 'order'];
|
||||||
|
|
||||||
|
public $timestamps = false;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Transaction extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'number',
|
||||||
|
'user_id',
|
||||||
|
'customer_id',
|
||||||
|
'address_id',
|
||||||
|
'location_id',
|
||||||
|
'time',
|
||||||
|
'note',
|
||||||
|
'amount',
|
||||||
|
'shipping_price',
|
||||||
|
'courier_company',
|
||||||
|
'courier_type',
|
||||||
|
'subtotal',
|
||||||
|
'discount',
|
||||||
|
'point',
|
||||||
|
'status',
|
||||||
|
'waybill_number',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customer()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Customer::class, 'customer_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function address()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Address::class, 'address_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function vouchers()
|
||||||
|
{
|
||||||
|
return $this->morphMany(Voucher::class,'reference_used');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shipping()
|
||||||
|
{
|
||||||
|
return $this->hasOne(TransactionShipping::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function location()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Location::class, 'location_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detailTransaction()
|
||||||
|
{
|
||||||
|
return $this->hasMany(TransactionDetail::class, 'transaction_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function details()
|
||||||
|
{
|
||||||
|
return $this->hasMany(TransactionDetail::class, 'transaction_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function xendits()
|
||||||
|
{
|
||||||
|
return $this->hasMany(TransactionPayment::class, 'transaction_id', 'id')
|
||||||
|
->where("method_type",XenditLink::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function payments()
|
||||||
|
{
|
||||||
|
return $this->hasMany(TransactionPayment::class, 'transaction_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function statuses()
|
||||||
|
{
|
||||||
|
return $this->hasMany(TransactionStatus::class, 'transaction_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoice()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PosInvoice::class, 'invoice_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getStatusTitleAttribute()
|
||||||
|
{
|
||||||
|
return __('order.status.'.strtolower($this->attributes['status']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusColorAttribute()
|
||||||
|
{
|
||||||
|
return match($this->attributes['status']) {
|
||||||
|
'wait_payment' => 'warning',
|
||||||
|
'wait_process' => 'info',
|
||||||
|
'on_process' => 'primary',
|
||||||
|
'on_delivery' => 'success',
|
||||||
|
'closed' => 'success',
|
||||||
|
'cancelled' => 'danger',
|
||||||
|
default => 'secondary',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTotalAttribute()
|
||||||
|
{
|
||||||
|
return $this->attributes['subtotal'] + $this->attributes['shipping_price'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class TransactionDetail extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'transaction_details';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'transaction_id',
|
||||||
|
'item_id',
|
||||||
|
'item_variant_id',
|
||||||
|
'item_reference_id',
|
||||||
|
'qty',
|
||||||
|
'unit',
|
||||||
|
'unit_price',
|
||||||
|
'unit_cost',
|
||||||
|
'point',
|
||||||
|
'discount',
|
||||||
|
'total',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Items::class, 'item_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reference() {
|
||||||
|
return $this->belongsTo(ItemReference::class, 'item_reference_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class TransactionPayment extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'transaction_payments';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'transaction_id',
|
||||||
|
'amount',
|
||||||
|
'status',
|
||||||
|
'method_type',
|
||||||
|
'method_id'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function transaction()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Transaction::class, 'transaction_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function method()
|
||||||
|
{
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class TransactionShipping extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"transaction_id",
|
||||||
|
"uid",
|
||||||
|
"tracking_id",
|
||||||
|
"waybill_id",
|
||||||
|
"company",
|
||||||
|
"type",
|
||||||
|
"driver_name",
|
||||||
|
"driver_phone",
|
||||||
|
"driver_photo_url",
|
||||||
|
"driver_plate_number",
|
||||||
|
"insurance_amount",
|
||||||
|
"insurance_fee",
|
||||||
|
"weight_total",
|
||||||
|
"price",
|
||||||
|
"note",
|
||||||
|
"status",
|
||||||
|
|
||||||
|
"origin_address",
|
||||||
|
"origin_name",
|
||||||
|
"origin_phone",
|
||||||
|
"origin_postal_code",
|
||||||
|
"origin_latitude",
|
||||||
|
"origin_longitude",
|
||||||
|
"origin_note",
|
||||||
|
|
||||||
|
|
||||||
|
"destination_address",
|
||||||
|
"destination_name",
|
||||||
|
"destination_phone",
|
||||||
|
"destination_postal_code",
|
||||||
|
"destination_latitude",
|
||||||
|
"destination_longitude",
|
||||||
|
"destination_note",
|
||||||
|
|
||||||
|
"shipper_name",
|
||||||
|
"shipper_phone",
|
||||||
|
"shipper_email",
|
||||||
|
];
|
||||||
|
|
||||||
|
public function tracks(){
|
||||||
|
return $this->hasMany(TransactionShippingTrack::class,"transaction_shipping_id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class TransactionShippingTrack extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"status",
|
||||||
|
"note",
|
||||||
|
"created_at"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class TransactionStatus extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'transaction_status';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'transaction_id',
|
||||||
|
'user_id',
|
||||||
|
'status',
|
||||||
|
'time',
|
||||||
|
'note',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function transaction()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Transaction::class, 'transaction_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,11 @@ class User extends Authenticatable
|
||||||
'name',
|
'name',
|
||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
|
'role_id',
|
||||||
|
'photo',
|
||||||
|
'fcm_token',
|
||||||
|
'phone',
|
||||||
|
'phone_verified_at',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -45,4 +50,25 @@ class User extends Authenticatable
|
||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function customer()
|
||||||
|
{
|
||||||
|
return $this->hasOne(Customer::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function addresses()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Address::class);
|
||||||
|
}
|
||||||
|
public function primary_address()
|
||||||
|
{
|
||||||
|
return $this->hasOne(Address::class)->where('is_primary', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPhotoUrlAttribute()
|
||||||
|
{
|
||||||
|
return $this->photo ? (str_contains($this->photo, 'http') ? $this->photo : env('WMS_ASSET_URL') . '/' . $this->photo) : asset('img/photo-placeholder.png');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class UserDevice extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['user_id','user_agent','ip_address','last_login_at','device','fcm_token'];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class UserOtp extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'user_otps';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'otp',
|
||||||
|
'expired_at',
|
||||||
|
'user_id',
|
||||||
|
'user_identity',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->hasOne(User::class, 'id', 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function format() : array{
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'otp' => $this->otp,
|
||||||
|
'expired_at' => $this->expired_at,
|
||||||
|
'user_id' => $this->user_id,
|
||||||
|
'user' => $this->user,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
|
use Spatie\Activitylog\LogOptions;
|
||||||
|
|
||||||
|
class Voucher extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
use LogsActivity;
|
||||||
|
|
||||||
|
public function getActivitylogOptions(): LogOptions
|
||||||
|
{
|
||||||
|
return LogOptions::defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $table = 'vouchers';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'number',
|
||||||
|
'nominal',
|
||||||
|
'calculation_type',
|
||||||
|
'description',
|
||||||
|
'customer_id',
|
||||||
|
'expired_at',
|
||||||
|
'voucher_event_id',
|
||||||
|
'affiliator_id',
|
||||||
|
'reference_issued_id',
|
||||||
|
'item_reference_id',
|
||||||
|
'reference_issued_type',
|
||||||
|
'reference_used_id',
|
||||||
|
'reference_used_type',
|
||||||
|
'used_at',
|
||||||
|
'max_nominal',
|
||||||
|
'percent',
|
||||||
|
'min_sales'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function scopeFilter(Builder $query, array $filters)
|
||||||
|
{
|
||||||
|
$query->when($filters['search'] ?? false, function ($query, $search) {
|
||||||
|
return $query
|
||||||
|
->where('number', 'iLIKE', '%' . $search . '%')
|
||||||
|
->orWhere('nominal', 'LIKE', '%' . $search . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function customer() {
|
||||||
|
return $this->belongsTo(Customer::class, 'customer_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function event(){
|
||||||
|
return $this->belongsTo(VoucherEvent::class,"voucher_event_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function location(){
|
||||||
|
return $this->belongsTo(Location::class,"location_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function affiliator(){
|
||||||
|
return $this->belongsTo(Affiliator::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function referenceIssued(){
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function referenceUsed(){
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ItemReference::class, 'item_reference_id', 'id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class VoucherClaim extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'voucher_claims';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
public $incrementing = true;
|
||||||
|
protected $keyType = 'int';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'time',
|
||||||
|
'voucher_id',
|
||||||
|
'user_id',
|
||||||
|
'claimable_id',
|
||||||
|
'claimable_type',
|
||||||
|
'claimer_id',
|
||||||
|
'claimer_type'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user() {
|
||||||
|
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function claimable(){
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function claimer(){
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function voucher(){
|
||||||
|
return $this->belongsTo(Voucher::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class VoucherCoaching extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['code','released_by','released_at',
|
||||||
|
'name', 'phone', 'email', 'submitted_at', 'scheduled_at', 'scheduled_by',
|
||||||
|
'schedule_date'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function releasedBy(){
|
||||||
|
return $this->belongsTo(User::class,"released_by");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scheduledBy(){
|
||||||
|
return $this->belongsTo(User::class,"scheduled_by");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class VoucherEvent extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = ['name', 'referral','nominal','calculation_type','code', 'redeem_point','for_affiliator','start_at','end_at','claim_limit','min_sales'];
|
||||||
|
|
||||||
|
public function items(){
|
||||||
|
return $this->belongsToMany(ItemReference::class,"voucher_items");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
class Wishlist extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'customer_id',
|
||||||
|
'item_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function customer(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Customer::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function item(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Items::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class XenditLink extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
"uid",
|
||||||
|
"invoice_url",
|
||||||
|
"user_id",
|
||||||
|
"external_id",
|
||||||
|
"status",
|
||||||
|
"amount",
|
||||||
|
"received_amount",
|
||||||
|
"expiry_date",
|
||||||
|
"payment_id",
|
||||||
|
"paid_amount",
|
||||||
|
"payment_method",
|
||||||
|
"bank_code",
|
||||||
|
"payment_channel",
|
||||||
|
"payment_destination",
|
||||||
|
"paid_at"
|
||||||
|
];
|
||||||
|
|
||||||
|
public function payment()
|
||||||
|
{
|
||||||
|
return $this->morphOne(TransactionPayment::class,"method");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
use Kreait\Firebase\Messaging\CloudMessage;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\UserDevice;
|
||||||
|
|
||||||
|
class FcmChannel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Send the given notification.
|
||||||
|
*/
|
||||||
|
public function send(object $notifiable, Notification $notification): void
|
||||||
|
{
|
||||||
|
// $payload = $notification->toFcm($notifiable);
|
||||||
|
|
||||||
|
// if ($notifiable->fcm_token != null){
|
||||||
|
// $this->sendNotification($payload, $notifiable->fcm_token, $notifiable);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// foreach($notifiable->devices as $device){
|
||||||
|
// if ($device->fcm_token == $notifiable->fcm_token)
|
||||||
|
// continue;
|
||||||
|
|
||||||
|
// $this->sendNotification($payload, $device->fcm_token, $device);
|
||||||
|
// sleep(0.5);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendNotification($payload, $fcm_token, $device){
|
||||||
|
|
||||||
|
// if (!$fcm_token)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// try{
|
||||||
|
// $payload["token"] = $fcm_token;
|
||||||
|
// $messaging = app('firebase.messaging');
|
||||||
|
// $message = CloudMessage::fromArray($payload);
|
||||||
|
// $result = $messaging->send($message);
|
||||||
|
// }catch(\Kreait\Firebase\Exception\Messaging\NotFound $e){
|
||||||
|
// if (get_class($device) == UserDevice::class){
|
||||||
|
// $device->fcm_token = null;
|
||||||
|
// $device->save();
|
||||||
|
// }else if (get_class($device) == User::class){
|
||||||
|
// $device->fcm_token = null;
|
||||||
|
// $device->save();
|
||||||
|
// }
|
||||||
|
// }catch(\Kreait\Firebase\Exception\Messaging\InvalidMessage $e){
|
||||||
|
// \Log::info([$fcm_token, $e->getMessage()]);
|
||||||
|
// }catch(\Exception $e){
|
||||||
|
// report($e);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
use App\Models\Transaction;
|
||||||
|
use App\Notifications\FcmChannel;
|
||||||
|
|
||||||
|
|
||||||
|
class NewOrder extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
protected $transaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new notification instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Transaction $transaction)
|
||||||
|
{
|
||||||
|
$this->transaction = $transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the notification's delivery channels.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function via($notifiable)
|
||||||
|
{
|
||||||
|
return ['database',FcmChannel::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||||
|
*/
|
||||||
|
public function toMail($notifiable)
|
||||||
|
{
|
||||||
|
return (new MailMessage)
|
||||||
|
->line('The introduction to the notification.')
|
||||||
|
->action('Notification Action', url('/'))
|
||||||
|
->line('Thank you for using our application!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray($notifiable)
|
||||||
|
{
|
||||||
|
$transaction = $this->transaction;
|
||||||
|
return [
|
||||||
|
"title" => "Ada Pesanan baru masuk!",
|
||||||
|
"body" => "Mohon segera proses pesanan nomor $transaction->number",
|
||||||
|
"type" => "Info",
|
||||||
|
"data" => $this->transaction,
|
||||||
|
"model" => get_class($this->transaction)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toFcm($notifiable)
|
||||||
|
{
|
||||||
|
$payload = $this->toArray($notifiable);
|
||||||
|
|
||||||
|
return [
|
||||||
|
"notification" => [
|
||||||
|
"title" => $payload["title"],
|
||||||
|
"body" => $payload["body"],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
use App\Models\Transaction;
|
||||||
|
use App\Notifications\FcmChannel;
|
||||||
|
|
||||||
|
|
||||||
|
class OrderCanceled extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
protected $transaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new notification instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Transaction $transaction)
|
||||||
|
{
|
||||||
|
$this->transaction = $transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the notification's delivery channels.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function via($notifiable)
|
||||||
|
{
|
||||||
|
return ['database',FcmChannel::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||||
|
*/
|
||||||
|
public function toMail($notifiable)
|
||||||
|
{
|
||||||
|
return (new MailMessage)
|
||||||
|
->line('The introduction to the notification.')
|
||||||
|
->action('Notification Action', url('/'))
|
||||||
|
->line('Thank you for using our application!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray($notifiable)
|
||||||
|
{
|
||||||
|
$transaction = $this->transaction;
|
||||||
|
$status = $transaction->statuses()->where("status","CANCELED")->first();
|
||||||
|
return [
|
||||||
|
"title" => "Pesanan telah dibatalkan!",
|
||||||
|
"body" => "Pesanan $transaction->number telah dibatalkan $status->note",
|
||||||
|
"type" => "Info",
|
||||||
|
"data" => $this->transaction,
|
||||||
|
"model" => get_class($this->transaction)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toFcm($notifiable)
|
||||||
|
{
|
||||||
|
$payload = $this->toArray($notifiable);
|
||||||
|
|
||||||
|
return [
|
||||||
|
"notification" => [
|
||||||
|
"title" => $payload["title"],
|
||||||
|
"body" => $payload["body"],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Member\Transaction;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
use App\Models\Transaction;
|
||||||
|
use App\Notifications\FcmChannel;
|
||||||
|
|
||||||
|
|
||||||
|
class OrderDelivered extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
protected $transaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new notification instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Transaction $transaction)
|
||||||
|
{
|
||||||
|
$this->transaction = $transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the notification's delivery channels.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function via($notifiable)
|
||||||
|
{
|
||||||
|
return ['database',FcmChannel::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mail representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||||
|
*/
|
||||||
|
public function toMail($notifiable)
|
||||||
|
{
|
||||||
|
return (new MailMessage)
|
||||||
|
->line('The introduction to the notification.')
|
||||||
|
->action('Notification Action', url('/'))
|
||||||
|
->line('Thank you for using our application!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array representation of the notification.
|
||||||
|
*
|
||||||
|
* @param mixed $notifiable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray($notifiable)
|
||||||
|
{
|
||||||
|
$transaction = $this->transaction;
|
||||||
|
return [
|
||||||
|
"title" => "Pesanan sudah tiba!",
|
||||||
|
"body" => "Pesanan $transaction->number sudah tiba di alamat tujuan",
|
||||||
|
"type" => "Info",
|
||||||
|
"data" => $this->transaction,
|
||||||
|
"model" => get_class($this->transaction)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toFcm($notifiable)
|
||||||
|
{
|
||||||
|
$payload = $this->toArray($notifiable);
|
||||||
|
|
||||||
|
return [
|
||||||
|
"notification" => [
|
||||||
|
"title" => $payload["title"],
|
||||||
|
"body" => $payload["body"],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue