wip
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\System\VersionManagement;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\System\VersionManagement\CheckForUpdateRequest;
|
||||
use App\Models\System\VersionManagement\AppVersion;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class AppVersionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Check for app updates
|
||||
*/
|
||||
public function checkForUpdate(CheckForUpdateRequest $request): JsonResponse
|
||||
{
|
||||
$app_version = AppVersion::latest()->where('os', $request->os)->first();
|
||||
|
||||
if (! $app_version || $request->version === $app_version->version) {
|
||||
return $this->latestVersion();
|
||||
}
|
||||
|
||||
if ($request->version < $app_version->version && $app_version->important) {
|
||||
return $this->requiredToUpdate();
|
||||
}
|
||||
|
||||
if ((int) $request->version < (int) $app_version->version) {
|
||||
return $this->optionalToUpdate();
|
||||
}
|
||||
|
||||
return $this->versionNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Latest version
|
||||
*/
|
||||
public function latestVersion(): JsonResponse
|
||||
{
|
||||
return response()->json(['update' => 'latest']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required to update
|
||||
*/
|
||||
public function requiredToUpdate(): JsonResponse
|
||||
{
|
||||
return response()->json(['update' => 'required']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update not required, but should be
|
||||
*/
|
||||
public function optionalToUpdate(): JsonResponse
|
||||
{
|
||||
return response()->json(['update' => 'optional']);
|
||||
}
|
||||
|
||||
/**
|
||||
* App version not found
|
||||
*/
|
||||
public function versionNotFound(): JsonResponse
|
||||
{
|
||||
return response()->json(['update' => 'version-not-found']);
|
||||
}
|
||||
}
|
||||
23
app/Http/Controllers/Api/V1/AttributeController.php
Normal file
23
app/Http/Controllers/Api/V1/AttributeController.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Shop\Product\Attribute;
|
||||
|
||||
class AttributeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return response()->rest(
|
||||
Attribute::with('values:id,key,attribute_id,value,position')
|
||||
->where('is_enabled', true)
|
||||
->get(['id', 'slug', 'name', 'type', 'category_id', 'is_enabled'])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Auth\Register;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class AuthRegisterRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'phone_number' => ['required', 'integer', 'between:61000000,71999999', 'unique:users,phone_number'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'address' => ['required', 'string', 'max:255'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a passed validation attempt.
|
||||
*/
|
||||
protected function passedValidation(): void
|
||||
{
|
||||
$name = explode(' ', $this->name);
|
||||
|
||||
$this->merge([
|
||||
'first_name' => $name[0],
|
||||
'last_name' => count($name) > 1 ? $name[0] : '',
|
||||
]);
|
||||
}
|
||||
}
|
||||
80
app/Http/Controllers/Api/V1/AuthController.php
Normal file
80
app/Http/Controllers/Api/V1/AuthController.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Auth\Register\AuthRegisterRequest;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Auth\AuthLoginRequest;
|
||||
use App\Http\Requests\Api\V1\Auth\AuthVerifyRequest;
|
||||
use App\Models\User;
|
||||
use App\Repositories\UserRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
/**
|
||||
* (Auth) Guest token (walk-in-user)
|
||||
*/
|
||||
public function guestToken(): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
data: UserRepository::guestUser()->createToken(bin2hex(random_bytes(25)))->plainTextToken,
|
||||
code: 201
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register user
|
||||
*/
|
||||
public function register(AuthRegisterRequest $request): JsonResponse
|
||||
{
|
||||
UserRepository::registerUser($request)();
|
||||
|
||||
sendSMSVerification($request->phone_number);
|
||||
|
||||
return response()->rest(
|
||||
data: [],
|
||||
code: 201,
|
||||
message: sprintf('%s: %s', __('Verification code sent to'), $request->phone_number)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (Auth) Login
|
||||
*/
|
||||
public function login(AuthLoginRequest $request): JsonResponse
|
||||
{
|
||||
sendSMSVerification($request->phone_number);
|
||||
|
||||
return response()->rest(
|
||||
data: [],
|
||||
code: 201,
|
||||
message: sprintf('%s: %s', __('Verification code sent to'), $request->phone_number)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (Auth) Verify the code
|
||||
*/
|
||||
public function verify(AuthVerifyRequest $request): JsonResponse
|
||||
{
|
||||
$user = User::where('phone_number', $request->phone_number)->firstOr(UserRepository::registerUser($request));
|
||||
|
||||
return response()->rest(
|
||||
data: $user->createToken(bin2hex(random_bytes(20)))->plainTextToken,
|
||||
code: 201
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (Auth)* Delete user
|
||||
*
|
||||
* @authenticated
|
||||
*/
|
||||
public function delete(): JsonResponse
|
||||
{
|
||||
auth()->user()->delete();
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
}
|
||||
32
app/Http/Controllers/Api/V1/Banner/BannerController.php
Normal file
32
app/Http/Controllers/Api/V1/Banner/BannerController.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Banner;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Banner\Requests\BannerIndexRequest;
|
||||
use App\Http\Controllers\Api\V1\Banner\Resources\BannerResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\CMS\Media\Banner;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class BannerController extends Controller
|
||||
{
|
||||
/**
|
||||
* (Media) Banners (index)
|
||||
*/
|
||||
public function index(BannerIndexRequest $request): JsonResponse
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
BannerResource::collection(
|
||||
Banner::with('media')
|
||||
->where('is_visible', true)
|
||||
->when($request->place, fn ($query, $place) => $query->where('place', $place))
|
||||
->when($request->app, fn ($query, $app) => $query->where('app', $app))
|
||||
->ordered()
|
||||
->simplePaginate(
|
||||
perPage: $request->perPage,
|
||||
columns: $request->fields,
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Banner\Requests;
|
||||
|
||||
use App\Models\CMS\Media\Banner;
|
||||
use App\Models\System\Settings\OS;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class BannerIndexRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'place' => ['nullable', 'string', Rule::in(array_keys(Banner::places()))],
|
||||
'app' => ['nullable', 'string', Rule::in(array_keys(OS::apps()))],
|
||||
'perPage' => ['nullable', 'integer'],
|
||||
'fields' => ['nullable', 'string'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a passed validation attempt.
|
||||
*/
|
||||
protected function passedValidation(): void
|
||||
{
|
||||
$fields = [];
|
||||
if ($this->fields) {
|
||||
$sanitezedFields = validateCommaSeperated($this->fields, Banner::class);
|
||||
|
||||
$fields['fields'] = ! empty($sanitezedFields) ? $sanitezedFields : ['*'];
|
||||
} else {
|
||||
$fields['fields'] = ['*'];
|
||||
}
|
||||
|
||||
$this->merge([
|
||||
'perPage' => $this->perPage ?: 6,
|
||||
...$fields,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error messages for the defined validation rules.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'place.in' => sprintf('Valid sources: %s', implode(', ', array_keys(OS::apps()))),
|
||||
'app.in' => sprintf('Valid sources: %s', implode(', ', array_keys(OS::apps()))),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Banner\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BannerResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->whenHas('id'),
|
||||
'app' => $this->whenHas('app'),
|
||||
'title' => $this->whenHas('title'),
|
||||
'place' => $this->whenHas('place'),
|
||||
'link' => $this->whenHas('link'),
|
||||
'resource_type' => $this->whenHas('resource_type'),
|
||||
'resource_id' => $this->whenHas('resource_id'),
|
||||
'thumbnail' => $this->thumbnail('350x350'),
|
||||
'related_resources' => $this->when(
|
||||
condition: $this->shouldIncludeRelatedResources($request),
|
||||
value: fn () => $this->relatedResources(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if should include related resources
|
||||
*/
|
||||
protected function shouldIncludeRelatedResources(Request $request): bool
|
||||
{
|
||||
if (! $request->fields) {
|
||||
$request->merge(['fields' => ['*']]);
|
||||
}
|
||||
|
||||
if ($request->fields[0] === '*') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return in_array(['resource_type', 'resource_id', 'place'], $request->fields);
|
||||
}
|
||||
}
|
||||
61
app/Http/Controllers/Api/V1/Brand/BrandController.php
Normal file
61
app/Http/Controllers/Api/V1/Brand/BrandController.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Brand;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Brand\Resources\BrandResource;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Brand\BrandIndexRequest;
|
||||
use App\Http\Requests\Api\V1\Brand\BrandProductsRequest;
|
||||
use App\Models\Ecommerce\Product\Brand\Brand;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class BrandController extends Controller
|
||||
{
|
||||
/**
|
||||
* Brands (index)
|
||||
*/
|
||||
public function index(BrandIndexRequest $request): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
BrandResource::collection(
|
||||
Brand::query()
|
||||
->with('media')
|
||||
->enabled()
|
||||
->ordered()
|
||||
->when($request->input('type'), fn ($query, $type) => $query->where('type', $type))
|
||||
->get()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Brands (show)
|
||||
*
|
||||
* @param App\Models\Ecommerce\Product\Brand\Brand $brand
|
||||
*/
|
||||
public function show(Brand $brand): JsonResponse
|
||||
{
|
||||
$brand->load('media');
|
||||
|
||||
return response()->rest(new BrandResource($brand));
|
||||
}
|
||||
|
||||
/**
|
||||
* Brands (products)
|
||||
*/
|
||||
public function products(BrandProductsRequest $request, Brand $brand): JsonResponse
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
ProductResource::collection(
|
||||
ProductRepository::make($request)
|
||||
->queryAsFromResource($brand)
|
||||
->applyBasicQueries()
|
||||
->applyFilters()
|
||||
->applySorting()
|
||||
->simplePaginate()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Brand\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BrandMediaResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'thumbnail' => $this->getUrl('thumb200x200'),
|
||||
'images_400x400' => $this->getUrl('thumb400x400'),
|
||||
'images_720x720' => $this->getUrl('thumb720x720'),
|
||||
'images_800x800' => $this->getUrl('thumb800x800'),
|
||||
'images_1200x1200' => $this->getUrl('thumb1200x1200'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Brand\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BrandResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
'type' => $this->type,
|
||||
'description' => $this->description,
|
||||
'media' => BrandMediaResource::collection($this->whenLoaded('media')),
|
||||
];
|
||||
}
|
||||
}
|
||||
32
app/Http/Controllers/Api/V1/Carousel/CarouselController.php
Normal file
32
app/Http/Controllers/Api/V1/Carousel/CarouselController.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Carousel;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Carousel\Requests\CarouselIndexRequest;
|
||||
use App\Http\Controllers\Api\V1\Carousel\Resources\CarouselResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\CMS\Media\Carousel;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class CarouselController extends Controller
|
||||
{
|
||||
/**
|
||||
* (Media) Carousels (index)
|
||||
*/
|
||||
public function index(CarouselIndexRequest $request): JsonResponse
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
CarouselResource::collection(
|
||||
Carousel::with('media')
|
||||
->where('is_visible', true)
|
||||
->when($request->place, fn ($query, $place) => $query->where('place', $place))
|
||||
->when($request->app, fn ($query, $app) => $query->where('app', $app))
|
||||
->ordered()
|
||||
->simplePaginate(
|
||||
perPage: $request->perPage,
|
||||
columns: $request->fields,
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Carousel\Requests;
|
||||
|
||||
use App\Models\CMS\Media\Carousel;
|
||||
use App\Models\System\Settings\OS;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class CarouselIndexRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'place' => ['nullable', 'string', Rule::in(array_keys(
|
||||
Carousel::places()
|
||||
))],
|
||||
'perPage' => ['nullable', 'integer'],
|
||||
'fields' => ['nullable', 'string'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a passed validation attempt.
|
||||
*/
|
||||
protected function passedValidation(): void
|
||||
{
|
||||
$fields = [];
|
||||
if ($this->fields) {
|
||||
$sanitezedFields = validateCommaSeperated($this->fields, Carousel::class);
|
||||
|
||||
$fields['fields'] = ! empty($sanitezedFields) ? $sanitezedFields : ['*'];
|
||||
} else {
|
||||
$fields['fields'] = ['*'];
|
||||
}
|
||||
|
||||
$this->merge([
|
||||
'perPage' => $this->perPage ?: 6,
|
||||
...$fields,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error messages for the defined validation rules.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'place.in' => sprintf('Valid sources: %s', implode(', ', array_keys(OS::apps()))),
|
||||
'app.in' => sprintf('Valid sources: %s', implode(', ', array_keys(OS::apps()))),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Carousel\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class CarouselResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->whenHas('id'),
|
||||
'title' => $this->whenHas('title'),
|
||||
'place' => $this->whenHas('place'),
|
||||
'app' => $this->whenHas('app'),
|
||||
'link' => $this->whenHas('link'),
|
||||
'resource_id' => $this->whenHas('resource_id'),
|
||||
'resource_type' => $this->whenHas('resource_type'),
|
||||
'thumbnail' => $this->thumbnail('650x650'),
|
||||
'image' => $this->getFirstMediaUrl('main'),
|
||||
];
|
||||
}
|
||||
}
|
||||
79
app/Http/Controllers/Api/V1/CartController.php
Normal file
79
app/Http/Controllers/Api/V1/CartController.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Cart\CartRemoveRequest;
|
||||
use App\Http\Requests\Api\V1\Cart\CartStoreRequest;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class CartController extends Controller
|
||||
{
|
||||
/**
|
||||
* (*) Users carts (index)
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
$cartItems = auth()->user()->carts()
|
||||
->with(['product' => ['media', 'brand']])
|
||||
->orderBy('cart_items.id', 'desc')
|
||||
->get()
|
||||
->each(function ($cartItem) {
|
||||
if ($cartItem->product->stock < $cartItem->product_quantity) {
|
||||
if ($cartItem->product->stock >= 1) {
|
||||
$cartItem->update([
|
||||
'product_quantity' => $cartItem->product->stock,
|
||||
]);
|
||||
} else {
|
||||
$cartItem->delete();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return response()->rest(
|
||||
$cartItems->map(fn ($cartItem) => [
|
||||
'id' => $cartItem->id,
|
||||
'user_id' => $cartItem->user_id,
|
||||
'product_id' => $cartItem->product_id,
|
||||
'product_quantity' => $cartItem->product_quantity,
|
||||
'created_at' => $cartItem->created_at,
|
||||
'updated_at' => $cartItem->updated_at,
|
||||
'product' => new ProductResource($cartItem->product),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Store new cart (store)
|
||||
*/
|
||||
public function store(CartStoreRequest $request): JsonResponse
|
||||
{
|
||||
auth()->user()->carts()->updateOrInsert(
|
||||
['user_id' => auth()->id(), 'product_id' => $request->product_id],
|
||||
['product_quantity' => $request->product_quantity]
|
||||
);
|
||||
|
||||
return response()->rest(message: 'Cart item added or updated successfully', code: 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Remove item from cart (patch)
|
||||
*/
|
||||
public function remove(CartRemoveRequest $request): JsonResponse
|
||||
{
|
||||
auth()->user()->carts()->where('product_id', $request->product_id)->delete();
|
||||
|
||||
return response()->rest(message: 'Cart item removed successfully', code: 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Delete all user's carts (delete)
|
||||
*/
|
||||
public function destroy(): JsonResponse
|
||||
{
|
||||
auth()->user()->carts()->delete();
|
||||
|
||||
return response()->rest(message: "All user's carts deleted successfully", code: 200);
|
||||
}
|
||||
}
|
||||
73
app/Http/Controllers/Api/V1/Category/CategoryController.php
Normal file
73
app/Http/Controllers/Api/V1/Category/CategoryController.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Category;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Category\Resources\CategoryResource;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Category\CategoryIndexRequest;
|
||||
use App\Http\Requests\Api\V1\Product\BasicProductIndexRequest;
|
||||
use App\Models\Ecommerce\Product\Category\Category;
|
||||
use App\Repositories\Ecommerce\Product\Category\CategoryRepository;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* Categories (index)
|
||||
*/
|
||||
public function index(CategoryIndexRequest $request): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
CategoryResource::collection(
|
||||
CategoryRepository::make($request)
|
||||
->applyBasicQueries()
|
||||
->applyFilters()
|
||||
->get()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Categories (show)
|
||||
*/
|
||||
public function show(Category $category): JsonResponse
|
||||
{
|
||||
$category->load(['media', 'children']);
|
||||
|
||||
return response()->rest(new CategoryResource($category));
|
||||
}
|
||||
|
||||
/**
|
||||
* Categories (children)
|
||||
*/
|
||||
public function children(Category $category): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
CategoryResource::collection(
|
||||
$category->children()
|
||||
->enabled()
|
||||
->ordered()
|
||||
->get()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Brands (products)
|
||||
*/
|
||||
public function products(BasicProductIndexRequest $request, Category $category): JsonResponse
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
ProductResource::collection(
|
||||
ProductRepository::make($request)
|
||||
->queryAsFromResource($category)
|
||||
->applyBasicQueries()
|
||||
->applyFilters()
|
||||
->applySorting()
|
||||
->simplePaginate()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Category\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class CategoryMediaResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'thumbnail' => $this->getUrl(),
|
||||
'images_400x400' => $this->getUrl('thumb400x400'),
|
||||
'images_720x720' => $this->getUrl('thumb720x720'),
|
||||
'images_800x800' => $this->getUrl('thumb800x800'),
|
||||
'images_1200x1200' => $this->getUrl('thumb1200x1200'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Category\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class CategoryResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'parent_id' => $this->parent_id,
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
'group' => $this->type,
|
||||
'description' => $this->description,
|
||||
'color' => $this->color,
|
||||
'media' => CategoryMediaResource::collection($this->whenLoaded('media')),
|
||||
'children' => static::collection($this->whenLoaded('children')),
|
||||
];
|
||||
}
|
||||
}
|
||||
61
app/Http/Controllers/Api/V1/Channel/ChannelController.php
Normal file
61
app/Http/Controllers/Api/V1/Channel/ChannelController.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Channel;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Channel\Requests\ChannelIndexRequest;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\V1\Channel\ChannelResource;
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ChannelController extends Controller
|
||||
{
|
||||
/**
|
||||
* Channels (index)
|
||||
*/
|
||||
public function index(ChannelIndexRequest $request): JsonResponse
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
ChannelResource::collection(
|
||||
Channel::query()
|
||||
->with('media')
|
||||
->where('is_visible', true)
|
||||
->ordered()
|
||||
->simplePaginate(
|
||||
perPage: $request->perPage,
|
||||
columns: $request->fields,
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Channels (show)
|
||||
*/
|
||||
public function show(Channel $channel): JsonResponse
|
||||
{
|
||||
$channel->load('media');
|
||||
|
||||
return response()->rest(new ChannelResource($channel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Channels (products)
|
||||
*/
|
||||
public function products(Request $request, Channel $channel): JsonResponse
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
ProductResource::collection(
|
||||
ProductRepository::make($request)
|
||||
->queryAsFromResource($channel)
|
||||
->applyBasicQueries()
|
||||
->applyFilters()
|
||||
->applySorting()
|
||||
->simplePaginate()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Channel\Requests;
|
||||
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ChannelIndexRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'perPage' => ['nullable', 'integer'],
|
||||
'fields' => ['nullable', 'string'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a passed validation attempt.
|
||||
*/
|
||||
protected function passedValidation(): void
|
||||
{
|
||||
$fields = [];
|
||||
if ($this->fields) {
|
||||
$sanitezedFields = validateCommaSeperated($this->fields, Channel::class);
|
||||
|
||||
$fields['fields'] = ! empty($sanitezedFields) ? $sanitezedFields : ['*'];
|
||||
} else {
|
||||
$fields['fields'] = ['*'];
|
||||
}
|
||||
|
||||
$this->merge([
|
||||
'perPage' => $this->perPage ?: 6,
|
||||
...$fields,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Collection;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Collection\Resources\CollectionResource;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Product\BasicProductIndexRequest;
|
||||
use App\Models\Ecommerce\Product\Collection\Collection;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CollectionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Collections (index).
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
CollectionResource::collection(
|
||||
Collection::with('media')->where('is_visible', true)->ordered()->get()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paginated
|
||||
*/
|
||||
public function paginated(Request $request)
|
||||
{
|
||||
$perPage = $request->perPage ?: 6;
|
||||
|
||||
return response()->rest_paginate(
|
||||
CollectionResource::collection(
|
||||
Collection::with('media')->where('is_visible', true)->ordered()->simplePaginate($perPage)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collections (show)
|
||||
*/
|
||||
public function show(Collection $collection): JsonResponse
|
||||
{
|
||||
$collection->load('media');
|
||||
|
||||
return response()->rest(new CollectionResource($collection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Collections (products)
|
||||
*/
|
||||
public function products(BasicProductIndexRequest $request, Collection $collection)
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
ProductResource::collection(
|
||||
ProductRepository::make($request)
|
||||
->queryAsFromResource($collection)
|
||||
->applyBasicQueries()
|
||||
->applyFilters()
|
||||
->applySorting()
|
||||
->simplePaginate()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Collection\Resources;
|
||||
|
||||
use App\Http\Resources\MediaResource;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class CollectionResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
'description' => $this->description,
|
||||
'sort_order' => $this->sort_order,
|
||||
'seo_title' => $this->seo_title,
|
||||
'seo_description' => $this->seo_description,
|
||||
'media' => MediaResource::collection($this->whenLoaded('media')),
|
||||
];
|
||||
}
|
||||
}
|
||||
102
app/Http/Controllers/Api/V1/CommentController.php
Normal file
102
app/Http/Controllers/Api/V1/CommentController.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Shop\Product\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class CommentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return response()->rest(
|
||||
DB::table('comments')->where('user_id', auth()->id())->get()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'product_id' => ['required', 'integer', 'exists:products,id'],
|
||||
'comment' => ['required', 'string'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, 'Validation failed');
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
$product = Product::find($request->product_id);
|
||||
$product->commentAsUser($user, strip_tags($request->comment));
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'comment_id' => ['required', 'integer', 'exists:comments,id'],
|
||||
'comment' => ['required', 'string'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, []);
|
||||
}
|
||||
|
||||
DB::table('comments')->where('id', $request->comment_id)->update([
|
||||
'comment' => strip_tags($request->comment),
|
||||
]);
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), ['comment_id' => ['required', 'integer']]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, []);
|
||||
}
|
||||
|
||||
DB::table('comments')->where('id', $request->comment_id)->delete();
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
}
|
||||
27
app/Http/Controllers/Api/V1/ContactMessageController.php
Normal file
27
app/Http/Controllers/Api/V1/ContactMessageController.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Forms\ContactUS\ContactUSStoreRequest;
|
||||
use App\Models\CMS\Forms\ContactUS;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class ContactMessageController extends Controller
|
||||
{
|
||||
/**
|
||||
* (Marketing)* Contact us
|
||||
*/
|
||||
public function store(ContactUSStoreRequest $request): JsonResponse
|
||||
{
|
||||
ContactUS::create([
|
||||
'phone' => $request->phone,
|
||||
'title' => $request->title,
|
||||
'content' => $request->content,
|
||||
'type' => $request->type,
|
||||
'user_id' => auth()->id(),
|
||||
]);
|
||||
|
||||
return response()->rest([], 201);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Auth\Verification;
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class EntrepreneurAuthController extends Controller
|
||||
{
|
||||
public function register(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'first_name' => ['required', 'string'],
|
||||
'phone_number' => ['required', 'integer', 'between:61000000,71999999', 'unique:users,phone_number'],
|
||||
'email' => ['required', 'email', 'unique:users,email'],
|
||||
'password' => ['required'],
|
||||
'region' => ['required', 'string', 'in:mr,ag,ah,dz,lb,bn'],
|
||||
'patent_data' => ['nullable'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($request) {
|
||||
$user = User::create([
|
||||
'first_name' => $request->first_name,
|
||||
'last_name' => ' ',
|
||||
'email' => $request->email,
|
||||
'password' => bcrypt($request->password),
|
||||
'phone_number' => $request->phone_number,
|
||||
]);
|
||||
|
||||
$user->documents()->create([
|
||||
'patent_data' => str_replace('public/', '', $request->file('patent_data')?->store('public/entrepreneur/patent_data') ?? 'public/'),
|
||||
]);
|
||||
|
||||
sendSMSVerification($request->phone_number);
|
||||
|
||||
// Verification::updateOrCreate(['username' => $request->email, 'code' => 12345]);
|
||||
});
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
|
||||
public function verifyPhoneNumber(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), ['phone_number' => 'required|integer|between:61000000,65999999', 'code' => 'required|string']);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
$verification = Verification::where('username', $request->phone_number)->where('code', $request->code)->first();
|
||||
|
||||
if (! $verification) {
|
||||
return response()->rest([], 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
User::where('phone_number', $request->phone_number)->update(['phone_number_verified_at' => now()]);
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
|
||||
public function verifyEmail(Request $request)
|
||||
{
|
||||
// email should be validated for deleted_at to
|
||||
$validator = Validator::make($request->all(), ['email' => ['required', 'string', 'email', 'exists:users,email'], 'code' => ['required', 'string']]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
$verfication = Verification::where('username', $request->email)->where('code', $request->code)->first();
|
||||
|
||||
if (! $verfication) {
|
||||
return response()->rest([], 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
$user->email_verified_at = now();
|
||||
$user->save();
|
||||
|
||||
event(new Verified($user));
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
|
||||
public function finalize(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'email' => ['required', 'string', 'email', 'exists:users,email'],
|
||||
'password' => ['required', 'string'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
if (! auth()->attempt(['email' => $request->email, 'password' => $request->password])) {
|
||||
return response()->rest([], 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if (! $user || ! Hash::check($request->password, $user->password)) {
|
||||
return response()->rest([], 400, 'Failed');
|
||||
}
|
||||
|
||||
if (! $user->hasRole('vendor')) {
|
||||
$user->assignRole('vendor');
|
||||
|
||||
// User
|
||||
$name = $user->first_name;
|
||||
|
||||
$channel = Channel::create([
|
||||
'name' => $name,
|
||||
'slug' => Str::slug($name).'_'.random_int(10000, 9999999),
|
||||
'description' => '',
|
||||
'timezone' => 'asia/ashgabat',
|
||||
'url' => url('/'),
|
||||
'is_default' => true,
|
||||
'channelables_type' => 'App\Models\User',
|
||||
'channelables_id' => $user->id,
|
||||
'is_visible' => true,
|
||||
]);
|
||||
|
||||
$channel->inventories()->create([
|
||||
'name' => $name,
|
||||
'code' => Str::slug($name).'_'.random_int(10000, 9999999),
|
||||
'region' => 'ag',
|
||||
'shareable' => false,
|
||||
'is_default' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
$bearerToken = $user->createToken(bin2hex(random_bytes(20)))->plainTextToken;
|
||||
|
||||
return response()->rest($bearerToken, 201);
|
||||
}
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), ['email' => 'required|string|email', 'password' => 'required|string']);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, 'Absolutely wrong credentials.');
|
||||
}
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if (! $user || ! Hash::check($request->password, $user->password)) {
|
||||
return response()->rest([], 400, 'Failed');
|
||||
}
|
||||
|
||||
$bearerToken = $user->createToken(bin2hex(random_bytes(20)))->plainTextToken;
|
||||
|
||||
return response()->rest($bearerToken, 201);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\V1\Vendor\Order\VendorOrderIndexResource;
|
||||
use App\Http\Resources\Api\V1\Vendor\Order\VendorOrderShowResource;
|
||||
use App\Models\Ecommerce\Product\Order\Order;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class EntrepreneurOrderController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$order_ids = DB::table('order_items')
|
||||
->where('channel_id', auth()->user()->channel()->id)
|
||||
->distinct()
|
||||
->pluck('order_id');
|
||||
|
||||
$perPage = $request->input('perPage') ?? 20;
|
||||
$page = $request->input('page') ?? 1;
|
||||
|
||||
return response()->rest_paginate(
|
||||
VendorOrderIndexResource::collection(
|
||||
Order::query()
|
||||
->whereIntegerInRaw('orders.id', $order_ids)
|
||||
->with('paymentType')
|
||||
->latest()
|
||||
->paginate($perPage, ['*'], 'page', $page)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function show(Order $order)
|
||||
{
|
||||
$order->load(['items' => ['product' => ['media']]]);
|
||||
|
||||
return new VendorOrderShowResource($order);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class VendorProductStoreRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
// essentials...
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'description' => ['nullable', 'string', 'max:255'],
|
||||
'files' => ['nullable'],
|
||||
|
||||
// prices...
|
||||
'cost_amount' => ['required', 'numeric'],
|
||||
'old_price_amount' => ['nullable', 'numeric', 'gt:cost_amount'],
|
||||
|
||||
// relationships...
|
||||
// 'integer', 'exists:brands,id'
|
||||
'brand_id' => ['nullable'],
|
||||
'category_ids' => ['required', 'array'],
|
||||
'collection_ids' => ['nullable', 'array'],
|
||||
|
||||
// inventories...
|
||||
'stock' => ['required', 'integer', 'min:1'],
|
||||
'sku' => ['nullable', 'string', 'max:255'],
|
||||
'barcode' => ['nullable', 'string', 'max:255', 'unique:products,barcode'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class VendorProductUpdateRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
// essentials...
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'description' => ['nullable', 'string', 'max:255'],
|
||||
'new_imgs' => ['nullable'],
|
||||
'deleted_images' => ['nullable'],
|
||||
|
||||
// prices...
|
||||
'cost_amount' => ['required', 'numeric'],
|
||||
'old_price_amount' => ['nullable', 'numeric', 'gt:cost_amount'],
|
||||
|
||||
// relationships...
|
||||
'brand_id' => ['nullable', 'integer', 'exists:brands,id'],
|
||||
'category_ids' => ['required', 'array'],
|
||||
'collection_ids' => ['nullable', 'array'],
|
||||
|
||||
// inventories...
|
||||
'stock' => ['required', 'integer', 'min:1'],
|
||||
'sku' => ['nullable', 'string', 'max:255'],
|
||||
'barcode' => ['nullable', 'string', 'max:255'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class VendorMetricsController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$channel = auth()->user()->channel();
|
||||
|
||||
$products_count = $channel->products()->count();
|
||||
$order_items = DB::table('order_items')->where('channel_id', $channel->id)->count();
|
||||
$order_items_today = DB::table('order_items')->where('channel_id', $channel->id)->whereDate('created_at', Carbon::today())->count();
|
||||
|
||||
return response()->rest([
|
||||
'products_count' => $products_count,
|
||||
'order_items_count' => $order_items,
|
||||
'order_items_today_count' => $order_items_today,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Entrepreneur\Requests\VendorProductStoreRequest;
|
||||
use App\Http\Controllers\Api\V1\Entrepreneur\Requests\VendorProductUpdateRequest;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\Review\ProductReviewResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\V1\Vendor\Product\VendorProductIndexResource;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Models\User;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class VendorProductController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$channel = $user->channel();
|
||||
|
||||
if (! $channel) {
|
||||
return response()->rest([], 400, 'User doest not have a channel');
|
||||
}
|
||||
|
||||
return response()->rest_paginate(
|
||||
VendorProductIndexResource::collection(
|
||||
ProductRepository::make($request)
|
||||
->queryAsFromResource($channel)
|
||||
->attachEagerLoadingRelationship([
|
||||
'brand',
|
||||
'media' => function ($query) {
|
||||
$query->orderBy('order_column', 'asc');
|
||||
},
|
||||
])
|
||||
->applyFilters()
|
||||
->applySorting()
|
||||
->simplePaginate()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(VendorProductStoreRequest $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$channel = $user->channel();
|
||||
$tax = productTaxForCategory($request->category_ids ?? []);
|
||||
|
||||
if ($request->brand_id == 0) {
|
||||
$request->merge(['brand_id' => null]);
|
||||
}
|
||||
|
||||
$this->addProduct($request, $user, $channel, $tax);
|
||||
|
||||
return response()->rest([], 201, 'Created');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product
|
||||
*/
|
||||
public function addProduct(Request $request, User $user, mixed $channel, int $tax)
|
||||
{
|
||||
$product = Product::create([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description,
|
||||
'cost_amount' => $request->cost_amount,
|
||||
'price_amount' => ProductRepository::calculatePrice($request->cost_amount, $tax),
|
||||
'old_price_amount' => $request->old_price_amount ? ProductRepository::calculatePrice($request->old_price_amount, $tax) : null,
|
||||
'sku' => $request->sku,
|
||||
'barcode' => $request->barcode,
|
||||
'brand_id' => $request->brand_id,
|
||||
'stock' => $request->stock,
|
||||
'is_visible' => false,
|
||||
'options' => json_encode(ProductRepository::shippingAttributes()),
|
||||
]);
|
||||
|
||||
$product->categories()->attach($request->category_ids);
|
||||
$product->collections()->attach($request->collection_ids);
|
||||
$product->channels()->attach($channel->id);
|
||||
|
||||
$inventory = $channel->inventories()->first() ?: tmpostDefaultInventory();
|
||||
|
||||
$product->inventories()->attach($inventory->id, ['stock' => $request->stock]);
|
||||
|
||||
if ($request->hasFile('files')) {
|
||||
$product->addMultipleMediaFromRequest(['files'])
|
||||
->each(function ($fileAdder) {
|
||||
$fileAdder->preservingOriginal()->toMediaCollection('uploads');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param App\Models\Ecommerce\Product\Product\Product $product
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Product $product)
|
||||
{
|
||||
$product->load('media');
|
||||
|
||||
return response()->rest(new VendorProductIndexResource($product));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(VendorProductUpdateRequest $request, Product $product)
|
||||
{
|
||||
$barcodeCheck = DB::table('products')
|
||||
->where('barcode', $request->barcode)
|
||||
->whereNot('id', $product->id)
|
||||
->exists();
|
||||
|
||||
if ($barcodeCheck) {
|
||||
return response()->rest([
|
||||
'message' => 'Used barcode',
|
||||
'errors' => ['barcode' => ['already taken']],
|
||||
]);
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$channel = $user->channel();
|
||||
$tax = productTaxForCategory($request->category_ids ?? []);
|
||||
|
||||
$product->update([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description,
|
||||
'cost_amount' => $request->cost_amount,
|
||||
'price_amount' => ProductRepository::calculatePrice($request->cost_amount, $tax),
|
||||
'old_price_amount' => $request->old_price_amount
|
||||
? ProductRepository::calculatePrice($request->old_price_amount, $tax)
|
||||
: null,
|
||||
'sku' => $request->sku,
|
||||
'barcode' => $request->barcode,
|
||||
'brand_id' => $request->brand_id,
|
||||
'stock' => $request->stock,
|
||||
]);
|
||||
|
||||
$product->categories()->attach($request->category_ids);
|
||||
$product->collections()->attach($request->collection_ids);
|
||||
|
||||
$inventory = $channel->inventories()->first() ?: tmpostDefaultInventory();
|
||||
|
||||
$product->inventories()->sync($inventory->id, ['stock' => $request->stock]);
|
||||
|
||||
if ($request->hasFile('files')) {
|
||||
$product->addMultipleMediaFromRequest(['files'])
|
||||
->each(function ($fileAdder) {
|
||||
$fileAdder->preservingOriginal()->toMediaCollection('uploads');
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->filled('deleted_images')) {
|
||||
$product->getMedia('uploads')->map(function ($media) use ($request) {
|
||||
if (in_array($media->getUrl('thumb'), $request->deleted_images)) {
|
||||
$media->delete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->hasFile('new_imgs')) {
|
||||
$product->addMultipleMediaFromRequest(['new_imgs'])
|
||||
->each(function ($fileAdder) {
|
||||
$fileAdder->toMediaCollection('uploads');
|
||||
});
|
||||
}
|
||||
|
||||
return response()->rest([], 201, 'Updated');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Product $product)
|
||||
{
|
||||
$product->delete();
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product reviews
|
||||
*/
|
||||
public function reviews(Product $product)
|
||||
{
|
||||
return ProductReviewResource::collection($product->reviews()->get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class VendorProfileController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
return response()->rest([
|
||||
'id' => $user->id,
|
||||
'first_name' => $user->first_name,
|
||||
'last_name' => $user->last_name,
|
||||
'email' => $user->email,
|
||||
'phone_number' => $user->phone_number,
|
||||
'email_verified_at' => $user->email_verified_at,
|
||||
'verified' => $user->verified,
|
||||
'options' => $user->options,
|
||||
'created_at' => $user->created_at,
|
||||
'updated_at' => $user->updated_at,
|
||||
'phone_number_verified_at' => $user->phone_number_verified_at,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur\Resources\Order;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class OrderIndexResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'status' => OrderStatus::formattedStatusFor($this->status),
|
||||
'shipping_method' => OrderShipping::formattedShippingMethod($this->shipping_method),
|
||||
'notes' => $this->notes,
|
||||
'delivery_time' => $this->delivery_time,
|
||||
'delivery_at' => $this->delivery_at,
|
||||
'region' => $this->region,
|
||||
'payment_type' => $this->paymentType?->name,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Entrepreneur\Resources\Order;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class OrderShowResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'status' => OrderStatus::formattedStatusFor($this->status),
|
||||
'shipping_method' => OrderShipping::formattedShippingMethod($this->shipping_method),
|
||||
'notes' => $this->notes,
|
||||
'delivery_time' => $this->delivery_time,
|
||||
'delivery_at' => $this->delivery_at,
|
||||
'region' => $this->region,
|
||||
'payment_type' => $this->paymentType?->name,
|
||||
'products' => $this->items->map(fn ($item) => [
|
||||
'quantity' => $item->quantity,
|
||||
'product' => [
|
||||
'id' => $item->product->id,
|
||||
'name' => $item->product->name,
|
||||
'price_amount' => $item->product->price_amount,
|
||||
'thumbnail' => $item->product->thumbnail('thumb150x150'),
|
||||
],
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
42
app/Http/Controllers/Api/V1/Favorite/FavoriteController.php
Normal file
42
app/Http/Controllers/Api/V1/Favorite/FavoriteController.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Favorite;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Favorite\Requests\FavoriteStoreRequest;
|
||||
use App\Http\Controllers\Api\V1\Favorite\Resources\FavoriteResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class FavoriteController extends Controller
|
||||
{
|
||||
/**
|
||||
* (*) User's favorite products (index)
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
FavoriteResource::collection(
|
||||
auth()->user()->favorites()->with(['product' => ['media', 'brand']])->get()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Store resource
|
||||
*/
|
||||
public function store(FavoriteStoreRequest $request): JsonResponse
|
||||
{
|
||||
$data = auth()->user()->favorites()->where('product_id', $request->product_id)->first();
|
||||
|
||||
$status = $data
|
||||
? $data->delete()
|
||||
: auth()->user()->favorites()->create([
|
||||
'user_id' => auth()->id(),
|
||||
'product_id' => $request->product_id,
|
||||
]);
|
||||
|
||||
return response()->rest(
|
||||
message: is_bool($status) ? 'Removed' : 'Added'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Favorite\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FavoriteStoreRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'product_id' => ['required', 'integer', 'exists:products,id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Favorite\Resources;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductResource;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class FavoriteResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'created_at' => $this->created_at,
|
||||
'product' => new ProductResource($this->whenLoaded('product')),
|
||||
];
|
||||
}
|
||||
}
|
||||
57
app/Http/Controllers/Api/V1/FilterParamsController.php
Normal file
57
app/Http/Controllers/Api/V1/FilterParamsController.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Shop\Product\Attribute;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class FilterParamsController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$category_id = (int) $request->category_id;
|
||||
|
||||
$attributes = Attribute::with('values:id,key,attribute_id,value')
|
||||
->where('is_enabled', true)
|
||||
->when($request->filled('category_id'), fn ($query) => $query->where('category_id', $category_id))
|
||||
->get(['id', 'slug', 'name', 'type', 'category_id', 'is_enabled']);
|
||||
|
||||
return [
|
||||
'brands' => $this->getBrands($request),
|
||||
'attributes' => $attributes->whereNotIn('slug', ['colour', 'size'])->flatten(1),
|
||||
'sizes' => $attributes->where('slug', 'size')->map(fn ($size_attribute) => [
|
||||
'attribute_id' => $size_attribute->id,
|
||||
'values' => $size_attribute->values,
|
||||
])->first(),
|
||||
'colours' => $attributes->where('slug', 'colour')->map(fn ($colour_attribute) => [
|
||||
'attribute_id' => $colour_attribute->id,
|
||||
'values' => $colour_attribute->values,
|
||||
])->first(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getBrands($request)
|
||||
{
|
||||
if ($request->filled('category_id')) {
|
||||
$category_id = (int) $request->category_id;
|
||||
|
||||
$brand_ids = DB::table('products')
|
||||
->join('product_has_relations', function ($join) use ($category_id) {
|
||||
$join->on('products.id', '=', 'product_has_relations.product_id')
|
||||
->where('product_has_relations.productable_id', '=', $category_id)
|
||||
->where('product_has_relations.productable_type', '=', 'category');
|
||||
})
|
||||
->select(['id', 'brand_id'])
|
||||
->pluck('brand_id');
|
||||
|
||||
return DB::table('brands')
|
||||
->where('is_enabled', true)
|
||||
->whereIn('id', $brand_ids)
|
||||
->get(['id', 'name']);
|
||||
}
|
||||
|
||||
return DB::table('brands')->where('is_enabled', true)->get(['id', 'name']);
|
||||
}
|
||||
}
|
||||
130
app/Http/Controllers/Api/V1/Filters/FilterController.php
Normal file
130
app/Http/Controllers/Api/V1/Filters/FilterController.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Filters;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Filters\Requests\FilterIndexRequest;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Ecommerce\Product\Brand\Brand;
|
||||
use App\Models\Ecommerce\Product\Category\Category;
|
||||
use App\Models\Ecommerce\Product\Collection\Collection;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class FilterController extends Controller
|
||||
{
|
||||
/**
|
||||
* Filter Controller
|
||||
*/
|
||||
public function __construct(
|
||||
protected Request $request
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Filters
|
||||
*/
|
||||
public function index(FilterIndexRequest $request): JsonResponse
|
||||
{
|
||||
return response()->rest([
|
||||
'categories' => $this->categories()->map(fn ($category) => [
|
||||
'id' => $category->id,
|
||||
'parent_id' => $category->parent_id,
|
||||
'name' => $category->name,
|
||||
]),
|
||||
'brands' => $this->brands(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Categories
|
||||
*/
|
||||
private function categories()
|
||||
{
|
||||
if ($this->shouldFilterByCategory()) {
|
||||
return Category::find($this->request->category_id, ['id', 'parent_id'])->children()->get(['id', 'parent_id', 'name']);
|
||||
}
|
||||
|
||||
if ($this->shouldFilterByCollection()) {
|
||||
return $this->filterByCategoryResource(Collection::find($this->request->collection_id));
|
||||
}
|
||||
|
||||
if ($this->shouldFilterByBrand()) {
|
||||
return $this->filterByCategoryResource(Brand::find($this->request->brand_id));
|
||||
}
|
||||
|
||||
return Category::query()->where('is_visible', true)->ordered()->get(['id', 'parent_id', 'name']);
|
||||
}
|
||||
|
||||
private function brands()
|
||||
{
|
||||
if ($this->shouldFilterByBrand()) {
|
||||
return Brand::where('id', $this->request->brand_id)->get(['id', 'name']);
|
||||
}
|
||||
|
||||
if ($this->shouldFilterByCategory()) {
|
||||
$brands = Category::find($this->request->category_id)->products()
|
||||
->where('products.is_visible', true)
|
||||
->where('products.parent_id', null)
|
||||
->where('products.stock', '>', 0)
|
||||
->distinct('products.brand_id')
|
||||
->pluck('products.brand_id');
|
||||
|
||||
return Brand::whereIntegerInRaw('id', $brands)->get(['id', 'name']);
|
||||
}
|
||||
|
||||
if ($this->shouldFilterByCollection()) {
|
||||
$brands = Collection::find($this->request->collection_id)->products()
|
||||
->where('products.is_visible', true)
|
||||
->where('products.parent_id', null)
|
||||
->where('products.stock', '>', 0)
|
||||
->distinct('products.brand_id')
|
||||
->pluck('products.brand_id');
|
||||
|
||||
return Brand::whereIntegerInRaw('id', $brands)->get(['id', 'name']);
|
||||
}
|
||||
|
||||
return Brand::query()->where('is_visible', true)->ordered()->get(['id', 'name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by category
|
||||
*/
|
||||
private function filterByCategoryResource($resource)
|
||||
{
|
||||
$products = $resource->products()
|
||||
->where('products.is_visible', true)
|
||||
->where('products.parent_id', null)
|
||||
->where('products.stock', '>', 0)
|
||||
->distinct('products.id')
|
||||
->pluck('products.id');
|
||||
|
||||
return Category::where('is_visible', true)->ordered()->join('product_has_relations', 'categories.id', '=', 'product_has_relations.productable_id')
|
||||
->where('product_has_relations.productable_type', '=', 'category')
|
||||
->whereIntegerInRaw('product_has_relations.product_id', $products)
|
||||
->get(['id', 'parent_id', 'name'])
|
||||
->unique('categories.id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if request should be filtered by category
|
||||
*/
|
||||
private function shouldFilterByCategory(): bool
|
||||
{
|
||||
return $this->request->filled('category_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if request should be filtered by collection
|
||||
*/
|
||||
private function shouldFilterByCollection(): bool
|
||||
{
|
||||
return $this->request->filled('collection_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if request should be filtered by brand
|
||||
*/
|
||||
private function shouldFilterByBrand(): bool
|
||||
{
|
||||
return $this->request->filled('brand_id');
|
||||
}
|
||||
}
|
||||
38
app/Http/Controllers/Api/V1/Filters/Helpers/BrandsFilter.php
Normal file
38
app/Http/Controllers/Api/V1/Filters/Helpers/BrandsFilter.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Filters\Helpers;
|
||||
|
||||
use Laravel\Nova\Makeable;
|
||||
|
||||
class BrandsFilter
|
||||
{
|
||||
use Makeable;
|
||||
|
||||
public function __construct(
|
||||
protected Builder $queryBuilder,
|
||||
protected Request $request,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Basic queries
|
||||
*/
|
||||
public function applyBaseQueries(): self
|
||||
{
|
||||
$this->queryBuilder->where('is_visible', true)->ordered();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get brands
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->queryBuilder->whereIntegerInRaw(
|
||||
column: 'id',
|
||||
values: $resource->products()->distinct('brand_id')->pluck('brand_id')
|
||||
)->get(['id', 'name']);
|
||||
|
||||
return $this->queryBuilder->get(['id', 'name']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Filters\Helpers;
|
||||
|
||||
use App\Models\Ecommerce\Product\Brand\Brand;
|
||||
use App\Models\Ecommerce\Product\Category\Category;
|
||||
use App\Models\Ecommerce\Product\Collection\Collection;
|
||||
use App\Repositories\Ecommerce\Filter\FilterParamRepository;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Makeable;
|
||||
|
||||
class CategoriesFilter
|
||||
{
|
||||
use Makeable;
|
||||
|
||||
/**
|
||||
* Request object to work with
|
||||
*/
|
||||
protected Request $request;
|
||||
|
||||
/**
|
||||
* Request object to work with
|
||||
*/
|
||||
protected Builder $queryBuilder;
|
||||
|
||||
/**
|
||||
* Filter repo
|
||||
*/
|
||||
protected FilterParamRepository $filterRepository;
|
||||
|
||||
/**
|
||||
* Table columns to get
|
||||
*/
|
||||
protected array $columns = [
|
||||
'id',
|
||||
'parent_id',
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Categories for filtering
|
||||
*/
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->queryBuilder = config('ecommerce.models.category')::query();
|
||||
$this->filterRepository = FilterParamRepository::make($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic queries
|
||||
*/
|
||||
public function applyBaseQueries(): self
|
||||
{
|
||||
$this->queryBuilder->enabled()->ordered();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all categories
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
if ($this->filterRepository->shouldFilterByCategory()) {
|
||||
return Category::find($this->request->category_id, ['id', 'parent_id'])->children()->get($this->columns);
|
||||
}
|
||||
|
||||
if ($this->filterRepository->shouldFilterByCollection()) {
|
||||
return $this->byResource(Collection::find($this->request->collection_id));
|
||||
}
|
||||
|
||||
if ($this->filterRepository->shouldFilterByBrand()) {
|
||||
return $this->byResource(Brand::find($this->request->brand_id));
|
||||
}
|
||||
|
||||
return $this->queryBuilder->get($this->columns);
|
||||
}
|
||||
|
||||
public function byResource($resource)
|
||||
{
|
||||
$products = $resource->products()
|
||||
->where('products.is_visible', true)
|
||||
->where('products.parent_id', null)
|
||||
->where('products.stock', '>', 0)
|
||||
->distinct('products.id')
|
||||
->pluck('products.id');
|
||||
|
||||
return $this->queryBuilder->join('product_has_relations', 'categories.id', '=', 'product_has_relations.productable_id')
|
||||
->where('product_has_relations.productable_type', '=', 'category')
|
||||
->whereIntegerInRaw('product_has_relations.product_id', $products)
|
||||
->get($this->columns)
|
||||
->unique('categories.id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Filters\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FilterIndexRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'collection_id' => ['bail', 'nullable', 'int', 'exists:collections,id'],
|
||||
'category_id' => ['bail', 'nullable', 'int', 'exists:categories,id'],
|
||||
'brand_id' => ['bail', 'nullable', 'int', 'exists:brands,id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
34
app/Http/Controllers/Api/V1/Legal/LegalPageController.php
Normal file
34
app/Http/Controllers/Api/V1/Legal/LegalPageController.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Legal;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\V1\Legal\LegalPageResource;
|
||||
use App\Models\Legal\LegalPage;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class LegalPageController extends Controller
|
||||
{
|
||||
/**
|
||||
* (Legal) Legal pages
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
LegalPage::where('is_active', true)
|
||||
->get(['slug', 'title'])
|
||||
->map(fn ($legalPage) => [
|
||||
'slug' => $legalPage->slug,
|
||||
'title' => $legalPage->title,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (Legal) Legal pages
|
||||
*/
|
||||
public function show(LegalPage $legalPage): JsonResponse
|
||||
{
|
||||
return response()->rest(new LegalPageResource($legalPage));
|
||||
}
|
||||
}
|
||||
42
app/Http/Controllers/Api/V1/LegalPagesController.php
Normal file
42
app/Http/Controllers/Api/V1/LegalPagesController.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Legal\LegalPage;
|
||||
|
||||
class LegalPagesController extends Controller
|
||||
{
|
||||
public function refundPolicy()
|
||||
{
|
||||
return response()->rest(
|
||||
LegalPage::where('slug', 'refund-policy')->first(['title', 'content'])
|
||||
);
|
||||
}
|
||||
|
||||
public function privacyPolicy()
|
||||
{
|
||||
return response()->rest(
|
||||
LegalPage::where('slug', 'privacy-policy')->first(['title', 'content'])
|
||||
);
|
||||
}
|
||||
|
||||
public function termsOfUse()
|
||||
{
|
||||
return response()->rest(
|
||||
LegalPage::where('slug', 'terms-of-use')->first(['title', 'content'])
|
||||
);
|
||||
}
|
||||
|
||||
public function shippingPolicy()
|
||||
{
|
||||
return response()->rest(
|
||||
LegalPage::where('slug', 'shipping-policy')->first(['title', 'content'])
|
||||
);
|
||||
}
|
||||
|
||||
public function paymentTypeNotAvailable()
|
||||
{
|
||||
return 'Töleg görnüşi elýeter däl';
|
||||
}
|
||||
}
|
||||
69
app/Http/Controllers/Api/V1/LikeController.php
Normal file
69
app/Http/Controllers/Api/V1/LikeController.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Products\ProductResource;
|
||||
use App\Models\Shop\Product\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Maize\Markable\Models\Like;
|
||||
|
||||
class LikeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return response()->rest_paginate(ProductResource::collection(
|
||||
Product::with(['media', 'brand'])->whereHasLike(auth()->user())->paginate(15)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'product_id' => ['required', 'integer', 'exists:products,id'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
$product = Product::find($request->product_id);
|
||||
|
||||
Like::add($product, auth()->user());
|
||||
|
||||
return response()->rest([], 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'product_id' => ['required', 'integer', 'exists:products,id'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest([], 400, 'Wrong credentials');
|
||||
}
|
||||
|
||||
$product = Product::find($request->product_id);
|
||||
Like::remove($product, auth()->user());
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
}
|
||||
30
app/Http/Controllers/Api/V1/LinkController.php
Normal file
30
app/Http/Controllers/Api/V1/LinkController.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class LinkController extends Controller
|
||||
{
|
||||
public function product(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'id' => ['required', 'integer'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->rest($validator->messages()->get('*'), 400, 'Validator fail');
|
||||
}
|
||||
|
||||
$product = DB::table('products')->where('id', $request->id)->pluck('slug', 'id');
|
||||
|
||||
if ($product->isEmpty()) {
|
||||
return to_route('web.products.show', ['product' => 1]);
|
||||
}
|
||||
|
||||
return to_route('web.products.show', ['product' => $product->first()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Forms\Newsletter\NewsletterSubscriptionStoreRequest;
|
||||
use App\Models\CMS\Marketing\NewsletterUser;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class NewsletterSubscriptionController extends Controller
|
||||
{
|
||||
/**
|
||||
* (Marketing) Subscribe to newsletter
|
||||
*/
|
||||
public function store(NewsletterSubscriptionStoreRequest $request): JsonResponse
|
||||
{
|
||||
NewsletterUser::insertOrIgnore($request->validated());
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
}
|
||||
132
app/Http/Controllers/Api/V1/OnlinePaymentController.php
Normal file
132
app/Http/Controllers/Api/V1/OnlinePaymentController.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Api\Services\Payment\HalkbankPaymentService;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Shop\Order\Order;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class OnlinePaymentController extends Controller
|
||||
{
|
||||
public function halkbank(Request $request)
|
||||
{
|
||||
$formData = $request->validate([
|
||||
'pan' => ['required', 'integer', 'digits:16'],
|
||||
'month' => ['required', 'integer', 'between:1,12'],
|
||||
'year' => ['required', 'integer', 'min:2022', 'max:2066'],
|
||||
'name' => ['required', 'string'],
|
||||
'cvc' => ['required'],
|
||||
'order_id' => ['required', 'integer', 'exists:orders,id'],
|
||||
]);
|
||||
|
||||
return route('payment-not-available');
|
||||
|
||||
$order = Order::find($request->order_id);
|
||||
|
||||
$halkbank = new HalkbankPaymentService(
|
||||
amount: (string) $order->fullPriceWithShipping().'00',
|
||||
returnURL: route('web.order.check.halkbank', ['id' => $order->id])
|
||||
);
|
||||
|
||||
$halkbank->orderTicket();
|
||||
|
||||
$app_name = 'POSTSHOP';
|
||||
$app_id = Str::random(16);
|
||||
|
||||
// Wagtyny kesgitlemek
|
||||
$response_start_hack = Http::asForm()->post('http://localhost:9090/api/v1/start-hack', [
|
||||
'app' => $app_name,
|
||||
'id' => $app_id,
|
||||
'url' => $halkbank->paymentPageUrl(),
|
||||
]);
|
||||
|
||||
Log::info(['hack' => $response_start_hack->json()]);
|
||||
|
||||
if (! ($response_start_hack && array_key_exists('status', $response_start_hack->json()) && $response_start_hack['status'] == 'ok')) {
|
||||
return response()->rest([$response_start_hack->body()]);
|
||||
}
|
||||
|
||||
$ok = (string) $request->cvc;
|
||||
|
||||
$cvc = match (strlen($ok)) {
|
||||
1 => '00'.$ok,
|
||||
2 => '0'.$ok,
|
||||
default => $ok
|
||||
};
|
||||
|
||||
$response_submit_card = Http::asForm()->post('http://localhost:9090/api/v1/submit-card', [
|
||||
'app' => $app_name,
|
||||
'id' => $app_id,
|
||||
'md-order' => $halkbank->ticketOrderId(),
|
||||
'card-number' => $request->pan,
|
||||
'card-expiry' => $request->year.$request->month,
|
||||
'name-on-card' => $request->name,
|
||||
'card-cvc' => $cvc,
|
||||
]);
|
||||
|
||||
Log::info(['submit_card' => $response_submit_card->json()]);
|
||||
|
||||
if (! ($response_submit_card && array_key_exists('status', $response_submit_card->json()) && $response_submit_card['status'] == 'ok')) {
|
||||
return response()->rest([$response_submit_card->body()]);
|
||||
}
|
||||
|
||||
return response()->rest([
|
||||
'order_id' => $order->id,
|
||||
'ticket_order_id' => $halkbank->ticketOrderId(),
|
||||
'url' => $response_submit_card['acs-session-url'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function checkPayment(Request $request)
|
||||
{
|
||||
$request->validate(['order_id' => 'required|integer|exists:orders,id', 'ticket_order_id' => 'required|string']);
|
||||
|
||||
$payment_status = HalkbankPaymentService::checkPayment($request->ticket_order_id);
|
||||
if ($payment_status) {
|
||||
Order::find($request->order_id)->markAsPaid();
|
||||
}
|
||||
|
||||
return response()->rest([
|
||||
'payment_status' => $payment_status,
|
||||
]);
|
||||
}
|
||||
|
||||
public function halkbankVerifyOTP(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'order_id' => ['required', 'integer', 'exists:orders,id'],
|
||||
'request_id' => ['required'],
|
||||
'sms_code' => ['required', 'integer'],
|
||||
]);
|
||||
|
||||
$response = HalkbankPaymentService::sendSMSVerificationCode(
|
||||
request_id: $request->request_id,
|
||||
sms_code: $request->sms_code
|
||||
);
|
||||
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadHTML($response->body());
|
||||
|
||||
$inputs = $doc->getElementsByTagName('input');
|
||||
|
||||
if (count($inputs) > 0) {
|
||||
$md = $inputs[0]->getAttribute('value');
|
||||
$paRes = $inputs[1]->getAttribute('value');
|
||||
}
|
||||
|
||||
if ($md && $paRes) {
|
||||
$response_3d = Http::asForm()->post('https://mpi.gov.tm:443/payment/rest/finish3ds.do', [
|
||||
'MD' => $md,
|
||||
'PaRes' => $paRes,
|
||||
]);
|
||||
|
||||
Log::info('3d', [$response_3d->body()]);
|
||||
}
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
}
|
||||
24
app/Http/Controllers/Api/V1/Order/OrderPaymentController.php
Normal file
24
app/Http/Controllers/Api/V1/Order/OrderPaymentController.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Order;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\System\Settings\Payments\PaymentType;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class OrderPaymentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Order payment types
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
PaymentType::all(['id', 'name'])
|
||||
->map(fn ($paymentType) => [
|
||||
'id' => $paymentType->id,
|
||||
'name' => $paymentType->name,
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
90
app/Http/Controllers/Api/V1/OrderController.php
Normal file
90
app/Http/Controllers/Api/V1/OrderController.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\CheckoutOrderRequest;
|
||||
use App\Http\Resources\Api\V1\Order\OrderIndexResource;
|
||||
use App\Models\Ecommerce\Product\Order\Order;
|
||||
use App\Repositories\Ecommerce\Order\OrderRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
/**
|
||||
* (*) User's orders
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
OrderIndexResource::collection(
|
||||
auth()->user()->orders()->with(['items', 'items.product', 'paymentType'])->latest()->paginate(20)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Return available times to make an order
|
||||
*/
|
||||
public function time(): JsonResponse
|
||||
{
|
||||
return response()->rest(OrderRepository::availableTimes());
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Store order
|
||||
*/
|
||||
public function store(CheckoutOrderRequest $request): JsonResponse
|
||||
{
|
||||
$order = (new OrderRepository($request->all()))->create();
|
||||
|
||||
$url = null;
|
||||
if ($request->payment_type_id == 3) {
|
||||
$response = createHalkbankOrder();
|
||||
|
||||
if ($response['status'] == 'success') {
|
||||
$url = $response['url'];
|
||||
}
|
||||
}
|
||||
|
||||
return response()->rest([
|
||||
'order_id' => $order->id,
|
||||
'payment_url' => $url
|
||||
], 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Show order
|
||||
*/
|
||||
public function show(Order $order): JsonResponse
|
||||
{
|
||||
$order->load(['items', 'items.product', 'paymentType']);
|
||||
|
||||
return response()->rest(new OrderIndexResource($order));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, Order $order): JsonResponse
|
||||
{
|
||||
// $order-.
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
return response()->rest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\PostBranch;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Post\PostBranch;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PostBranchController extends Controller
|
||||
{
|
||||
/**
|
||||
* All post branches
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
PostBranch::query()
|
||||
->get()
|
||||
->map(fn ($postBranch) => [
|
||||
'id' => $postBranch->id,
|
||||
'province_id' => $postBranch->province_id,
|
||||
'name' => $postBranch->name,
|
||||
'address' => $postBranch->address,
|
||||
'description' => $postBranch->description,
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Barcode;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Barcode\Requests\ProductBarcodeSearchIndexRequest;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class ProductBarcodeSearchController extends Controller
|
||||
{
|
||||
/**
|
||||
* Search product via barcode
|
||||
*/
|
||||
public function index(ProductBarcodeSearchIndexRequest $request): JsonResponse
|
||||
{
|
||||
$product = Product::where('barcode', $request->barcode)->with('media')->first();
|
||||
|
||||
return response()->rest([
|
||||
'id' => $product->id,
|
||||
'name' => $product->name,
|
||||
'stock' => $product->stock,
|
||||
'price_amount' => $product->price_amount,
|
||||
'image' => [
|
||||
'thumbnail' => $product->thumbnail(),
|
||||
'images_400x400' => $product->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb400x400')),
|
||||
'images_720x720' => $product->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb720x720')),
|
||||
'images_800x800' => $product->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb800x800')),
|
||||
'images_1200x1200' => $product->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb1200x1200')),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Barcode\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ProductBarcodeSearchIndexRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'barcode' => ['required', 'string', 'max:255', 'exists:products,barcode'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Product\ProductCommentStore;
|
||||
use App\Http\Resources\Api\V1\Common\CommentResource;
|
||||
use App\Models\Common\Comment;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductCommentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Product's comments
|
||||
*/
|
||||
public function index(Request $request, Product $product): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
CommentResource::collection(
|
||||
$product->comments()->with('user')->where('active', true)->get()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store
|
||||
*/
|
||||
public function store(ProductCommentStore $request, Product $product): JsonResponse
|
||||
{
|
||||
$product->comments()->create([
|
||||
'comment' => $request->comment,
|
||||
'user_id' => auth()->id(),
|
||||
]);
|
||||
|
||||
return response()->rest(message: 'Comment added successfully', code: 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the comment from product
|
||||
*/
|
||||
public function destroy(Product $product, Comment $comment): JsonResponse
|
||||
{
|
||||
$product->comments()->where('comments.id', $comment->id)->delete();
|
||||
|
||||
return response()->rest(message: 'Comment removed successfully from product', code: 204);
|
||||
}
|
||||
}
|
||||
52
app/Http/Controllers/Api/V1/Product/ProductController.php
Normal file
52
app/Http/Controllers/Api/V1/Product/ProductController.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductIndexResource;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductShowResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Product\ProductIndexRequest;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
/**
|
||||
* Products (index)
|
||||
*/
|
||||
public function index(ProductIndexRequest $request): JsonResponse
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
ProductIndexResource::collection(
|
||||
ProductRepository::make($request)
|
||||
->applyBasicQueries()
|
||||
->applyFilters()
|
||||
->applySorting()
|
||||
->simplePaginate()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Products (show)
|
||||
*/
|
||||
public function show(Product $product): JsonResponse
|
||||
{
|
||||
$product->load([
|
||||
'channels:id,name',
|
||||
'properties',
|
||||
'media' => function ($query) {
|
||||
$query->orderBy('order_column', 'asc');
|
||||
},
|
||||
'variations' => [
|
||||
'media',
|
||||
'properties',
|
||||
],
|
||||
'reviews',
|
||||
'categories:id,name',
|
||||
]);
|
||||
|
||||
return response()->rest(new ProductShowResource($product));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ProductRelatedController extends Controller
|
||||
{
|
||||
/**
|
||||
* Related products (index)
|
||||
*/
|
||||
public function index(Product $product): JsonResponse
|
||||
{
|
||||
$products = DB::table('product_has_relations')
|
||||
->select('product_has_relations.product_id')
|
||||
->whereIn('product_has_relations.productable_id', (function ($query) use ($product) {
|
||||
$query->from('product_has_relations')
|
||||
->select('productable_id')
|
||||
->distinct('productable_id')
|
||||
->where('productable_type', '=', 'category')
|
||||
->where('product_id', '=', $product->id);
|
||||
}))
|
||||
->limit(12)
|
||||
->orderByRaw('RANDOM()')
|
||||
->pluck('product_has_relations.product_id')
|
||||
->unique();
|
||||
|
||||
return response()->rest(
|
||||
ProductResource::collection(
|
||||
ProductRepository::make(request())
|
||||
->applyBasicQueries()
|
||||
->whereIntegerInRaw('id', $products->toArray())
|
||||
->get()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\Review\ProductReviewResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Product\Review\ProductReviewStore;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class ProductReviewController extends Controller
|
||||
{
|
||||
/**
|
||||
* Product reviews (index)
|
||||
*/
|
||||
public function index(Product $product): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
ProductReviewResource::collection(
|
||||
$product->reviews()
|
||||
->where('is_visible', true)
|
||||
->orderBy('is_recommended')
|
||||
->get()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Product reviews (store)
|
||||
*/
|
||||
public function store(ProductReviewStore $request, Product $product): JsonResponse
|
||||
{
|
||||
$product->reviews()->create([
|
||||
'user_id' => auth()->id(),
|
||||
...$request->validated(),
|
||||
]);
|
||||
|
||||
return response()->rest(message: 'Review added successfully', code: 201);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Resources\Attribute;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductAttributeProductShowResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'attribute_id' => $this->attribute->id,
|
||||
'name' => $this->attribute->name,
|
||||
'value' => $this->values->map(fn ($val) => $val->real_value)->first(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Resources\Attribute;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductAttributeResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'attribute_id' => $this->attribute->id,
|
||||
'name' => $this->attribute->name,
|
||||
'value' => $this->values->map(fn ($val) => $val->real_value)->first(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Resources;
|
||||
|
||||
use App\Http\Resources\MediaResource;
|
||||
use App\Repositories\Ecommerce\Product\Property\PropertyRepository;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductIndexResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
$reviews = $this->whenLoaded('reviews');
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'parent_id' => $this->parent_id,
|
||||
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
'description' => '',
|
||||
|
||||
'sku' => $this->sku,
|
||||
'barcode' => $this->barcode,
|
||||
'stock' => $this->stock,
|
||||
|
||||
'price_amount' => $this->price_amount,
|
||||
'old_price_amount' => $this->old_price_amount,
|
||||
|
||||
'backorder' => $this->backorder,
|
||||
'weight_value' => $this->weight_value,
|
||||
'weight_unit' => $this->weight_unit,
|
||||
'height_value' => $this->height_value,
|
||||
'height_unit' => $this->height_unit,
|
||||
|
||||
'media' => MediaResource::collection($this->whenLoaded('media')),
|
||||
|
||||
'created_at' => $this->created_at,
|
||||
|
||||
'seo_title' => $this->seo_title,
|
||||
'seo_description' => $this->seo_description,
|
||||
|
||||
'colour' => PropertyRepository::getRealValue('colour', $this->colour),
|
||||
'size' => PropertyRepository::getRealValue('size', $this->size),
|
||||
|
||||
'brand' => [
|
||||
'id' => $this->brand_id,
|
||||
'name' => $this->brand?->name,
|
||||
],
|
||||
|
||||
'reviews' => [
|
||||
'count' => $reviews ? $reviews->count() : 0,
|
||||
'rating' => $reviews ? number_format($reviews->avg('rating'), 2) : 0,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductMediaResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'thumbnail' => $this->getUrl('thumb288x431'),
|
||||
'images_400x400' => $this->getUrl('thumb400x400'),
|
||||
'images_720x720' => $this->getUrl('thumb720x720'),
|
||||
'images_800x800' => $this->getUrl('thumb800x800'),
|
||||
'images_1200x1200' => $this->getUrl('thumb1200x1200'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Resources;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\Attribute\ProductAttributeProductShowResource;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\Variant\ProductVariantResource;
|
||||
use App\Http\Resources\Api\V1\Channel\ChannelResource;
|
||||
use App\Repositories\Ecommerce\Product\Property\PropertyRepository;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
$media = $this->whenLoaded('media');
|
||||
$reviews = $this->whenLoaded('reviews');
|
||||
|
||||
$reviewsLoaded = get_class($reviews) !== 'Illuminate\\Http\\Resources\\MissingValue';
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'parent_id' => $this->parent_id,
|
||||
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
'description' => $this->description,
|
||||
|
||||
'sku' => $this->sku,
|
||||
'barcode' => $this->barcode,
|
||||
'stock' => $this->stock,
|
||||
|
||||
'price_amount' => $this->price_amount,
|
||||
'old_price_amount' => $this->old_price_amount,
|
||||
|
||||
'backorder' => $this->backorder,
|
||||
'weight_value' => $this->weight_value,
|
||||
'weight_unit' => $this->weight_unit,
|
||||
'height_value' => $this->height_value,
|
||||
'height_unit' => $this->height_unit,
|
||||
|
||||
'media' => ProductMediaResource::collection($media),
|
||||
|
||||
'created_at' => $this->created_at,
|
||||
|
||||
'seo_title' => $this->seo_title,
|
||||
'seo_description' => $this->seo_description,
|
||||
|
||||
'is_visible' => $this->is_visible,
|
||||
|
||||
'colour' => PropertyRepository::getRealValue('colour', $this->colour),
|
||||
'size' => PropertyRepository::getRealValue('size', $this->size),
|
||||
|
||||
'brand' => [
|
||||
'id' => $this->brand_id,
|
||||
'name' => $this->brand?->name,
|
||||
],
|
||||
|
||||
'channel' => ChannelResource::collection($this->whenLoaded('channels')),
|
||||
|
||||
'properties' => ProductAttributeProductShowResource::collection($this->whenLoaded('properties')),
|
||||
'variations' => ProductVariantResource::collection($this->whenLoaded('variations')),
|
||||
|
||||
'reviews' => [
|
||||
'count' => $reviewsLoaded ? $reviews->count() : 0,
|
||||
'rating' => $reviewsLoaded ? number_format($reviews->avg('rating'), 2) : '',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Resources;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\Attribute\ProductAttributeProductShowResource;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\Review\ProductReviewResource;
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\Variant\ProductVariantResource;
|
||||
use App\Http\Resources\Api\V1\Channel\ChannelResource;
|
||||
use App\Http\Resources\MediaResource;
|
||||
use App\Repositories\Ecommerce\Product\Property\PropertyRepository;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductShowResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
$reviews = $this->whenLoaded('reviews');
|
||||
$categories = $this->whenLoaded('categories');
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'parent_id' => $this->parent_id,
|
||||
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
'description' => $this->description,
|
||||
|
||||
'sku' => $this->sku,
|
||||
'barcode' => $this->barcode,
|
||||
'stock' => $this->stock,
|
||||
|
||||
'price_amount' => $this->price_amount,
|
||||
'old_price_amount' => $this->old_price_amount,
|
||||
|
||||
'backorder' => $this->backorder ? 'true' : 'false',
|
||||
'weight_value' => $this->weight_value,
|
||||
'weight_unit' => $this->weight_unit,
|
||||
'height_value' => $this->height_value,
|
||||
'height_unit' => $this->height_unit,
|
||||
|
||||
'media' => MediaResource::collection($this->whenLoaded('media')),
|
||||
|
||||
'created_at' => $this->created_at,
|
||||
|
||||
'seo_title' => $this->seo_title,
|
||||
'seo_description' => $this->seo_description,
|
||||
|
||||
'colour' => PropertyRepository::getRealValue('colour', $this->colour),
|
||||
'size' => PropertyRepository::getRealValue('size', $this->size),
|
||||
|
||||
'available_colors' => PropertyRepository::getAvailableColors($this),
|
||||
'available_sizes' => PropertyRepository::getAvailableSizes($this),
|
||||
|
||||
'brand' => [
|
||||
'id' => $this->brand_id,
|
||||
'name' => $this->brand?->name,
|
||||
],
|
||||
|
||||
'channel' => ChannelResource::collection($this->whenLoaded('channels')),
|
||||
|
||||
'properties' => ProductAttributeProductShowResource::collection($this->whenLoaded('properties')),
|
||||
'variations' => ProductVariantResource::collection($this->whenLoaded('variations')),
|
||||
'reviews' => [
|
||||
'count' => $reviews ? $reviews->count() : 0,
|
||||
'rating' => $reviews ? number_format($reviews->avg('rating'), 2) : 0,
|
||||
],
|
||||
|
||||
'reviews_resources' => ProductReviewResource::collection($this->whenLoaded('reviews')),
|
||||
|
||||
$this->mergeWhen($categories, [
|
||||
'categories' => $categories->map(fn ($category) => [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
]),
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Resources\Review;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductReviewResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'user_id' => $this->user_id,
|
||||
'product_id' => $this->product_id,
|
||||
'rating' => $this->rating,
|
||||
'title' => $this->title,
|
||||
'content' => $this->content,
|
||||
'is_recommended' => $this->is_recommended,
|
||||
'source' => $this->source,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Resources\Variant;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\Attribute\ProductAttributeResource;
|
||||
use App\Repositories\Ecommerce\Product\Property\PropertyRepository;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductVariantResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'parent_id' => $this->parent_id,
|
||||
|
||||
'name' => $this->name,
|
||||
'slug' => $this->slug,
|
||||
'description' => $this->description,
|
||||
|
||||
'sku' => $this->sku,
|
||||
'barcode' => $this->barcode,
|
||||
'stock' => $this->stock,
|
||||
|
||||
'cost_amount' => $this->cost_amount,
|
||||
'price_amount' => $this->price_amount,
|
||||
'old_price_amount' => $this->old_price_amount,
|
||||
|
||||
'backorder' => $this->backorder,
|
||||
'weight_value' => $this->weight_value,
|
||||
'weight_unit' => $this->weight_unit,
|
||||
'height_value' => $this->height_value,
|
||||
'height_unit' => $this->height_unit,
|
||||
|
||||
'colour' => PropertyRepository::getRealValue('colour', $this->colour),
|
||||
'size' => PropertyRepository::getRealValue('size', $this->size),
|
||||
|
||||
'thumbnail' => $this->thumbnail(),
|
||||
'images_400x400' => $this->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb400x400')),
|
||||
'images_800x800' => $this->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb800x800')),
|
||||
'images_1200x1200' => $this->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb1200x1200')),
|
||||
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
|
||||
'properties' => ProductAttributeResource::collection($this->whenLoaded('properties')),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Product\Search;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Product\Resources\ProductMediaResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductSearchController extends Controller
|
||||
{
|
||||
/**
|
||||
* Search product via barcode
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'q' => ['required', 'string', 'max:255'],
|
||||
]);
|
||||
|
||||
$searchQuery = $request->input('q');
|
||||
|
||||
$products = Product::with(['brand', 'media'])
|
||||
->where(function ($query) use ($searchQuery) {
|
||||
if (is_numeric($searchQuery)) {
|
||||
$query->where('products.id', intval($searchQuery));
|
||||
}
|
||||
|
||||
$query
|
||||
->orWhere('products.name', '~*', $searchQuery)
|
||||
->orWhere('products.sku', '~*', $searchQuery)
|
||||
->orWhere('products.barcode', '~*', $searchQuery);
|
||||
})
|
||||
->when($request->isNotFilled('internal'), function ($query) {
|
||||
$query->where('products.is_visible', true)
|
||||
->where('products.parent_id', null)
|
||||
->where('products.stock', '>', 0);
|
||||
})
|
||||
->limit(40)
|
||||
->get();
|
||||
|
||||
return response()->rest(
|
||||
$products->map(fn ($product) => [
|
||||
'id' => $product->id,
|
||||
'name' => $product->fullName,
|
||||
'stock' => $product->stock,
|
||||
'cost_amount' => $product->cost_amount,
|
||||
'price_amount' => $product->price_amount,
|
||||
'brand' => [
|
||||
'id' => $product->brand?->id,
|
||||
'name' => $product->brand?->name,
|
||||
],
|
||||
'thumbnail' => $product->thumbnail(),
|
||||
'media' => ProductMediaResource::collection($product->media),
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
47
app/Http/Controllers/Api/V1/Profile/ProfileController.php
Normal file
47
app/Http/Controllers/Api/V1/Profile/ProfileController.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Profile;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
/**
|
||||
* Users profile
|
||||
*/
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
return response()->rest([
|
||||
'first_name' => $user->first_name,
|
||||
'last_name' => $user->last_name,
|
||||
'phone_number' => $user->phone_number,
|
||||
'address' => $user->options->get('address'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'phone_number' => ['required', 'int', 'between:61000000,71999999', Rule::unique('users', 'phone_number')->ignore(auth()->id())],
|
||||
'address' => ['required', 'string', 'max:255'],
|
||||
]);
|
||||
|
||||
auth()->user()->update([
|
||||
'first_name' => $request->name,
|
||||
'phone_number' => $request->phone_number,
|
||||
]);
|
||||
|
||||
auth()->user()->options->set('address', $request->address);
|
||||
|
||||
return response()->rest();
|
||||
}
|
||||
}
|
||||
26
app/Http/Controllers/Api/V1/Province/ProvinceController.php
Normal file
26
app/Http/Controllers/Api/V1/Province/ProvinceController.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Province;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\System\Settings\Location\Province;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProvinceController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get provinces
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
Province::query()
|
||||
->get()
|
||||
->map(fn ($province) => [
|
||||
'id' => $province->id,
|
||||
'region' => $province->region,
|
||||
'name' => $province->name,
|
||||
]));
|
||||
}
|
||||
}
|
||||
45
app/Http/Controllers/Api/V1/ReviewController.php
Normal file
45
app/Http/Controllers/Api/V1/ReviewController.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Reviews\Resources\ReviewResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\V1\Product\Review\ProductReviewUpdate;
|
||||
use App\Models\Ecommerce\Product\Review\Review;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ReviewController extends Controller
|
||||
{
|
||||
/**
|
||||
* (*) User's reviews
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
return response()->rest_paginate(
|
||||
ReviewResource::collection(
|
||||
auth()->user()->reviews()->with(['product', 'product.brand'])->simplePaginate($request->perPage ?: 10)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Update review
|
||||
*/
|
||||
public function update(ProductReviewUpdate $request, Review $review): JsonResponse
|
||||
{
|
||||
$review->update($request->validated());
|
||||
|
||||
return response()->rest(message: 'Review updated successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Destroy the comment from product
|
||||
*/
|
||||
public function destroy(Review $review): JsonResponse
|
||||
{
|
||||
$review->delete();
|
||||
|
||||
return response()->rest(message: 'Review deleted successfully');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Reviews\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ReviewResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'product' => $this->when($this->relationLoaded('product'), [
|
||||
'id' => $this->product->id,
|
||||
'name' => $this->product->name,
|
||||
'barcode' => $this->product->barcode,
|
||||
'price_amount' => $this->product->price_amount,
|
||||
'brand' => [
|
||||
'id' => $this->product->brand_id,
|
||||
'name' => $this->product->brand?->name,
|
||||
],
|
||||
]),
|
||||
'rating' => $this->rating,
|
||||
'title' => $this->title,
|
||||
'content' => $this->content,
|
||||
'is_recommended' => $this->is_recommended,
|
||||
'updated_at' => $this->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user