Compare commits
43 Commits
de1d7fbed8
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e98841eea | |||
| 2b8f9aa314 | |||
| cb63c54c39 | |||
| b7bc192e6f | |||
| 06617a0005 | |||
| da2645fae9 | |||
| 066f4d6a53 | |||
|
|
1e84ceab3c | ||
|
|
a8599d9c79 | ||
|
|
78ef14b99b | ||
|
|
1a63c52106 | ||
|
|
75a6af68eb | ||
|
|
58c1915413 | ||
|
|
ba537b7868 | ||
|
|
bf69d6733b | ||
|
|
9107d3118d | ||
|
|
fac624b2a5 | ||
|
|
9071c9a4c6 | ||
|
|
18e510674a | ||
|
|
073bbd497b | ||
|
|
ab3e69e831 | ||
|
|
18401b908f | ||
|
|
c712fa07ba | ||
|
|
f011da72d9 | ||
|
|
4a0e24683a | ||
|
|
49ef491e80 | ||
|
|
1880a167b3 | ||
|
|
ec33006984 | ||
|
|
147e7b9516 | ||
|
|
e70ec773f9 | ||
|
|
e2adf5e9da | ||
|
|
d3ac6ff8d9 | ||
|
|
b0c6a4236c | ||
|
|
9fac84a882 | ||
|
|
8f49fe0124 | ||
|
|
43272bb1b1 | ||
|
|
c48ad83548 | ||
|
|
b4a05e3f8c | ||
|
|
bac1579285 | ||
|
|
41d6ddc346 | ||
|
|
522ebdae34 | ||
|
|
683fa5e0d9 | ||
|
|
d83bc03258 |
@@ -7,6 +7,8 @@ APP_URL=http://localhost
|
||||
API_TOKEN=123
|
||||
NOVA_LICENSE_KEY=UEkhFwqhhYw2UPqcoVNWWhKrZOOWXujgj7pLPdDzMqflYX4Pwl
|
||||
|
||||
DEBUGBAR_ENABLED=false
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Install posgres and configure
|
||||
sudo su - postgres
|
||||
psql
|
||||
CREATE USER postshop WITH PASSWORD 'ACvL2(F@H^F)D7gs';
|
||||
CREATE USER postshop WITH PASSWORD 'HRbuBNRBaTPeUfbcFf9XHWay';
|
||||
CREATE DATABASE postshopdb WITH OWNER = postshop LC_COLLATE = 'en_US.UTF-8' TEMPLATE template0;
|
||||
|
||||
# Clone
|
||||
|
||||
@@ -18,6 +18,9 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
// Remove non saved attachments...
|
||||
$schedule->call(new PruneStaleAttachments)->daily();
|
||||
|
||||
// IF any warnings unresolved warnings exists, send notify me
|
||||
$schedule->call(new WarnDev)->dailyAt('16:00');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
25
app/Console/WarnDev.php
Normal file
25
app/Console/WarnDev.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Models\System\Warning;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class WarnDev extends Command
|
||||
{
|
||||
/**
|
||||
* Notify me if any unresolved warnings exists
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __invoke()
|
||||
{
|
||||
$warnings = Warning::whereNull('resolved_at')->get();
|
||||
|
||||
if ($warnings->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendSMS('61929248', 'Warnings: '.$warnings->count());
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
@@ -29,5 +31,25 @@ class Handler extends ExceptionHandler
|
||||
return response()->noContent(404);
|
||||
}
|
||||
});
|
||||
|
||||
$this->reportable(function (Throwable $e) {
|
||||
$statusCode = $e instanceof HttpException ? $e->getStatusCode() : 500;
|
||||
|
||||
// only real server errors
|
||||
if ($statusCode < 500) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
warn(
|
||||
message: get_class($e),
|
||||
content: $e->getMessage(),
|
||||
where: $e->getFile().':'.$e->getLine(),
|
||||
notes: substr($e->getTraceAsString(), 0, 65000),
|
||||
);
|
||||
} catch (Throwable $ignored) {
|
||||
// logging must never crash the app
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,11 +81,10 @@ class ProductFilterer
|
||||
$this->queryBuilder->whereIn(
|
||||
column: 'id',
|
||||
values: (
|
||||
fn ($query) => $query->from('product_has_relations')
|
||||
fn ($query) => $query->from('category_product')
|
||||
->select('product_id')
|
||||
->distinct('product_id')
|
||||
->where('productable_type', '=', 'category')
|
||||
->whereIn('productable_id', explode(',', $this->request->categories))
|
||||
->whereIn('category_id', explode(',', $this->request->categories))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use App\Models\Auth\Verification;
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use App\Models\Ecommerce\Product\Inventory\Inventory;
|
||||
use App\Models\System\Warning;
|
||||
use App\Repositories\Ecommerce\Product\Barcode\BarcodeRepository;
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -176,9 +177,7 @@ if (! function_exists('tmpostChannel')) {
|
||||
*/
|
||||
function tmpostChannel(): Channel
|
||||
{
|
||||
Cache::rememberForever('tmpostChannel', fn () => Channel::tmpostDefault());
|
||||
|
||||
return Cache::get('tmpostChannel');
|
||||
return Channel::tmpostDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,9 +187,7 @@ if (! function_exists('tmpostDefaultInventory')) {
|
||||
*/
|
||||
function tmpostDefaultInventory(): mixed
|
||||
{
|
||||
Cache::rememberForever('tmpostDefaultInventory', fn () => Inventory::tmpostDefault());
|
||||
|
||||
return Cache::get('tmpostDefaultInventory');
|
||||
return Inventory::tmpostDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,3 +389,16 @@ function createHalkbankOrder($price = 123): array
|
||||
'url' => $paymentResponse['formUrl'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn brother
|
||||
*/
|
||||
function warn(string $message, string $content = '', string $where = '', string $notes = ''): void
|
||||
{
|
||||
Warning::forceCreate([
|
||||
'name' => $message,
|
||||
'content' => $content,
|
||||
'where' => $where,
|
||||
'notes' => $notes,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -15,9 +15,8 @@ class BrandMediaResource extends JsonResource
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'thumbnail' => $this->getUrl('thumb200x200'),
|
||||
'thumbnail' => $this->getUrl('thumb400x400'),
|
||||
'images_400x400' => $this->getUrl('thumb400x400'),
|
||||
'images_720x720' => $this->getUrl('thumb720x720'),
|
||||
'images_800x800' => $this->getUrl('thumb800x800'),
|
||||
'images_1200x1200' => $this->getUrl('thumb1200x1200'),
|
||||
];
|
||||
|
||||
@@ -55,7 +55,7 @@ class CategoryController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Brands (products)
|
||||
* Categories (products)
|
||||
*/
|
||||
public function products(BasicProductIndexRequest $request, Category $category): JsonResponse
|
||||
{
|
||||
|
||||
@@ -17,7 +17,6 @@ class CategoryMediaResource extends JsonResource
|
||||
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,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Category\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class SelectedCategoryResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'is_visible' => $this->is_visible,
|
||||
'categories' => CategoryResource::collection($this->whenLoaded('categories')),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Category;
|
||||
|
||||
use App\Http\Controllers\Api\V1\Category\Resources\SelectedCategoryResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Ecommerce\Product\Category\SelectedCategory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SelectedCategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* Selected Categories (index)
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$selectedCategories = SelectedCategory::query()
|
||||
->where('is_visible', true)
|
||||
->with(['categories' => function ($query) {
|
||||
$query->where('is_visible', true)->ordered()->with(['media']);
|
||||
}])
|
||||
->get();
|
||||
|
||||
return response()->json(SelectedCategoryResource::collection($selectedCategories));
|
||||
}
|
||||
|
||||
/**
|
||||
* Selected Categories (show)
|
||||
*/
|
||||
public function show(SelectedCategory $selectedCategory): JsonResponse
|
||||
{
|
||||
$selectedCategory->load('categories');
|
||||
|
||||
return response()->json(new SelectedCategoryResource($selectedCategory));
|
||||
}
|
||||
}
|
||||
@@ -38,10 +38,9 @@ class FilterParamsController extends Controller
|
||||
$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');
|
||||
->join('category_product', function ($join) use ($category_id) {
|
||||
$join->on('products.id', '=', 'category_product.product_id')
|
||||
->where('category_product.category_id', '=', $category_id);
|
||||
})
|
||||
->select(['id', 'brand_id'])
|
||||
->pluck('brand_id');
|
||||
|
||||
@@ -97,9 +97,8 @@ class FilterController extends Controller
|
||||
->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)
|
||||
return Category::where('is_visible', true)->ordered()->join('category_product', 'categories.id', '=', 'category_product.category_id')
|
||||
->whereIntegerInRaw('category_product.product_id', $products)
|
||||
->get(['id', 'parent_id', 'name'])
|
||||
->unique('categories.id');
|
||||
}
|
||||
|
||||
@@ -87,9 +87,8 @@ class CategoriesFilter
|
||||
->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)
|
||||
return $this->queryBuilder->join('category_product', 'categories.id', '=', 'category_product.category_id')
|
||||
->whereIntegerInRaw('category_product.product_id', $products)
|
||||
->get($this->columns)
|
||||
->unique('categories.id');
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class OrderPaymentController extends Controller
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
return response()->rest(
|
||||
PaymentType::all(['id', 'name'])
|
||||
PaymentType::query()->where('is_enabled', true)->get(['id', 'name'])
|
||||
->map(fn ($paymentType) => [
|
||||
'id' => $paymentType->id,
|
||||
'name' => $paymentType->name,
|
||||
|
||||
@@ -6,6 +6,7 @@ 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\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use App\Repositories\Ecommerce\Order\OrderRepository;
|
||||
use App\Services\Order\CreateOrderService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -33,6 +34,27 @@ class OrderController extends Controller
|
||||
return response()->rest(OrderRepository::availableTimes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Order deliveries
|
||||
*/
|
||||
public function deliveries(): JsonResponse
|
||||
{
|
||||
return response()->rest([
|
||||
[
|
||||
'name' => OrderShipping::STANDART,
|
||||
'price' => 20,
|
||||
],
|
||||
[
|
||||
'name' => OrderShipping::SELF_PICKUP,
|
||||
'price' => 0
|
||||
],
|
||||
[
|
||||
'name' => OrderShipping::REGION,
|
||||
'price' => 40,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* (*) Store order
|
||||
*/
|
||||
|
||||
@@ -16,18 +16,17 @@ class ProductRelatedController extends Controller
|
||||
*/
|
||||
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')
|
||||
$products = DB::table('category_product')
|
||||
->select('category_product.product_id')
|
||||
->whereIn('category_product.category_id', (function ($query) use ($product) {
|
||||
$query->from('category_product')
|
||||
->select('category_id')
|
||||
->distinct('category_id')
|
||||
->where('product_id', '=', $product->id);
|
||||
}))
|
||||
->limit(12)
|
||||
->orderByRaw('RANDOM()')
|
||||
->pluck('product_has_relations.product_id')
|
||||
->pluck('category_product.product_id')
|
||||
->unique();
|
||||
|
||||
return response()->rest(
|
||||
|
||||
@@ -15,9 +15,9 @@ class ProductMediaResource extends JsonResource
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'thumbnail' => $this->getUrl('thumb288x431'),
|
||||
'original' => $this->getUrl(),
|
||||
'thumbnail' => $this->getUrl('thumb400x400'),
|
||||
'images_400x400' => $this->getUrl('thumb400x400'),
|
||||
'images_720x720' => $this->getUrl('thumb720x720'),
|
||||
'images_800x800' => $this->getUrl('thumb800x800'),
|
||||
'images_1200x1200' => $this->getUrl('thumb1200x1200'),
|
||||
];
|
||||
|
||||
@@ -40,6 +40,7 @@ class CheckoutOrderRequest extends FormRequest
|
||||
'customer_address' => ['required', 'string', 'max:255'],
|
||||
|
||||
'shipping_method' => ['required', 'string', 'max:255', Rule::in(array_keys(OrderShipping::values()))],
|
||||
'shipping_price' => ['nullable', 'numeric'],
|
||||
'payment_type_id' => ['required', Rule::in(array_keys(OrderPayment::values()))],
|
||||
|
||||
'notes' => ['nullable', 'string', 'max:255'],
|
||||
@@ -65,7 +66,7 @@ class CheckoutOrderRequest extends FormRequest
|
||||
'user_id' => auth()->id(),
|
||||
'notes' => $this->notes ?: null,
|
||||
'province_id' => $this->province_id ?: null,
|
||||
'shipping_price' => OrderShipping::priceFor($this->shipping_method),
|
||||
'shipping_price' => $this->shipping_price ?: OrderShipping::priceFor($this->shipping_method),
|
||||
'delivery_time' => $this->delivery_time ?: OrderShipping::MORNING,
|
||||
'delivery_at' => $this->delivery_at ?: date('Y-m-d'),
|
||||
'source' => $this->source ?: OS::MOBILE_APP,
|
||||
|
||||
@@ -17,7 +17,6 @@ class ChannelMediaResource extends JsonResource
|
||||
return [
|
||||
'thumbnail' => $this->getUrl(),
|
||||
'images_400x400' => $this->getUrl('thumb400x400'),
|
||||
'images_720x720' => $this->getUrl('thumb720x720'),
|
||||
'images_800x800' => $this->getUrl('thumb800x800'),
|
||||
'images_1200x1200' => $this->getUrl('thumb1200x1200'),
|
||||
];
|
||||
|
||||
@@ -15,9 +15,8 @@ class MediaResource extends JsonResource
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'thumbnail' => $this->getUrl('thumb720x720'),
|
||||
'thumbnail' => $this->getUrl('thumb400x400'),
|
||||
'images_400x400' => $this->getUrl('thumb400x400'),
|
||||
'images_720x720' => $this->getUrl('thumb720x720'),
|
||||
'images_800x800' => $this->getUrl('thumb800x800'),
|
||||
'images_1200x1200' => $this->getUrl('thumb1200x1200'),
|
||||
];
|
||||
|
||||
@@ -59,6 +59,11 @@ class UpdateProductRelations implements ShouldQueue
|
||||
'product_custom_value' => in_array($attribute->type, ['text', 'number']) ? $this->properties[$attribute->slug] : null,
|
||||
]);
|
||||
});
|
||||
|
||||
// sync properties json
|
||||
if (method_exists($this->model, 'syncPropertiesJson')) {
|
||||
$this->model->syncPropertiesJson();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,24 +106,15 @@ class Banner extends Model implements HasMedia
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb350x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 350, 350);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ use App\Repositories\System\Cache\CacheRepository;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Laravel\Nova\Nova;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
@@ -109,29 +109,14 @@ class Channel extends Model implements HasMedia, Sortable
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb150x150')
|
||||
->fit(Manipulations::FIT_CONTAIN, 150, 150);
|
||||
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,9 +164,9 @@ class Channel extends Model implements HasMedia, Sortable
|
||||
/**
|
||||
* Products
|
||||
*/
|
||||
public function products(): MorphToMany
|
||||
public function products(): BelongsToMany
|
||||
{
|
||||
return $this->morphToMany(Product::class, 'productable', 'product_has_relations');
|
||||
return $this->belongsToMany(Product::class, 'channel_product');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,26 +85,14 @@ class Brand extends Model implements HasMedia, Sortable
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,6 @@ use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Image\Manipulations;
|
||||
@@ -83,7 +82,6 @@ class Category extends Model implements HasMedia, Sortable
|
||||
{
|
||||
$this->addMediaCollection('uploads')
|
||||
->singleFile()
|
||||
->acceptsMimeTypes(['image/jpg', 'image/jpeg', 'image/png'])
|
||||
->useFallbackUrl(
|
||||
sprintf('%s/logo-space.png', config('app.url'))
|
||||
);
|
||||
@@ -94,29 +92,14 @@ class Category extends Model implements HasMedia, Sortable
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
|
||||
$this->addMediaConversion('thumb657x230')
|
||||
->fit(Manipulations::FIT_CROP, 657, 230);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,9 +135,9 @@ class Category extends Model implements HasMedia, Sortable
|
||||
/**
|
||||
* Category Products
|
||||
*/
|
||||
public function products(): MorphToMany
|
||||
public function products(): BelongsToMany
|
||||
{
|
||||
return $this->morphToMany(Product::class, 'productable', 'product_has_relations');
|
||||
return $this->belongsToMany(Product::class, 'category_product');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
31
app/Models/Ecommerce/Product/Category/SelectedCategory.php
Normal file
31
app/Models/Ecommerce/Product/Category/SelectedCategory.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Category;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class SelectedCategory extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
'is_visible',
|
||||
];
|
||||
|
||||
public $translatable = ['name', 'description'];
|
||||
|
||||
protected $casts = [
|
||||
'is_visible' => 'boolean',
|
||||
];
|
||||
|
||||
public function categories(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Category::class, 'category_selected_category');
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace App\Models\Ecommerce\Product\Collection;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Image\Manipulations;
|
||||
@@ -84,34 +84,22 @@ class Collection extends Model implements HasMedia, Sortable
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* Products
|
||||
*/
|
||||
public function products(): MorphToMany
|
||||
public function products(): BelongsToMany
|
||||
{
|
||||
return $this->morphToMany(Product::class, 'productable', 'product_has_relations');
|
||||
return $this->belongsToMany(Product::class, 'collection_product');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order;
|
||||
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\Ecommerce\Product\Order\Concerns\HasPayments;
|
||||
use App\Models\Ecommerce\Product\Order\Concerns\HasShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Concerns\HasStatus;
|
||||
@@ -19,6 +20,7 @@ class Order extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasPayments;
|
||||
use HasSchemalessAttributes;
|
||||
use HasShipping;
|
||||
use HasStatus;
|
||||
use SoftDeletes;
|
||||
|
||||
@@ -21,32 +21,20 @@ trait ProductMedia
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* Thumbnail
|
||||
*/
|
||||
public function thumbnail(string $size = '200x200'): string
|
||||
public function thumbnail(string $size = '400x400'): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('uploads', 'thumb'.$size);
|
||||
}
|
||||
@@ -54,7 +42,7 @@ trait ProductMedia
|
||||
/**
|
||||
* Get image when hovered (returns second image)
|
||||
*/
|
||||
public function getHoverImage(string $size = '270x350'): string
|
||||
public function getHoverImage(string $size = '400x400'): string
|
||||
{
|
||||
$media = $this->getMedia('uploads');
|
||||
$image_count = $media->count();
|
||||
|
||||
@@ -15,7 +15,6 @@ use App\Models\Ecommerce\Product\Review\Review;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
|
||||
trait ProductRelationships
|
||||
{
|
||||
@@ -38,9 +37,9 @@ trait ProductRelationships
|
||||
/**
|
||||
* Related Channels
|
||||
*/
|
||||
public function channels(): MorphToMany
|
||||
public function channels(): BelongsToMany
|
||||
{
|
||||
return $this->morphedByMany(Channel::class, 'productable', 'product_has_relations');
|
||||
return $this->belongsToMany(Channel::class, 'channel_product');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,25 +55,25 @@ trait ProductRelationships
|
||||
/**
|
||||
* Related products (similar)
|
||||
*/
|
||||
public function relatedProducts(): MorphToMany
|
||||
public function relatedProducts(): BelongsToMany
|
||||
{
|
||||
return $this->morphedByMany(Product::class, 'productable', 'product_has_relations');
|
||||
return $this->belongsToMany(Product::class, 'product_related', 'product_id', 'related_product_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Related categories
|
||||
*/
|
||||
public function categories(): MorphToMany
|
||||
public function categories(): BelongsToMany
|
||||
{
|
||||
return $this->morphedByMany(Category::class, 'productable', 'product_has_relations');
|
||||
return $this->belongsToMany(Category::class, 'category_product');
|
||||
}
|
||||
|
||||
/**
|
||||
* Related Collections
|
||||
*/
|
||||
public function collections(): MorphToMany
|
||||
public function collections(): BelongsToMany
|
||||
{
|
||||
return $this->morphedByMany(Collection::class, 'productable', 'product_has_relations');
|
||||
return $this->belongsToMany(Collection::class, 'collection_product');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,7 +62,7 @@ class MostSoldProducts extends Lens
|
||||
{
|
||||
return [
|
||||
ID::make(__('ID'), 'id')->sortable(),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb200x200'),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb400x400'),
|
||||
Text::make(__('Name'), 'name')->sortable(),
|
||||
Number::make(__('Price'), 'price_amount')->sortable(),
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class Banner extends Resource
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'main')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->conversionOnIndexView('thumb400x400')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class Channel extends Resource
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->conversionOnIndexView('thumb400x400')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class ChannelFieldsForIndex
|
||||
ID::make()->hidden(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200'),
|
||||
->conversionOnIndexView('thumb400x400'),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->sortable(),
|
||||
|
||||
@@ -96,7 +96,7 @@ class Brand extends Resource
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->conversionOnIndexView('thumb400x400')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ class Category extends Resource
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->conversionOnIndexView('thumb400x400')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Category;
|
||||
|
||||
use App\Models\Ecommerce\Product\Category\SelectedCategory as SelectedCategoryModel;
|
||||
use App\Nova\Resource;
|
||||
use Laravel\Nova\Fields\BelongsToMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Textarea;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class SelectedCategory extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<SelectedCategoryModel>
|
||||
*/
|
||||
public static $model = SelectedCategoryModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Sections');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Section');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->sortable()
|
||||
->translatable()
|
||||
->rules('required'),
|
||||
|
||||
Textarea::make(__('Description'), 'description')
|
||||
->translatable()
|
||||
->nullable(),
|
||||
|
||||
NovaSwitcher::make(__('Is Visible'), 'is_visible')
|
||||
->default(true),
|
||||
|
||||
BelongsToMany::make(__('Categories'), 'categories', Category::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class Collection extends Resource
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->conversionOnIndexView('thumb400x400')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class ProductResource extends Resource
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb200x200'),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb400x400'),
|
||||
Text::make(__('Name'), fn () => $this->novaDetailPage())
|
||||
->displayUsing(FieldHelpers::asLink(
|
||||
link: $this->novaDetailPage(),
|
||||
|
||||
@@ -27,7 +27,7 @@ class OrderFieldsForCreate
|
||||
return [
|
||||
Hidden::make('number')->default(Str::random(30)),
|
||||
Hidden::make('user_id')->default($request->user()->id),
|
||||
Hidden::make('source_app')->default(OS::ADMIN),
|
||||
Hidden::make('source')->default(OS::ADMIN),
|
||||
|
||||
ID::make(),
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class OrderFieldsForDetail
|
||||
)
|
||||
->asHtml(),
|
||||
|
||||
Select::make(__('App'), 'source_app')
|
||||
Select::make(__('App'), 'source')
|
||||
->displayUsingLabels()
|
||||
->options(OS::apps())
|
||||
->sortable(),
|
||||
|
||||
@@ -55,7 +55,7 @@ class OrderFieldsForIndex
|
||||
->default(OrderShipping::default())
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Source'), 'source_app')
|
||||
Select::make(__('Source'), 'source')
|
||||
->displayUsingLabels()
|
||||
->options(OS::apps())
|
||||
->sortable(),
|
||||
|
||||
@@ -93,7 +93,7 @@ class ProductFieldsForCreate
|
||||
->rules('nullable', 'string'),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->conversionOnIndexView('thumb400x400')
|
||||
->rules('required')
|
||||
->setFileName(NovaForm::fillMediaFileName())
|
||||
->required(),
|
||||
|
||||
@@ -53,7 +53,7 @@ class ProductFieldsForDetail
|
||||
Text::make(__('Name'), 'name'),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200'),
|
||||
->conversionOnIndexView('thumb400x400'),
|
||||
|
||||
Trix::make(__('Description'), 'description')->withFiles('public')->alwaysShow(),
|
||||
Text::make(__('Price'), 'cost_amount'),
|
||||
@@ -134,8 +134,8 @@ class ProductFieldsForDetail
|
||||
'name' => $property->attribute->slug,
|
||||
'type' => $property->attribute->type,
|
||||
'default' => $property->attribute->type === 'select'
|
||||
? $property->values->first()->value?->id
|
||||
: $property->values->first()->product_custom_value,
|
||||
? $property->values->first()->value?->id ?? '-'
|
||||
: $property->values->first()->product_custom_value ?? '-',
|
||||
'options' => $property->attribute->values->map(fn ($value) => [
|
||||
'label' => $value->value,
|
||||
'value' => $value->id,
|
||||
|
||||
@@ -26,7 +26,7 @@ class ProductFieldsForIndex
|
||||
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb200x200'),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb400x400'),
|
||||
Text::make(__('Name'), 'name')->sortable(),
|
||||
|
||||
BelongsTo::make(__('Brand'), 'brand', Brand::class)
|
||||
|
||||
@@ -32,7 +32,7 @@ class VariantFieldsForDetail
|
||||
BelongsTo::make(__('Parent'), 'parent', Product::class),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200'),
|
||||
->conversionOnIndexView('thumb400x400'),
|
||||
|
||||
Text::make(__('Price'), 'cost_amount')
|
||||
->rules('required', 'numeric'),
|
||||
|
||||
@@ -20,7 +20,7 @@ class VariantFieldsForIndex
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200'),
|
||||
->conversionOnIndexView('thumb400x400'),
|
||||
|
||||
Text::make(__('Price'), 'cost_amount')
|
||||
->rules('required', 'numeric'),
|
||||
|
||||
@@ -33,9 +33,8 @@ class ProductEntrepreneurFilter extends Filter
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
$vendorProducts = DB::table('product_has_relations')
|
||||
->where('productable_type', 'channel')
|
||||
->where('productable_id', $value)
|
||||
$vendorProducts = DB::table('channel_product')
|
||||
->where('channel_id', $value)
|
||||
->pluck('product_id');
|
||||
|
||||
$query->whereIntegerInRaw('id', $vendorProducts);
|
||||
|
||||
@@ -123,9 +123,8 @@ class Product extends Resource
|
||||
$user = $request->user();
|
||||
|
||||
if ($user->hasRole('vendor')) {
|
||||
$vendorProducts = DB::table('product_has_relations')
|
||||
->where('productable_type', 'channel')
|
||||
->where('productable_id', $user->channel()->id)
|
||||
$vendorProducts = DB::table('channel_product')
|
||||
->where('channel_id', $user->channel()->id)
|
||||
->pluck('product_id');
|
||||
|
||||
$query->whereIntegerInRaw('id', $vendorProducts);
|
||||
|
||||
@@ -64,8 +64,8 @@ class ChannelPolicy
|
||||
*/
|
||||
public function update(User $user, Channel $channel): Response
|
||||
{
|
||||
if ($user->hasRole(['admin'])) {
|
||||
return $this->allow();
|
||||
if (tmpostChannel()->slug === $channel->slug) {
|
||||
return $this->deny();
|
||||
}
|
||||
|
||||
return $this->deny();
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Nova\Resources\Ecommerce\Payout\PayoutResource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Attribute\Attribute;
|
||||
use App\Nova\Resources\Ecommerce\Product\Brand\Brand;
|
||||
use App\Nova\Resources\Ecommerce\Product\Category\Category;
|
||||
use App\Nova\Resources\Ecommerce\Product\Category\SelectedCategory;
|
||||
use App\Nova\Resources\Ecommerce\Product\Collection\Collection;
|
||||
use App\Nova\Resources\Ecommerce\Product\Coupon\Coupon;
|
||||
use App\Nova\Resources\Ecommerce\Product\Inventory\Inventory;
|
||||
@@ -158,6 +159,7 @@ class NovaServiceProvider extends NovaApplicationServiceProvider
|
||||
MenuItem::resource(Category::class),
|
||||
MenuItem::resource(Brand::class),
|
||||
MenuItem::resource(Attribute::class),
|
||||
MenuItem::resource(SelectedCategory::class),
|
||||
])->icon('color-swatch'),
|
||||
])->icon('shopping-bag')->collapsedByDefault(),
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Repositories\Ecommerce\Product\Category;
|
||||
|
||||
use App\Models\Ecommerce\Product\Category\Category;
|
||||
use App\Repositories\System\Cache\CacheRepository;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CategoryRepository
|
||||
@@ -124,16 +123,13 @@ class CategoryRepository
|
||||
/**
|
||||
* Names with taxes (usefull for nova)
|
||||
*/
|
||||
public static function namesWithTaxes(): array
|
||||
public static function namesWithTaxes(): mixed
|
||||
{
|
||||
return CacheRepository::make(
|
||||
name: 'cs-nova-models-categories',
|
||||
value: fn () => static::maskParentName(
|
||||
Category::tree()
|
||||
->where('is_visible', true)
|
||||
->get(['id', 'slug', 'name', 'tax_percentage', 'parent_id', 'is_visible'])
|
||||
->toTree()
|
||||
)
|
||||
return static::maskParentName(
|
||||
Category::tree()
|
||||
->where('is_visible', true)
|
||||
->get(['id', 'slug', 'name', 'tax_percentage', 'parent_id', 'is_visible'])
|
||||
->toTree()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -181,9 +177,8 @@ class CategoryRepository
|
||||
])) {
|
||||
$products = $resource->products()->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)
|
||||
return $this->queryBuilder->join('category_product', 'categories.id', '=', 'category_product.category_id')
|
||||
->whereIntegerInRaw('category_product.product_id', $products)
|
||||
->distinct('categories.id')
|
||||
->get(['id', 'slug', 'name']);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ class CreateOrderService
|
||||
{
|
||||
return DB::transaction(function () use ($user, $data) {
|
||||
// 1. Create the order
|
||||
info(['service' => $data]);
|
||||
$order = Order::create($data);
|
||||
|
||||
// 2. Process Cart Items
|
||||
@@ -41,10 +40,24 @@ class CreateOrderService
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
// Update Stock
|
||||
// Update Stock directly in products table, also relationship
|
||||
$stock = $cart->product->stock - $cart->product_quantity;
|
||||
$cart->product->update([
|
||||
'stock' => $cart->product->stock - $cart->product_quantity,
|
||||
'stock' => $stock,
|
||||
]);
|
||||
|
||||
$data = DB::table('inventory_product')->where('product_id', $cart->product_id)->first();
|
||||
if ($data) {
|
||||
DB::table('inventory_product')->where('id', $data->id)->update([
|
||||
'stock' => $stock,
|
||||
]);
|
||||
} else {
|
||||
warn('Product has no inventory record', json_encode([
|
||||
'product_id' => $cart->product_id,
|
||||
'order_id' => $order->id,
|
||||
]));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// 3. Clear User Cart
|
||||
|
||||
28
app/Support/ShortFileNamer.php
Normal file
28
app/Support/ShortFileNamer.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\MediaLibrary\Conversions\Conversion;
|
||||
use Spatie\MediaLibrary\Support\FileNamer\FileNamer;
|
||||
|
||||
class ShortFileNamer extends FileNamer
|
||||
{
|
||||
/**
|
||||
* Generate a short random name for the original file.
|
||||
*/
|
||||
public function originalFileName(string $fileName): string
|
||||
{
|
||||
return Str::random(10);
|
||||
}
|
||||
|
||||
public function conversionFileName(string $fileName, Conversion $conversion): string
|
||||
{
|
||||
return $conversion->getName();
|
||||
}
|
||||
|
||||
public function responsiveFileName(string $fileName): string
|
||||
{
|
||||
return 'res';
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ return [
|
||||
/*
|
||||
* This is the class that is responsible for naming generated files.
|
||||
*/
|
||||
'file_namer' => Spatie\MediaLibrary\Support\FileNamer\DefaultFileNamer::class,
|
||||
'file_namer' => App\Support\ShortFileNamer::class,
|
||||
|
||||
/*
|
||||
* The class that contains the strategy for determining a media file's path.
|
||||
|
||||
3
database/data/.gitignore
vendored
Normal file
3
database/data/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!provinces.json
|
||||
!.gitignore
|
||||
716
database/data/provinces.json
Normal file
716
database/data/provinces.json
Normal file
@@ -0,0 +1,716 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Ak bugday\", \"ru\": \"Ак бугдай\", \"tk\": \"Ak bugdaý\"}",
|
||||
"created_at": "2022-11-15 14:24:55",
|
||||
"updated_at": "2022-11-15 14:24:55"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Tejen\", \"ru\": \"Теджен\", \"tk\": \"Tejen\"}",
|
||||
"created_at": "2022-11-15 14:26:35",
|
||||
"updated_at": "2022-11-15 14:26:35"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Kaka\", \"ru\": \"Кака\", \"tk\": \"Kaka\"}",
|
||||
"created_at": "2022-11-15 14:28:01",
|
||||
"updated_at": "2022-11-15 14:28:01"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"region": "ag",
|
||||
"name": "{\"en\": \"Bagtyyarlyk\", \"ru\": \"Багтыярлык\", \"tk\": \"Bagtyýarlyk\"}",
|
||||
"created_at": "2022-11-15 15:08:49",
|
||||
"updated_at": "2022-11-15 15:08:49"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"region": "ag",
|
||||
"name": "{\"en\": \"Kopetdag\", \"ru\": \"Копетдаг\", \"tk\": \"Köpetdag\"}",
|
||||
"created_at": "2022-11-15 15:10:33",
|
||||
"updated_at": "2022-11-15 15:10:33"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"region": "ag",
|
||||
"name": "{\"en\": \"Berkararlyk\", \"ru\": \"Беркарарлык\", \"tk\": \"Berkararlyk\"}",
|
||||
"created_at": "2022-11-15 15:11:56",
|
||||
"updated_at": "2022-11-15 15:11:56"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"region": "ag",
|
||||
"name": "{\"en\": \"Buzmeyin\", \"ru\": \"Бузмеин\", \"tk\": \"Büzmeýin\"}",
|
||||
"created_at": "2022-11-15 15:13:11",
|
||||
"updated_at": "2022-11-15 15:13:11"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Babadayhan\", \"ru\": \"Бабадайхан\", \"tk\": \"Babadaýhan\"}",
|
||||
"created_at": "2022-11-15 15:18:43",
|
||||
"updated_at": "2022-11-15 15:18:43"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Gokdepe\", \"ru\": \"Геёкдепе\", \"tk\": \"Gökdepe\"}",
|
||||
"created_at": "2022-11-15 15:20:02",
|
||||
"updated_at": "2022-11-15 15:20:02"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Baherden\", \"ru\": \"Бахерден\", \"tk\": \"Bäherden\"}",
|
||||
"created_at": "2022-11-15 15:21:20",
|
||||
"updated_at": "2022-11-15 15:21:20"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Sarahs\", \"ru\": \"Сарахс\", \"tk\": \"Sarahs\"}",
|
||||
"created_at": "2022-11-15 15:23:04",
|
||||
"updated_at": "2022-11-15 15:23:04"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Mary\", \"ru\": \"Мары\", \"tk\": \"Mary\"}",
|
||||
"created_at": "2022-11-15 15:24:10",
|
||||
"updated_at": "2022-11-15 15:24:10"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Garagum\", \"ru\": \"Гарагум\", \"tk\": \"Garagum\"}",
|
||||
"created_at": "2022-11-15 15:25:22",
|
||||
"updated_at": "2022-11-15 15:25:22"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Vekilbazar\", \"ru\": \"Векилбазар\", \"tk\": \"Wekilbazar\"}",
|
||||
"created_at": "2022-11-15 15:26:42",
|
||||
"updated_at": "2022-11-15 15:26:42"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Yoloten\", \"ru\": \"Ёлотен\", \"tk\": \"Yolöten\"}",
|
||||
"created_at": "2022-11-15 15:27:45",
|
||||
"updated_at": "2022-11-15 15:27:45"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Bayramaly\", \"ru\": \"Байрамалы\", \"tk\": \"Baýramaly\"}",
|
||||
"created_at": "2022-11-15 15:28:49",
|
||||
"updated_at": "2022-11-15 15:28:49"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Murgap\", \"ru\": \"Мургап\", \"tk\": \"Murgap\"}",
|
||||
"created_at": "2022-11-15 15:30:27",
|
||||
"updated_at": "2022-11-15 15:30:27"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Sakarchage\", \"ru\": \"Сакарчаге\", \"tk\": \"Sakarçäge\"}",
|
||||
"created_at": "2022-11-15 15:31:42",
|
||||
"updated_at": "2022-11-15 15:31:42"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Tagtabazar\", \"ru\": \"Тагтабазар\", \"tk\": \"Tagtabazar\"}",
|
||||
"created_at": "2022-11-15 15:32:53",
|
||||
"updated_at": "2022-11-15 15:32:53"
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Turkmengala\", \"ru\": \"Туркменгала\", \"tk\": \"Türkmengala\"}",
|
||||
"created_at": "2022-11-15 15:33:59",
|
||||
"updated_at": "2022-11-15 15:33:59"
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Etrek\", \"ru\": \"Етрек\", \"tk\": \"Etrek\"}",
|
||||
"created_at": "2022-11-15 15:35:37",
|
||||
"updated_at": "2022-11-15 15:35:37"
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Turkmenbashy\", \"ru\": \"Туркменбащы\", \"tk\": \"Türkmenbaşy\"}",
|
||||
"created_at": "2022-11-15 15:38:29",
|
||||
"updated_at": "2022-11-15 15:38:29"
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Esenguly\", \"ru\": \"Эсенгулы\", \"tk\": \"Esenguly\"}",
|
||||
"created_at": "2022-11-15 15:39:37",
|
||||
"updated_at": "2022-11-15 15:39:37"
|
||||
},
|
||||
{
|
||||
"id": 24,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Gyzylarbat\", \"ru\": \"Гызыларбат\", \"tk\": \"Gyzylarbat\"}",
|
||||
"created_at": "2022-11-15 15:40:50",
|
||||
"updated_at": "2022-11-15 15:40:50"
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Bereket\", \"ru\": \"Берекет\", \"tk\": \"Bereket\"}",
|
||||
"created_at": "2022-11-15 15:41:39",
|
||||
"updated_at": "2022-11-15 15:41:39"
|
||||
},
|
||||
{
|
||||
"id": 26,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Magtymguly\", \"ru\": \"Магтымгулы\", \"tk\": \"Magtymguly\"}",
|
||||
"created_at": "2022-11-15 15:42:46",
|
||||
"updated_at": "2022-11-15 15:42:46"
|
||||
},
|
||||
{
|
||||
"id": 27,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Gorogly\", \"ru\": \"Гёроглы\", \"tk\": \"Görogly\"}",
|
||||
"created_at": "2022-11-15 15:44:05",
|
||||
"updated_at": "2022-11-15 15:44:05"
|
||||
},
|
||||
{
|
||||
"id": 28,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Akdepe\", \"ru\": \"Aкдепе\", \"tk\": \"Akdepe\"}",
|
||||
"created_at": "2022-11-15 15:44:53",
|
||||
"updated_at": "2022-11-15 15:44:53"
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Ruhybelent\", \"ru\": \"Рухыбелент\", \"tk\": \"Ruhybelent\"}",
|
||||
"created_at": "2022-11-15 15:45:43",
|
||||
"updated_at": "2022-11-15 15:45:43"
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Boldumsaz\", \"ru\": \"Болдумсаз\", \"tk\": \"Boldumsaz\"}",
|
||||
"created_at": "2022-11-15 15:46:38",
|
||||
"updated_at": "2022-11-15 15:46:38"
|
||||
},
|
||||
{
|
||||
"id": 31,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Koneurgench\", \"ru\": \"Конеугенч\", \"tk\": \"Köneürgenç\"}",
|
||||
"created_at": "2022-11-15 15:48:00",
|
||||
"updated_at": "2022-11-15 15:48:00"
|
||||
},
|
||||
{
|
||||
"id": 32,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Shabat\", \"ru\": \"Шабать\", \"tk\": \"Gubadag\"}",
|
||||
"created_at": "2022-11-15 15:48:46",
|
||||
"updated_at": "2022-12-03 10:08:32"
|
||||
},
|
||||
{
|
||||
"id": 33,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"S.Turkmenbashy\", \"ru\": \"С.Туркменбащы\", \"tk\": \"S.Türkmenbaşy\"}",
|
||||
"created_at": "2022-11-15 15:50:34",
|
||||
"updated_at": "2022-12-03 10:13:38"
|
||||
},
|
||||
{
|
||||
"id": 34,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Charjev\", \"ru\": \"Чарджев\", \"tk\": \"Çärjew\"}",
|
||||
"created_at": "2022-11-15 15:52:33",
|
||||
"updated_at": "2022-11-15 15:52:33"
|
||||
},
|
||||
{
|
||||
"id": 35,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Halach\", \"ru\": \"Халач\", \"tk\": \"Halaç\"}",
|
||||
"created_at": "2022-11-15 15:53:16",
|
||||
"updated_at": "2022-11-15 15:53:16"
|
||||
},
|
||||
{
|
||||
"id": 36,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Hojambaz\", \"ru\": \"Ходжамбаз\", \"tk\": \"Hojambaz\"}",
|
||||
"created_at": "2022-11-15 15:54:20",
|
||||
"updated_at": "2022-11-15 15:54:20"
|
||||
},
|
||||
{
|
||||
"id": 37,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Kerki\", \"ru\": \"Керки\", \"tk\": \"Kerki\"}",
|
||||
"created_at": "2022-11-15 15:55:09",
|
||||
"updated_at": "2022-11-15 15:55:09"
|
||||
},
|
||||
{
|
||||
"id": 38,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Darganata\", \"ru\": \"Дарганата\", \"tk\": \"Darganata\"}",
|
||||
"created_at": "2022-11-15 15:56:01",
|
||||
"updated_at": "2022-11-15 15:56:01"
|
||||
},
|
||||
{
|
||||
"id": 39,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Danev\", \"ru\": \"Данев\", \"tk\": \"Dänew\"}",
|
||||
"created_at": "2022-11-15 15:57:20",
|
||||
"updated_at": "2022-11-15 15:57:20"
|
||||
},
|
||||
{
|
||||
"id": 40,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Sayat\", \"ru\": \"Саят\", \"tk\": \"Saýat\"}",
|
||||
"created_at": "2022-11-15 15:58:08",
|
||||
"updated_at": "2022-11-15 15:58:08"
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Koytendag\", \"ru\": \"Койтендаг\", \"tk\": \"Köýtendag\"}",
|
||||
"created_at": "2022-11-15 15:58:58",
|
||||
"updated_at": "2022-11-15 15:58:58"
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Altyn asyr c.\", \"ru\": \"Aлтын асыр г.\", \"tk\": \"Altyn asyr ş.\"}",
|
||||
"created_at": "2022-11-15 16:44:54",
|
||||
"updated_at": "2022-11-15 16:47:40"
|
||||
},
|
||||
{
|
||||
"id": 43,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Anev c.\", \"ru\": \"Аннау г.\", \"tk\": \"Änew ş.\"}",
|
||||
"created_at": "2022-11-15 16:46:43",
|
||||
"updated_at": "2022-11-15 16:46:43"
|
||||
},
|
||||
{
|
||||
"id": 44,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Dushak c.\", \"ru\": \"Душак г.\", \"tk\": \"Duşak ş.\"}",
|
||||
"created_at": "2022-11-15 16:49:47",
|
||||
"updated_at": "2022-11-15 16:50:26"
|
||||
},
|
||||
{
|
||||
"id": 45,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Balkanaabat c.\", \"ru\": \"Балканабат г.\", \"tk\": \"Balkanabat ş.\"}",
|
||||
"created_at": "2022-11-15 16:51:48",
|
||||
"updated_at": "2022-11-15 16:51:48"
|
||||
},
|
||||
{
|
||||
"id": 46,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Gumdag c.\", \"ru\": \"Гумдаг г.\", \"tk\": \"Gumdag ş.\"}",
|
||||
"created_at": "2022-11-15 16:53:07",
|
||||
"updated_at": "2022-11-15 16:53:07"
|
||||
},
|
||||
{
|
||||
"id": 47,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Garabogaz c.\", \"ru\": \"Гарабогаз г.\", \"tk\": \"Garabogaz ş.\"}",
|
||||
"created_at": "2022-11-15 16:54:31",
|
||||
"updated_at": "2022-11-15 16:54:31"
|
||||
},
|
||||
{
|
||||
"id": 48,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Hazar c.\", \"ru\": \"Хазар г.\", \"tk\": \"Hazar ş.\"}",
|
||||
"created_at": "2022-11-15 16:55:40",
|
||||
"updated_at": "2022-11-15 16:55:40"
|
||||
},
|
||||
{
|
||||
"id": 49,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Sakar c.\", \"ru\": \"Cакар г.\", \"tk\": \"Sakar ş\"}",
|
||||
"created_at": "2022-11-15 17:06:13",
|
||||
"updated_at": "2022-11-15 17:06:13"
|
||||
},
|
||||
{
|
||||
"id": 50,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Seydi c.\", \"ru\": \"Сейди г.\", \"tk\": \"Seýdi ş.\"}",
|
||||
"created_at": "2022-11-15 17:07:17",
|
||||
"updated_at": "2022-11-15 17:07:17"
|
||||
},
|
||||
{
|
||||
"id": 51,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Dostlyk c.\", \"ru\": \"Достлык г.\", \"tk\": \"Dostluk ş.\"}",
|
||||
"created_at": "2022-11-15 17:08:27",
|
||||
"updated_at": "2022-11-15 17:08:27"
|
||||
},
|
||||
{
|
||||
"id": 52,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Murgap\", \"ru\": \"Мургап\", \"tk\": \"Murgap\"}",
|
||||
"created_at": "2022-11-15 17:09:29",
|
||||
"updated_at": "2022-11-15 17:09:29"
|
||||
},
|
||||
{
|
||||
"id": 53,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Garabekrevul c.\", \"ru\": \"Гарабекевул г.\", \"tk\": \"Garabekewül ş.\"}",
|
||||
"created_at": "2022-11-15 17:11:41",
|
||||
"updated_at": "2022-11-16 09:02:15"
|
||||
},
|
||||
{
|
||||
"id": 54,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Gurbansoltan Eje\", \"ru\": \"Гурбансолтан эдже\", \"tk\": \"Gurbansoltan Eje\"}",
|
||||
"created_at": "2022-12-03 10:10:57",
|
||||
"updated_at": "2022-12-03 10:10:57"
|
||||
},
|
||||
{
|
||||
"id": 55,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"S.Nyýazow\", \"ru\": \"С,Ныязов\", \"tk\": \"S.Nyýazow\"}",
|
||||
"created_at": "2022-12-03 10:12:31",
|
||||
"updated_at": "2022-12-03 10:12:31"
|
||||
},
|
||||
{
|
||||
"id": 56,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Dashoguz s.\", \"ru\": \"Дашогуз г.\", \"tk\": \"Daşoguz ş.\"}",
|
||||
"created_at": "2023-01-18 11:00:24",
|
||||
"updated_at": "2023-01-18 11:00:24"
|
||||
},
|
||||
{
|
||||
"id": 58,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Watan f/u\", \"ru\": \"Ватан с/ф\", \"tk\": \"Watan d/b\"}",
|
||||
"created_at": "2023-05-23 14:31:44",
|
||||
"updated_at": "2023-05-23 14:45:56"
|
||||
},
|
||||
{
|
||||
"id": 59,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"A blessed town\", \"ru\": \"Берекет г.\", \"tk\": \"Bereket ş.\"}",
|
||||
"created_at": "2023-05-23 15:47:26",
|
||||
"updated_at": "2023-05-23 15:47:26"
|
||||
},
|
||||
{
|
||||
"id": 60,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Youth town\", \"ru\": \"Яшлик г.\", \"tk\": \"Ýaşlyk ş.\"}",
|
||||
"created_at": "2023-05-23 15:59:14",
|
||||
"updated_at": "2023-05-23 15:59:57"
|
||||
},
|
||||
{
|
||||
"id": 61,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Altyn asyr ş.\", \"ru\": \"Altyn asyr ş.\", \"tk\": \"Altyn asyr ş.\"}",
|
||||
"created_at": "2023-05-23 16:09:54",
|
||||
"updated_at": "2023-05-23 16:09:54"
|
||||
},
|
||||
{
|
||||
"id": 62,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Small brother village\", \"ru\": \"Деревня младшего брата\", \"tk\": \"Kiçi aga obasy\"}",
|
||||
"created_at": "2023-05-23 16:22:25",
|
||||
"updated_at": "2023-05-23 16:22:25"
|
||||
},
|
||||
{
|
||||
"id": 63,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Truth Farmers Union\", \"ru\": \"Правда с/ф\", \"tk\": \"Hakykat d/b\"}",
|
||||
"created_at": "2023-05-23 16:45:22",
|
||||
"updated_at": "2023-05-23 16:45:22"
|
||||
},
|
||||
{
|
||||
"id": 64,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Bed City\", \"ru\": \"Бед Сити\", \"tk\": \"Duşak ş.\"}",
|
||||
"created_at": "2023-05-23 16:49:30",
|
||||
"updated_at": "2023-05-23 16:49:30"
|
||||
},
|
||||
{
|
||||
"id": 65,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"White Gold Consulting\", \"ru\": \"Консалтинг Белого Золота\", \"tk\": \"Ak Altyn g.\"}",
|
||||
"created_at": "2023-05-23 17:02:49",
|
||||
"updated_at": "2023-05-23 17:02:49"
|
||||
},
|
||||
{
|
||||
"id": 66,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"\\\"Hasyl\\\" f/a\", \"ru\": \"«Хасыл» a/ф\", \"tk\": \"Hasyl d/b\"}",
|
||||
"created_at": "2023-05-23 17:11:00",
|
||||
"updated_at": "2023-05-23 17:11:00"
|
||||
},
|
||||
{
|
||||
"id": 67,
|
||||
"region": "ah",
|
||||
"name": "{\"en\": \"Zahmet Farmers Union\", \"ru\": \"Захмет c/ф\", \"tk\": \"Zähmet d/b\"}",
|
||||
"created_at": "2023-05-23 17:16:37",
|
||||
"updated_at": "2023-05-23 17:16:37"
|
||||
},
|
||||
{
|
||||
"id": 68,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Jebel t.\", \"ru\": \"Джебель ш.\", \"tk\": \"Jebel ş.\"}",
|
||||
"created_at": "2023-05-24 16:33:15",
|
||||
"updated_at": "2023-05-24 16:39:39"
|
||||
},
|
||||
{
|
||||
"id": 69,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Edge\", \"ru\": \"Кенар\", \"tk\": \"Kenar\"}",
|
||||
"created_at": "2023-05-24 17:23:40",
|
||||
"updated_at": "2023-05-24 17:23:40"
|
||||
},
|
||||
{
|
||||
"id": 70,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Serdar\", \"ru\": \"Сердар\", \"tk\": \"Serdar\"}",
|
||||
"created_at": "2023-05-25 16:36:42",
|
||||
"updated_at": "2023-05-25 16:36:42"
|
||||
},
|
||||
{
|
||||
"id": 71,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Ekerem şäherçe\", \"ru\": \"Экерем ш.\", \"tk\": \"Ekerem şäherçe\"}",
|
||||
"created_at": "2023-05-25 16:53:18",
|
||||
"updated_at": "2023-05-25 16:53:18"
|
||||
},
|
||||
{
|
||||
"id": 72,
|
||||
"region": "bn",
|
||||
"name": "{\"en\": \"Garadepe ş.\", \"ru\": \"Гарадепе ш.\", \"tk\": \"Garadepe ş.\"}",
|
||||
"created_at": "2023-05-25 17:09:27",
|
||||
"updated_at": "2023-05-25 17:09:27"
|
||||
},
|
||||
{
|
||||
"id": 73,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Bagtyýar zaman oba\", \"ru\": \"Багтыйар заман село\", \"tk\": \"Bagtyýar zaman oba\"}",
|
||||
"created_at": "2023-05-26 15:15:20",
|
||||
"updated_at": "2023-05-26 15:15:20"
|
||||
},
|
||||
{
|
||||
"id": 74,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Al Horezmi\", \"ru\": \"Ал Хорезми\", \"tk\": \"Al Horezmi\"}",
|
||||
"created_at": "2023-05-26 15:37:43",
|
||||
"updated_at": "2023-05-26 15:37:43"
|
||||
},
|
||||
{
|
||||
"id": 75,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Jeýhun\", \"ru\": \"Джейхун\", \"tk\": \"Jeýhun\"}",
|
||||
"created_at": "2023-05-26 15:58:35",
|
||||
"updated_at": "2023-05-26 15:58:35"
|
||||
},
|
||||
{
|
||||
"id": 76,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Azady\", \"ru\": \"Азады\", \"tk\": \"Azady\"}",
|
||||
"created_at": "2023-05-26 16:12:52",
|
||||
"updated_at": "2023-05-26 16:12:52"
|
||||
},
|
||||
{
|
||||
"id": 77,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Baýramhan\", \"ru\": \"Байрамхан\", \"tk\": \"Baýramhan\"}",
|
||||
"created_at": "2023-05-26 16:21:31",
|
||||
"updated_at": "2023-05-26 16:21:31"
|
||||
},
|
||||
{
|
||||
"id": 78,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Ruhnama\", \"ru\": \"Рухнама\", \"tk\": \"Ruhnama\"}",
|
||||
"created_at": "2023-05-29 14:53:11",
|
||||
"updated_at": "2023-05-29 14:53:11"
|
||||
},
|
||||
{
|
||||
"id": 79,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Magtymguly\", \"ru\": \"Махтумкули\", \"tk\": \"Magtymguly\"}",
|
||||
"created_at": "2023-05-29 14:58:36",
|
||||
"updated_at": "2023-05-29 14:58:36"
|
||||
},
|
||||
{
|
||||
"id": 80,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Ýalkym\", \"ru\": \"Ялкым\", \"tk\": \"Ýalkym\"}",
|
||||
"created_at": "2023-05-29 15:03:57",
|
||||
"updated_at": "2023-05-29 15:03:57"
|
||||
},
|
||||
{
|
||||
"id": 81,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Türkmenbaşy şaýoly\", \"ru\": \"Туркменбаши шайолы\", \"tk\": \"Türkmenbaşy şaýoly\"}",
|
||||
"created_at": "2023-05-29 15:26:24",
|
||||
"updated_at": "2023-05-29 15:28:05"
|
||||
},
|
||||
{
|
||||
"id": 82,
|
||||
"region": "dz",
|
||||
"name": "{\"en\": \"Oguzhan\", \"ru\": \"Огузхан\", \"tk\": \"Oguzhan\"}",
|
||||
"created_at": "2023-05-29 15:36:50",
|
||||
"updated_at": "2023-05-29 15:36:50"
|
||||
},
|
||||
{
|
||||
"id": 83,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Türkmenabat ş\", \"ru\": \"Туркменабат ш\", \"tk\": \"Türkmenabat ş\"}",
|
||||
"created_at": "2023-05-29 15:55:51",
|
||||
"updated_at": "2023-05-29 15:55:51"
|
||||
},
|
||||
{
|
||||
"id": 84,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Farap\", \"ru\": \"Фарап\", \"tk\": \"Farap\"}",
|
||||
"created_at": "2023-05-30 15:09:46",
|
||||
"updated_at": "2023-05-30 15:09:46"
|
||||
},
|
||||
{
|
||||
"id": 85,
|
||||
"region": "lb",
|
||||
"name": "{\"en\": \"Döwletli\", \"ru\": \"Довлетли\", \"tk\": \"Döwletli\"}",
|
||||
"created_at": "2023-05-30 17:34:41",
|
||||
"updated_at": "2023-05-30 17:34:41"
|
||||
},
|
||||
{
|
||||
"id": 86,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Mollanepes k.\", \"ru\": \"Молланепес к.\", \"tk\": \"Mollanepes k.\"}",
|
||||
"created_at": "2023-06-01 14:46:03",
|
||||
"updated_at": "2023-06-01 14:46:03"
|
||||
},
|
||||
{
|
||||
"id": 87,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Parahatlyk k.\", \"ru\": \"Парахатлык к.\", \"tk\": \"Parahatlyk k.\"}",
|
||||
"created_at": "2023-06-01 14:49:45",
|
||||
"updated_at": "2023-06-01 14:49:45"
|
||||
},
|
||||
{
|
||||
"id": 88,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Kemine k.\", \"ru\": \"Кемине к.\", \"tk\": \"Kemine k.\"}",
|
||||
"created_at": "2023-06-01 14:56:09",
|
||||
"updated_at": "2023-06-01 14:56:09"
|
||||
},
|
||||
{
|
||||
"id": 89,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Bagtyýarlyk k.\", \"ru\": \"Багтыярлык к.\", \"tk\": \"Bagtyýarlyk k.\"}",
|
||||
"created_at": "2023-06-01 15:03:22",
|
||||
"updated_at": "2023-06-01 15:03:22"
|
||||
},
|
||||
{
|
||||
"id": 90,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Güneş ş.\", \"ru\": \"Гюнеш ш.\", \"tk\": \"Güneş ş.\"}",
|
||||
"created_at": "2023-06-01 15:14:30",
|
||||
"updated_at": "2023-06-01 15:14:30"
|
||||
},
|
||||
{
|
||||
"id": 91,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Türkmenbaşy ş.\", \"ru\": \"Туркменбаши ш.\", \"tk\": \"Türkmenbaşy ş.\"}",
|
||||
"created_at": "2023-06-01 15:24:42",
|
||||
"updated_at": "2023-06-01 15:24:42"
|
||||
},
|
||||
{
|
||||
"id": 92,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Şatlyk ş\", \"ru\": \"Шатлык ш\", \"tk\": \"Şatlyk ş\"}",
|
||||
"created_at": "2023-06-01 15:40:12",
|
||||
"updated_at": "2023-06-01 15:40:12"
|
||||
},
|
||||
{
|
||||
"id": 93,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Oguzhan ş.\", \"ru\": \"Огузхан ш.\", \"tk\": \"Oguzhan ş.\"}",
|
||||
"created_at": "2023-06-01 16:25:28",
|
||||
"updated_at": "2023-06-01 16:25:28"
|
||||
},
|
||||
{
|
||||
"id": 94,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Oguzhan\", \"ru\": \"Огузхан\", \"tk\": \"Oguzhan\"}",
|
||||
"created_at": "2023-06-01 16:31:14",
|
||||
"updated_at": "2023-06-01 16:31:14"
|
||||
},
|
||||
{
|
||||
"id": 95,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Hakykat d/b\", \"ru\": \"Хакукат д/б\", \"tk\": \"Hakykat d/b\"}",
|
||||
"created_at": "2023-06-01 16:37:04",
|
||||
"updated_at": "2023-06-01 16:37:04"
|
||||
},
|
||||
{
|
||||
"id": 96,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Peşanaly ş.\", \"ru\": \"Пешаналы ш.\", \"tk\": \"Peşanaly ş.\"}",
|
||||
"created_at": "2023-06-01 16:48:10",
|
||||
"updated_at": "2023-06-01 16:48:10"
|
||||
},
|
||||
{
|
||||
"id": 97,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Türkmengala ş\", \"ru\": \"Туркменгала ш.\", \"tk\": \"Türkmengala ş\"}",
|
||||
"created_at": "2023-06-02 15:09:50",
|
||||
"updated_at": "2023-06-02 15:09:50"
|
||||
},
|
||||
{
|
||||
"id": 98,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Nurana Gurbanmyradow d/b\", \"ru\": \"Нурана Гурбанмурадов д/б\", \"tk\": \"Nurana Gurbanmyradow d/b\"}",
|
||||
"created_at": "2023-06-02 15:34:15",
|
||||
"updated_at": "2023-06-02 15:34:15"
|
||||
},
|
||||
{
|
||||
"id": 99,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"746470 +993 632 8-41-68\", \"ru\": \"Сариязи д/б\", \"tk\": \"Saryýazy d/b\"}",
|
||||
"created_at": "2023-06-02 16:33:22",
|
||||
"updated_at": "2023-06-02 16:33:22"
|
||||
},
|
||||
{
|
||||
"id": 100,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"746500 +993 624 5-43-97\", \"ru\": \"Сариджа\", \"tk\": \"Saryja\"}",
|
||||
"created_at": "2023-06-02 16:36:09",
|
||||
"updated_at": "2023-06-02 16:36:09"
|
||||
},
|
||||
{
|
||||
"id": 101,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Serhatabat ş.\", \"ru\": \"Серхетабат ш.\", \"tk\": \"Serhatabat ş.\"}",
|
||||
"created_at": "2023-06-02 16:48:42",
|
||||
"updated_at": "2023-06-02 16:48:42"
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Ýeňiş d/b\", \"ru\": \"Йениш д/б\", \"tk\": \"Ýeňiş d/b\"}",
|
||||
"created_at": "2023-06-02 16:52:04",
|
||||
"updated_at": "2023-06-02 16:52:04"
|
||||
},
|
||||
{
|
||||
"id": 103,
|
||||
"region": "mr",
|
||||
"name": "{\"en\": \"Serhetabat etr\", \"ru\": \"Серхетабат\", \"tk\": \"Serhetabat etr\"}",
|
||||
"created_at": "2023-06-02 16:56:52",
|
||||
"updated_at": "2023-06-02 16:56:52"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// 1. Create new pivot tables
|
||||
Schema::create('category_product', function (Blueprint $table) {
|
||||
$table->foreignId('product_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('category_id')->constrained()->cascadeOnDelete();
|
||||
// No primary key on pivot usually, but maybe composite unique?
|
||||
// product_has_relations didn't have one explicitly shown but usually pivots do.
|
||||
// Let's add an index for performance.
|
||||
$table->unique(['product_id', 'category_id']);
|
||||
});
|
||||
|
||||
Schema::create('collection_product', function (Blueprint $table) {
|
||||
$table->foreignId('product_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('collection_id')->constrained()->cascadeOnDelete();
|
||||
$table->unique(['product_id', 'collection_id']);
|
||||
});
|
||||
|
||||
Schema::create('channel_product', function (Blueprint $table) {
|
||||
$table->foreignId('product_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('channel_id')->constrained()->cascadeOnDelete();
|
||||
$table->unique(['product_id', 'channel_id']);
|
||||
});
|
||||
|
||||
Schema::create('product_related', function (Blueprint $table) {
|
||||
$table->foreignId('product_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('related_product_id')->constrained('products')->cascadeOnDelete();
|
||||
$table->unique(['product_id', 'related_product_id']);
|
||||
});
|
||||
|
||||
// 2. Migrate data
|
||||
// Using raw SQL for efficiency and simplicity
|
||||
DB::statement("INSERT INTO category_product (product_id, category_id) SELECT product_id, productable_id FROM product_has_relations WHERE productable_type = 'category'");
|
||||
DB::statement("INSERT INTO collection_product (product_id, collection_id) SELECT product_id, productable_id FROM product_has_relations WHERE productable_type = 'collection'");
|
||||
DB::statement("INSERT INTO channel_product (product_id, channel_id) SELECT product_id, productable_id FROM product_has_relations WHERE productable_type = 'channel'");
|
||||
DB::statement("INSERT INTO product_related (product_id, related_product_id) SELECT product_id, productable_id FROM product_has_relations WHERE productable_type = 'product'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('category_product');
|
||||
Schema::dropIfExists('collection_product');
|
||||
Schema::dropIfExists('channel_product');
|
||||
Schema::dropIfExists('product_related');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('user_addresses', function (Blueprint $table) {
|
||||
$table->string('title')->nullable();
|
||||
$table->string('building')->nullable();
|
||||
$table->string('floor')->nullable();
|
||||
$table->string('door')->nullable();
|
||||
$table->string('location')->nullable();
|
||||
|
||||
$table->dropColumn('first_name');
|
||||
$table->dropColumn('last_name');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('user_addresses', function (Blueprint $table) {
|
||||
$table->dropColumn('title');
|
||||
$table->dropColumn('building');
|
||||
$table->dropColumn('floor');
|
||||
$table->dropColumn('door');
|
||||
$table->dropColumn('location');
|
||||
$table->string('first_name')->nullable();
|
||||
$table->string('last_name')->nullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('orders', function (Blueprint $table) {
|
||||
$table->jsonb('options')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('orders', function (Blueprint $table) {
|
||||
$table->dropColumn('options');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('selected_categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->jsonb('name');
|
||||
$table->jsonb('description')->nullable();
|
||||
$table->boolean('is_visible')->default(true);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('selected_categories');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('category_selected_category', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('selected_category_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('category_id')->constrained()->cascadeOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('category_selected_category');
|
||||
}
|
||||
};
|
||||
@@ -2,8 +2,23 @@
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Database\Seeders\New\AddressSeeder;
|
||||
use Database\Seeders\New\BrandsSeeder;
|
||||
use Database\Seeders\New\CategoriesTableSeeder;
|
||||
use Database\Seeders\New\CustomersTableSeeder;
|
||||
use Database\Seeders\New\FavoritesSeeder;
|
||||
use Database\Seeders\New\MediaSeeder;
|
||||
use Database\Seeders\New\OrderAddressSeeder;
|
||||
use Database\Seeders\New\OrderSeeder;
|
||||
use Database\Seeders\New\ProductBarcodesSeeder;
|
||||
use Database\Seeders\New\ProductCategoryRelationshipsSeeder;
|
||||
use Database\Seeders\New\ProductPricesSeeder;
|
||||
use Database\Seeders\New\ProductPropertiesSeeder;
|
||||
use Database\Seeders\New\ProductPropertyValuesSeeder;
|
||||
use Database\Seeders\New\ProductsTableSeeder;
|
||||
use Database\Seeders\New\ProductStocksSeeder;
|
||||
use Database\Seeders\New\PropertiesTableSeeder;
|
||||
use Database\Seeders\New\SectionsSeeder;
|
||||
use Database\Seeders\New\SellersTableSeeder;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
@@ -18,11 +33,27 @@ class DatabaseSeeder extends Seeder
|
||||
public function run(): void
|
||||
{
|
||||
$this->call([
|
||||
// ProvincesTableSeeder::class,
|
||||
// PaymentTypeSeeder::class,
|
||||
// UsersTableSeeder::class,
|
||||
// BrandsSeeder::class,
|
||||
// CustomersTableSeeder::class,
|
||||
SellersTableSeeder::class,
|
||||
// InventoriesTableSeeder::class,
|
||||
// BrandsSeeder::class,
|
||||
// CustomersTableSeeder::class,
|
||||
// SellersTableSeeder::class,
|
||||
// ProductsTableSeeder::class,
|
||||
// ProductPricesSeeder::class,
|
||||
// CategoriesTableSeeder::class,
|
||||
// AddressSeeder::class,
|
||||
// PropertiesTableSeeder::class,
|
||||
// FavoritesSeeder::class,
|
||||
// SectionsSeeder::class,
|
||||
// ProductCategoryRelationshipsSeeder::class,
|
||||
// ProductBarcodesSeeder::class,
|
||||
// ProductPropertiesSeeder::class,
|
||||
// ProductPropertyValuesSeeder::class,
|
||||
// ProductStocksSeeder::class,
|
||||
// MediaSeeder::class,
|
||||
// OrderSeeder::class,
|
||||
// OrderAddressSeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
42
database/seeders/PaymentTypeSeeder.php
Normal file
42
database/seeders/PaymentTypeSeeder.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\System\Settings\Payments\PaymentType;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class PaymentTypeSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
collect([
|
||||
[
|
||||
'id' => 1,
|
||||
'code' => 'cash',
|
||||
'name' => ['en' => 'Cash', 'tk' => 'Nagt', 'ru' => 'Näliçni'],
|
||||
'tax' => 0,
|
||||
'is_enabled' => true,
|
||||
'options' => null,
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'code' => 'atm',
|
||||
'name' => ['en' => 'ATM', 'tk' => 'Terminal', 'ru' => 'ATM'],
|
||||
'tax' => 0,
|
||||
'is_enabled' => true,
|
||||
'options' => null,
|
||||
],
|
||||
[
|
||||
'id' => 3,
|
||||
'code' => 'online_halkbank',
|
||||
'name' => ['en' => 'Online (halkbank)', 'tk' => 'Onlaýn (halkbank)', 'ru' => 'Onlaýn (halkbank)'],
|
||||
'tax' => 0,
|
||||
'is_enabled' => true,
|
||||
'options' => null,
|
||||
],
|
||||
])->each(fn ($data) => PaymentType::create($data));
|
||||
}
|
||||
}
|
||||
38
database/seeders/ProvincesTableSeeder.php
Normal file
38
database/seeders/ProvincesTableSeeder.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class ProvincesTableSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$datas = json_decode(File::get('database/data/provinces.json'));
|
||||
|
||||
$table = 'provinces';
|
||||
foreach ($datas as $data) {
|
||||
try {
|
||||
DB::table($table)->insert([
|
||||
'id' => $data->id,
|
||||
'region' => $data->region,
|
||||
'name' => $data->name,
|
||||
'created_at' => $data->created_at,
|
||||
'updated_at' => $data->updated_at,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
info(['province db erorr: ' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use App\Models\Ecommerce\Product\Inventory\Inventory;
|
||||
use App\Models\System\Roles\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
@@ -22,7 +24,7 @@ class UsersTableSeeder extends Seeder
|
||||
*/
|
||||
public function seedStarterKit(): void
|
||||
{
|
||||
$this->seedRoles();
|
||||
// $this->seedRoles();
|
||||
|
||||
collect([
|
||||
[
|
||||
@@ -36,6 +38,8 @@ class UsersTableSeeder extends Seeder
|
||||
|
||||
$user->assignRole('admin');
|
||||
});
|
||||
|
||||
// $this->createChannels();
|
||||
}
|
||||
|
||||
public function seedRoles(): void
|
||||
@@ -76,4 +80,31 @@ class UsersTableSeeder extends Seeder
|
||||
SELECT setval('roles_id_seq', (SELECT MAX(id) from roles))
|
||||
");
|
||||
}
|
||||
|
||||
public function createChannels(): void
|
||||
{
|
||||
collect([
|
||||
[
|
||||
'name' => 'Tmpost',
|
||||
'slug' => 'tmpost',
|
||||
'description' => 'Tmpost default',
|
||||
'timezone' => 'Asia/Ashgabat',
|
||||
'url' => 'http://shop.post.tm',
|
||||
'is_default' => true,
|
||||
],
|
||||
])->each(fn ($data) => Channel::create($data));
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('channels_id_seq', (SELECT MAX(id) from channels))
|
||||
");
|
||||
|
||||
Inventory::create([
|
||||
'id' => 14,
|
||||
'code' => 'tmpost',
|
||||
'name' => 'Tmpost inventory',
|
||||
'region' => 'ag',
|
||||
'phone_number' => '99361099310',
|
||||
'channel_id' => Channel::where('slug', 'tmpost')->first()->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
56
database/seeders/new/AddressSeeder.php
Normal file
56
database/seeders/new/AddressSeeder.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class AddressSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'user_addresses';
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/addresses.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
// First we need to fill user_addresses table with json data, then find user id matching addressable_id and fill user options with {"address": "$data"}
|
||||
|
||||
foreach ($items as $data) {
|
||||
try {
|
||||
DB::table($table)->insert([
|
||||
'id' => $data['id'],
|
||||
'user_id' => $data['addressable_id'],
|
||||
'street_address' => $data['address'],
|
||||
'title' => $data['title'],
|
||||
'building' => $data['building'],
|
||||
'floor' => $data['floor'],
|
||||
'door' => $data['door'],
|
||||
'location' => $data['location'],
|
||||
'type' => $data['type'],
|
||||
'created_at' => $data['created_at'],
|
||||
'updated_at' => $data['updated_at'],
|
||||
'is_default' => false,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$user = User::where('id', $data['addressable_id'])->first();
|
||||
if ($user) {
|
||||
info($user);
|
||||
$user->options->set('address', $data['address']);
|
||||
$user->save();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,12 @@ class BrandsSeeder extends Seeder
|
||||
DB::table($table)->truncate();
|
||||
|
||||
foreach ($datas as $data) {
|
||||
DB::table($table)->insertOrIgnore([
|
||||
$name = json_decode($data->name);
|
||||
|
||||
DB::table($table)->insert([
|
||||
'id' => $data->id,
|
||||
'slug' => Str::slug(json_decode($data->name)->en ?? $data->code),
|
||||
'name' => $data->name,
|
||||
'slug' => Str::slug($name->en ?? $data->code).'_'.$data->id,
|
||||
'name' => $name->en,
|
||||
'is_visible' => $data->is_blocked,
|
||||
'sort_order' => $data->priority,
|
||||
'created_at' => $data->created_at,
|
||||
|
||||
41
database/seeders/new/CategoriesTableSeeder.php
Normal file
41
database/seeders/new/CategoriesTableSeeder.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class CategoriesTableSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'categories';
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/categories.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
DB::table($table)->insert([
|
||||
'id' => $data['id'],
|
||||
'parent_id' => $data['parent_id'],
|
||||
'slug' => $data['slug'],
|
||||
'name' => str_replace('"tm"', '"tk"', $data['name']),
|
||||
'is_visible' => $data['is_blocked'],
|
||||
'sort_order' => $data['priority'],
|
||||
'tax_percentage' => $data['percentage'],
|
||||
'created_at' => $data['created_at'],
|
||||
'updated_at' => $data['updated_at'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
});
|
||||
}
|
||||
}
|
||||
29
database/seeders/new/FavoritesSeeder.php
Normal file
29
database/seeders/new/FavoritesSeeder.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class FavoritesSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$datas = json_decode(File::get('database/data/favorite_products.json'));
|
||||
$table = 'favorites';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
foreach ($datas as $data) {
|
||||
DB::table($table)->insert([
|
||||
'user_id' => $data->customer_id,
|
||||
'product_id' => $data->item_id,
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
}
|
||||
}
|
||||
64
database/seeders/new/MediaSeeder.php
Normal file
64
database/seeders/new/MediaSeeder.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class MediaSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'media';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/media.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
$modelType = match ($data['model_type']) {
|
||||
'Domain\Brand\Models\Brand' => 'brand',
|
||||
'Domain\Category\Models\Category' => 'category',
|
||||
'Domain\Item\Models\Item' => 'product',
|
||||
'Domain\Promo\Models\Banner' => 'banner',
|
||||
'Domain\Promo\Models\Carousel' => 'channel',
|
||||
};
|
||||
|
||||
if ($modelType === 'banner') {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table($table)->insert([
|
||||
'id' => $data['id'],
|
||||
'model_type' => $modelType,
|
||||
'model_id' => $data['model_id'],
|
||||
'uuid' => $data['uuid'],
|
||||
'collection_name' => 'uploads',
|
||||
'name' => $data['name'],
|
||||
'file_name' => $data['file_name'],
|
||||
'mime_type' => $data['mime_type'],
|
||||
'disk' => $data['disk'],
|
||||
'conversions_disk' => $data['conversions_disk'],
|
||||
'size' => $data['size'],
|
||||
'manipulations' => $data['manipulations'],
|
||||
'custom_properties' => $data['custom_properties'],
|
||||
'generated_conversions' => $data['generated_conversions'],
|
||||
'responsive_images' => $data['responsive_images'],
|
||||
'order_column' => $data['order_column'],
|
||||
'created_at' => $data['created_at'],
|
||||
'updated_at' => $data['updated_at'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
});
|
||||
}
|
||||
}
|
||||
30
database/seeders/new/OrderAddressSeeder.php
Normal file
30
database/seeders/new/OrderAddressSeeder.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class OrderAddressSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$items = Items::fromFile(
|
||||
database_path('data/order_address.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
DB::table('orders')->where('id', $data['order_id'])->update([
|
||||
'customer_address' => $data['address'],
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
119
database/seeders/new/OrderSeeder.php
Normal file
119
database/seeders/new/OrderSeeder.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class OrderSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$this->fillOrders();
|
||||
$this->fillOrderItems();
|
||||
}
|
||||
|
||||
private function fillOrderItems()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'order_items';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/order_items.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
$channel_id = DB::table('channel_product')->where('product_id', $data['item_id'])->first()->channel_id ?? tmpostChannel()->id;
|
||||
|
||||
DB::table($table)->insert([
|
||||
'id' => $data['id'],
|
||||
'order_id' => $data['order_id'],
|
||||
'product_id' => $data['item_id'],
|
||||
'quantity' => $data['quantity'],
|
||||
'unit_price_amount' => $data['price'],
|
||||
|
||||
'channel_id' => $channel_id,
|
||||
|
||||
'created_at' => $data['created_at'],
|
||||
'updated_at' => $data['updated_at'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
});
|
||||
}
|
||||
|
||||
private function fillOrders()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'orders';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/orders.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
DB::table($table)->insert([
|
||||
'id' => $data['id'],
|
||||
'number' => Str::random(30),
|
||||
'user_id' => $data['customer_id'],
|
||||
'options' => sprintf('{"seller_id":"%s","warehouse_id":"%s"}', $data['seller_id'], $data['warehouse_id']),
|
||||
'status' => $this->formatStatus($data['status']),
|
||||
'shipping_method' => $this->formatShippingMethod($data['delivery_type']),
|
||||
'payment_type_id' => $this->formatPaymentType($data['payment_type']),
|
||||
'notes' => $data['note'],
|
||||
'created_at' => $data['created_at'],
|
||||
'updated_at' => $data['updated_at'],
|
||||
'deleted_at' => $data['deleted_at'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
});
|
||||
}
|
||||
|
||||
private function formatStatus(string $status): string
|
||||
{
|
||||
return match ($status) {
|
||||
'DRAFT' => OrderStatus::PENDING,
|
||||
'COMPLETED' => OrderStatus::COMPLETED,
|
||||
'DELIVERED' => OrderStatus::COMPLETED,
|
||||
'CANCELLED' => OrderStatus::CANCELLED,
|
||||
default => OrderStatus::default(),
|
||||
};
|
||||
}
|
||||
|
||||
private function formatShippingMethod($shippingMethod): string
|
||||
{
|
||||
return match ($shippingMethod) {
|
||||
'PICK_UP' => OrderShipping::SELF_PICKUP,
|
||||
'EXPRESS_DELIVERY' => OrderShipping::EXPRESS,
|
||||
'SELECTED_DELIVERY' => OrderShipping::STANDART,
|
||||
default => OrderShipping::default(),
|
||||
};
|
||||
}
|
||||
|
||||
private function formatPaymentType($paymentType): int
|
||||
{
|
||||
return match ($paymentType) {
|
||||
'CASH' => 1,
|
||||
'CARD' => 2,
|
||||
default => 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
30
database/seeders/new/ProductBarcodesSeeder.php
Normal file
30
database/seeders/new/ProductBarcodesSeeder.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class ProductBarcodesSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'products';
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/item_barcodes.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
// item_id is product id, I need to find product and update price_amount to $data['value'] and cost_amount to $data['cost_value']
|
||||
DB::table($table)->where('id', $data['item_id'])->update([
|
||||
'barcode' => $data['barcode'],
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
35
database/seeders/new/ProductCategoryRelationshipsSeeder.php
Normal file
35
database/seeders/new/ProductCategoryRelationshipsSeeder.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class ProductCategoryRelationshipsSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'category_product';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/categorizables.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
if ($data['categorizable_type'] == 'Domain\\Item\\Models\\Item') {
|
||||
DB::table($table)->insert([
|
||||
'product_id' => $data['categorizable_id'],
|
||||
'category_id' => $data['category_id'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
31
database/seeders/new/ProductPricesSeeder.php
Normal file
31
database/seeders/new/ProductPricesSeeder.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class ProductPricesSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'products';
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/prices.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
// item_id is product id, I need to find product and update price_amount to $data['value'] and cost_amount to $data['cost_value']
|
||||
DB::table($table)->where('id', $data['item_id'])->update([
|
||||
'price_amount' => $data['value'],
|
||||
'cost_amount' => $data['cost_value'],
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
32
database/seeders/new/ProductPropertiesSeeder.php
Normal file
32
database/seeders/new/ProductPropertiesSeeder.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class ProductPropertiesSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'product_attributes';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/item_properties.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
DB::table($table)->insert([
|
||||
'product_id' => $data['item_id'],
|
||||
'attribute_id' => $data['property_id'],
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
80
database/seeders/new/ProductPropertyValuesSeeder.php
Normal file
80
database/seeders/new/ProductPropertyValuesSeeder.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class ProductPropertyValuesSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$propertyWithValues = $this->fillPropertyValues();
|
||||
$this->fillProductPropertyValues($propertyWithValues);
|
||||
}
|
||||
|
||||
private function fillPropertyValues()
|
||||
{
|
||||
$propertyWithValues = collect();
|
||||
|
||||
DB::transaction(function () use (&$propertyWithValues) {
|
||||
$table = 'attribute_values';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/property_values.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
DB::table($table)->insert([
|
||||
'id' => $data['id'],
|
||||
'key' => $data['id'],
|
||||
'attribute_id' => $data['property_id'],
|
||||
'value' => str_replace('"tm"', '"tk"', $data['name']),
|
||||
'created_at' => $data['created_at'],
|
||||
'updated_at' => $data['updated_at'],
|
||||
]);
|
||||
|
||||
$propertyWithValues->push([
|
||||
'attribute_id' => $data['property_id'],
|
||||
'value_id' => $data['id'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
});
|
||||
|
||||
return $propertyWithValues;
|
||||
}
|
||||
|
||||
private function fillProductPropertyValues($propertyWithValues)
|
||||
{
|
||||
DB::transaction(function () use ($propertyWithValues) {
|
||||
$table = 'attribute_value_product_attribute';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/item_property_values.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
DB::table($table)->insert([
|
||||
'product_attribute_id' => $propertyWithValues->firstWhere('value_id', $data['property_value_id'])['attribute_id'],
|
||||
'attribute_value_id' => $data['property_value_id'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
});
|
||||
}
|
||||
}
|
||||
39
database/seeders/new/ProductStocksSeeder.php
Normal file
39
database/seeders/new/ProductStocksSeeder.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class ProductStocksSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$items = Items::fromFile(
|
||||
database_path('data/stocks.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
// First we update stock in products table, then in inventory_product table
|
||||
foreach ($items as $data) {
|
||||
DB::table('products')->where('id', $data['item_id'])->update([
|
||||
'stock' => $data['quantity'],
|
||||
]);
|
||||
|
||||
DB::table('inventory_product')
|
||||
->insert([
|
||||
'product_id' => $data['item_id'],
|
||||
'inventory_id' => $data['warehouse_id'],
|
||||
'stock' => $data['quantity'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('inventory_product_id_seq', (SELECT MAX(id) from inventory_product))
|
||||
");
|
||||
});
|
||||
}
|
||||
}
|
||||
59
database/seeders/new/ProductsTableSeeder.php
Normal file
59
database/seeders/new/ProductsTableSeeder.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ExtJsonDecoder;
|
||||
|
||||
class ProductsTableSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$table = 'products';
|
||||
$users = User::whereNotNull('options->old_customer_id')->get();
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
$items = Items::fromFile(
|
||||
database_path('data/items.json'),
|
||||
['decoder' => new ExtJsonDecoder(true)]
|
||||
);
|
||||
|
||||
foreach ($items as $data) {
|
||||
$name = json_decode($data['name']);
|
||||
$description = json_decode($data['description']);
|
||||
|
||||
DB::table($table)->insert([
|
||||
'id' => $data['id'],
|
||||
'sku' => $data['sku'],
|
||||
'name' => $name->tm ?? $name->en ?? '',
|
||||
'slug' => $data['slug'],
|
||||
'description' => $description->tm ?? $description->en ?? '',
|
||||
'brand_id' => $data['brand_id'],
|
||||
'is_visible' => $data['is_blocked'],
|
||||
'created_at' => $data['created_at'],
|
||||
'updated_at' => $data['updated_at'],
|
||||
]);
|
||||
|
||||
// We find user with $data->seller_id matching old_customer_id in options, then we get users channel and attach product to it
|
||||
$user = $users->firstWhere(function ($user) use ($data) {
|
||||
return $user->options['old_customer_id'] == $data['seller_id'];
|
||||
});
|
||||
|
||||
$channel = $user ? $user->channel() : tmpostChannel();
|
||||
DB::table('channel_product')->insert([
|
||||
'product_id' => $data['id'],
|
||||
'channel_id' => $channel->id,
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
});
|
||||
}
|
||||
}
|
||||
34
database/seeders/new/PropertiesTableSeeder.php
Normal file
34
database/seeders/new/PropertiesTableSeeder.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class PropertiesTableSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$datas = json_decode(File::get('database/data/properties.json'));
|
||||
$table = 'attributes';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
foreach ($datas as $data) {
|
||||
DB::table($table)->insertOrIgnore([
|
||||
'id' => $data->id,
|
||||
'slug' => $data->code,
|
||||
'name' => str_replace('"tm"', '"tk"', $data->name),
|
||||
'description' => $data->description,
|
||||
'type' => 'text',
|
||||
'created_at' => $data->created_at,
|
||||
'updated_at' => $data->updated_at,
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
}
|
||||
}
|
||||
37
database/seeders/new/SectionsSeeder.php
Normal file
37
database/seeders/new/SectionsSeeder.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\New;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SectionsSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$datas = json_decode(File::get('database/data/sections.json'));
|
||||
$table = 'collections';
|
||||
|
||||
DB::table($table)->truncate();
|
||||
|
||||
foreach ($datas as $data) {
|
||||
DB::table($table)->insert([
|
||||
'id' => $data->id,
|
||||
'name' => str_replace('"tm"', '"tk"', $data->title),
|
||||
'slug' => Str::slug($data->title).'_'.$data->id,
|
||||
'is_visible' => ! $data->is_blocked,
|
||||
'sort_order' => $data->priority,
|
||||
'created_at' => $data->created_at,
|
||||
'updated_at' => $data->updated_at,
|
||||
]);
|
||||
}
|
||||
|
||||
DB::statement("
|
||||
SELECT setval('{$table}_id_seq', (SELECT MAX(id) from {$table}))
|
||||
");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ class SellersTableSeeder extends Seeder
|
||||
'email' => $data->email,
|
||||
'phone_number' => Str::after($data->phone, '993'),
|
||||
'password' => Hash::make('12345678'),
|
||||
'options' => sprintf('{"old_customer_id":"%s"}', $data->id),
|
||||
]);
|
||||
|
||||
$user->assignRole('vendor');
|
||||
|
||||
@@ -363,6 +363,7 @@
|
||||
"Seller": "Satyjy",
|
||||
"View products": "Harytlary gör",
|
||||
"Sections": "Bölümler",
|
||||
"Section": "Bölüm",
|
||||
"Product count": "Haryt sany",
|
||||
"Count": "Sany",
|
||||
"Shipping rates": "Eltip bermek nyrhnamasy",
|
||||
@@ -397,5 +398,6 @@
|
||||
"Inventory exit": "Çykyş",
|
||||
"Total count": "Jemi sany",
|
||||
"Verification code is incorrect": "Tassyklaýyş belgi ýalňyş",
|
||||
"User with this phone number does not exist": "GIrizilen telefon belgili ulanyjy tapylmady"
|
||||
"User with this phone number does not exist": "GIrizilen telefon belgili ulanyjy tapylmady",
|
||||
"Page not found": "Sahypa tapylmady"
|
||||
}
|
||||
|
||||
219
resources/views/errors/404.blade.php
Normal file
219
resources/views/errors/404.blade.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>404 - Page Not Found</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #0a1821;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
font-family: Roboto, Arial, sans-serif;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.not-found {
|
||||
width: 560px;
|
||||
height: 225px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.starry-sky {
|
||||
display: block;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.notfound-copy {
|
||||
color: #fff;
|
||||
position: fixed;
|
||||
top: 25px;
|
||||
right: 10%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 700;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 300;
|
||||
color: #fff;
|
||||
border-bottom: 1.5px solid #5581d4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
font-weight: 300;
|
||||
color: #fff;
|
||||
border-bottom: 2px solid #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* change to alternating star opacities */
|
||||
.all-stars {
|
||||
animation: blinkblink 4s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes blinkblink {
|
||||
50% {
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(-25px);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
}
|
||||
|
||||
.floating-object {
|
||||
animation: float 3s ease-in-out infinite;
|
||||
transform-box: fill-box;
|
||||
}
|
||||
|
||||
.moon {}
|
||||
|
||||
input[type=text] {
|
||||
color: #fff;
|
||||
background-color: #0a1821;
|
||||
padding: 5px;
|
||||
border: none;
|
||||
border-bottom: 2px solid #ccc;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
input[type=text]:focus {
|
||||
border-color: none;
|
||||
border-bottom: 2px solid #ccc;
|
||||
}
|
||||
|
||||
@media (max-width: 647px) {
|
||||
.moon {
|
||||
padding-top: -500px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="notfound-copy">
|
||||
<svg aria-labelledby="404" alt="404 Page not found" class="not-found">
|
||||
<title id="svgtitle1">404 Page not found</title>
|
||||
<g class="404-text floating-object">
|
||||
<g opacity=".5" fill="#3B3D3D">
|
||||
<path
|
||||
d="M320.1 209.5c0 7.2-6 12.5-13.7 12.5s-13.7-5.4-13.7-12.5v-16.3h-43.8c-8.4 0-14.1-6.4-14.1-13.5 0-.8.8-4.4 2-7L275 84.5c2-4.8 7.2-7.8 12.3-7.8 6.8 0 13.7 6 13.7 12.9 0 1.2 0 2.6-.8 4.4-11.5 26.7-20.9 47.6-32.4 74.2h24.9v-30.4c0-7.2 6-12.5 13.7-12.5 7.4 0 13.7 5.4 13.7 12.5v30.4h2.6c7.6 0 13.3 5.8 13.3 12.3 0 7-5.8 12.5-13.3 12.5h-2.6v16.5zM436.9 123.9v54.7c0 24.3-16.3 43.6-46 43.6s-46-19.3-46-43.6v-54.7c0-26.3 13.9-47.4 46-47.4 32.1.1 46 21.2 46 47.4zm-64.3-1.4v56.1c0 11.3 6.4 19.1 18.3 19.1s18.3-7.8 18.3-19.1v-56.1c0-12.7-5.2-21.7-18.3-21.7s-18.3 9-18.3 21.7zM535 209.5c0 7.2-6 12.5-13.7 12.5s-13.7-5.4-13.7-12.5v-16.3h-43.8c-8.4 0-14.1-6.4-14.1-13.5 0-.8.8-4.4 2-7l38.2-88.2c2-4.8 7.2-7.8 12.3-7.8 6.8 0 13.7 6 13.7 12.9 0 1.2 0 2.6-.8 4.4-11.5 26.7-20.9 47.6-32.4 74.2h24.9v-30.4c0-7.2 6-12.5 13.7-12.5 7.4 0 13.7 5.4 13.7 12.5v30.4h2.6c7.6 0 13.3 5.8 13.3 12.3 0 7-5.8 12.5-13.3 12.5H535v16.5z" />
|
||||
</g>
|
||||
<g fill="#FFF">
|
||||
<path
|
||||
d="M326.4 197.5c0 7.2-6 12.5-13.7 12.5s-13.7-5.4-13.7-12.5v-16.3h-43.8c-8.4 0-14.1-6.4-14.1-13.5 0-.8.8-4.4 2-7l38.2-88.2c2-4.8 7.2-7.8 12.3-7.8 6.8 0 13.7 6 13.7 12.9 0 1.2 0 2.6-.8 4.4-11.5 26.7-20.9 47.6-32.4 74.2H299v-30.4c0-7.2 6-12.5 13.7-12.5 7.4 0 13.7 5.4 13.7 12.5v30.4h2.6c7.6 0 13.3 5.8 13.3 12.3 0 7-5.8 12.5-13.3 12.5h-2.6v16.5zM443.2 111.9v54.7c0 24.3-16.3 43.6-46 43.6s-46-19.3-46-43.6v-54.7c0-26.3 13.9-47.4 46-47.4 32.1.1 46 21.2 46 47.4zm-64.2-1.4v56.1c0 11.3 6.4 19.1 18.3 19.1s18.3-7.8 18.3-19.1v-56.1c0-12.7-5.2-21.7-18.3-21.7s-18.3 9-18.3 21.7zM541.4 197.5c0 7.2-6 12.5-13.7 12.5-7.8 0-13.7-5.4-13.7-12.5v-16.3h-43.8c-8.4 0-14.1-6.4-14.1-13.5 0-.8.8-4.4 2-7l38.2-88.2c2-4.8 7.2-7.8 12.3-7.8 6.8 0 13.7 6 13.7 12.9 0 1.2 0 2.6-.8 4.4-11.5 26.7-20.9 47.6-32.4 74.2H514v-30.4c0-7.2 6-12.5 13.7-12.5 7.4 0 13.7 5.4 13.7 12.5v30.4h2.6c7.6 0 13.3 5.8 13.3 12.3 0 7-5.8 12.5-13.3 12.5h-2.6v16.5z" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>{{ __('Page not found') }}</h1>
|
||||
<p><a href="/">{{ __('Home') }}</a></p>
|
||||
</div>
|
||||
|
||||
<svg aria-labelledby="Starry sky" alt="Starry sky" class="starry-sky">
|
||||
<title id="svgtitle2">Starry sky</title>
|
||||
<!-- STARS START -->
|
||||
<g class="all-stars" fill="#F6F5BC">
|
||||
<path class="stars-one"
|
||||
d="M148.9 151.5c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.7-6.2-6.2-6.2-6.2zM93.6 " />
|
||||
<path class="stars-two"
|
||||
d="M148.9 540.6c-4.9-1.6-6.2-6.2-6.2-6.2-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.8-.4-1zM526.3 551.7c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.7-6.2-6.2-6.2-6.2zM617.4 291.9c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.6-6.2-6.2-6.2-6.2zM681.9 42.7c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.7-6.2-6.2-6.2-6.2zM51.1 83.9c-.3-.3-.6-.4-1-.4s-.7.1-1 .4C47.5 88.8 43 90 43 90c-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5.1-1.6-6.3-6.1-6.3-6.1z" />
|
||||
<path class="all-stars"
|
||||
d="M148.9 151.5c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.7-6.2-6.2-6.2-6.2zM93.6 318.5c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.7-6.2-6.2-6.2-6.2zM132.3 169c-.2-.2-.4-.3-.6-.3s-.4.1-.6.3c-1 3.1-3.8 3.8-3.8 3.8-.2.2-.3.4-.3.6 0 .2.1.4.3.6 3.1 1 3.8 3.8 3.8 3.8.2.2.4.3.6.3s.4-.1.6-.3c1-3.1 3.8-3.8 3.8-3.8.2-.2.3-.4.3-.6 0-.2-.1-.4-.3-.6-3-.9-3.8-3.8-3.8-3.8zM585.9 269.5c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.7-6.2-6.2-6.2-6.2zM723.4 540.6c-4.9-1.6-6.2-6.2-6.2-6.2-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.8-.4-1zM526.3 551.7c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.7-6.2-6.2-6.2-6.2zM617.4 291.9c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.6-6.2-6.2-6.2-6.2zM681.9 42.7c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-1.6 4.9-6.2 6.2-6.2 6.2-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5-1.7-6.2-6.2-6.2-6.2zM51.1 83.9c-.3-.3-.6-.4-1-.4s-.7.1-1 .4C47.5 88.8 43 90 43 90c-.3.3-.4.6-.4 1s.1.7.4 1c4.9 1.6 6.2 6.2 6.2 6.2.3.3.6.4 1 .4s.7-.1 1-.4c1.6-4.9 6.2-6.2 6.2-6.2.3-.3.4-.6.4-1s-.1-.7-.4-1c-5.1-1.6-6.3-6.1-6.3-6.1z" />
|
||||
</g>
|
||||
<!-- Moon shadow -->
|
||||
<g class="moon">
|
||||
<g class="floating-object">
|
||||
<path opacity=".5" fill="#3B3D3D" d="M122.7 373.9L-237.1 744l283.8 269.4 279.9-492.8z" />
|
||||
<!-- Moon color base -->
|
||||
<g fill="#D1D5D6">
|
||||
<path
|
||||
d="M209 340.6c-70.9 0-128.4 57.5-128.4 128.4S138.1 597.4 209 597.4 337.4 539.9 337.4 469 279.9 340.6 209 340.6zm-41.9 176.1c0 10.9-8.9 19.8-19.8 19.8s-19.8-8.9-19.8-19.8c0-1.4.1-2.7.4-4-18.3-1.7-32.6-17-32.6-35.7 0-19.8 16.1-35.9 35.9-35.9 19.8 0 35.9 16.1 35.9 35.9 0 8.9-3.3 17.1-8.6 23.3 5.1 3.7 8.6 9.7 8.6 16.4zm20.2 3.9c0-8.8 7.1-16 16-16 8.8 0 16 7.1 16 16 0 8.8-7.1 16-16 16-8.9-.1-16-7.2-16-16zm5.8-43.5c0-13.3 10.7-24 24-24s24 10.7 24 24-10.7 24-24 24-24-10.8-24-24zm72.7 86.4c-4.2 0-8.2-.7-11.9-2-.5 12.8-11 23.1-24 23.1-13.3 0-24-10.7-24-24s10.7-24 24-24h1.1c-.7-2.9-1.1-5.8-1.1-8.9 0-19.8 16.1-35.9 35.9-35.9 19.8 0 35.9 16.1 35.9 35.9s-16.1 35.8-35.9 35.8zm10.9-91.1c0 2.6-2.1 4.6-4.6 4.6-2.6 0-4.6-2.1-4.6-4.6 0-2.6 2.1-4.6 4.6-4.6 2.5 0 4.6 2.1 4.6 4.6zm27.7 13.1c-2.1 2-4.9 3.2-8.1 3.2-6.5 0-11.7-5.2-11.7-11.7 0-6.5 5.2-11.7 11.7-11.7.5 0 1.1 0 1.6.1-1.5-3.6-3.2-7.1-5.1-10.5 2.5-4 3.9-8.7 3.9-13.8 0-14.6-11.8-26.4-26.4-26.4-3.6 0-7 .7-10.2 2-4.9-3.8-10.2-7.2-15.7-10.2.1 1 .2 2 .2 3.1 0 17.4-14.1 31.5-31.5 31.5-16.7 0-30.4-13-31.4-29.5 0-.7-.1-1.3-.1-2 0-3.4.5-6.6 1.5-9.6.9-2.8 2.2-5.5 3.8-7.9-2.2 0-4.3.1-6.5.2-3.8-6.7-11-11.2-19.2-11.2-11.8 0-21.5 9.3-22.1 21-17.1 7.5-32.1 18.8-43.9 32.8 14.3-50.3 60.6-87.2 115.6-87.2 66.3 0 120.1 53.8 120.1 120.1 0 29.5-10.6 56.4-28.2 77.3 3-10.5 4.6-21.5 4.6-32.9.1-9.1-.9-18.1-2.9-26.7z" />
|
||||
<circle cx="256.3" cy="384.3" r="14.1" />
|
||||
</g>
|
||||
<g fill="#FFF">
|
||||
<circle cx="217.1" cy="477.1" r="24" />
|
||||
<path
|
||||
d="M265.8 491.7c-19.8 0-35.9 16.1-35.9 35.9 0 3.1.4 6.1 1.1 8.9h-1.1c-13.3 0-24 10.7-24 24s10.7 24 24 24c12.9 0 23.5-10.2 24-23.1 3.7 1.3 7.7 2 11.9 2 19.8 0 35.9-16.1 35.9-35.9s-16.1-35.8-35.9-35.8zM131.2 441.2c-19.8 0-35.9 16.1-35.9 35.9 0 18.7 14.3 34.1 32.6 35.7-.3 1.3-.4 2.6-.4 4 0 10.9 8.9 19.8 19.8 19.8s19.8-8.9 19.8-19.8c0-6.8-3.4-12.8-8.6-16.3 5.4-6.3 8.6-14.4 8.6-23.3 0-20-16.1-36-35.9-36z" />
|
||||
<path
|
||||
d="M331 467.9c0-66.3-53.8-120.1-120.1-120.1-54.9 0-101.3 36.9-115.6 87.2 11.8-14.1 26.9-25.4 43.9-32.8.6-11.7 10.2-21 22.1-21 8.2 0 15.4 4.5 19.2 11.2 2.2-.1 4.3-.2 6.5-.2-1.6 2.4-2.9 5.1-3.8 7.9-1 3-1.5 6.3-1.5 9.6 0 .7 0 1.3.1 2 1 16.5 14.7 29.5 31.4 29.5 17.4 0 31.5-14.1 31.5-31.5 0-1-.1-2.1-.2-3.1 5.5 3 10.7 6.4 15.7 10.2 3.1-1.3 6.6-2 10.2-2 14.6 0 26.4 11.8 26.4 26.4 0 5-1.4 9.8-3.9 13.8 1.9 3.4 3.6 6.9 5.1 10.5-.5-.1-1.1-.1-1.6-.1-6.5 0-11.7 5.2-11.7 11.7 0 6.5 5.2 11.7 11.7 11.7 3.1 0 6-1.2 8.1-3.2 2 8.6 3 17.6 3 26.8 0 11.4-1.6 22.5-4.6 32.9 17.5-21 28.1-48 28.1-77.4z" />
|
||||
<circle cx="203.2" cy="520.6" r="16" />
|
||||
<circle cx="272.1" cy="472.4" r="4.6" />
|
||||
</g>
|
||||
<path opacity=".1" fill-rule="evenodd" clip-rule="evenodd" fill="#3B3D3D"
|
||||
d="M201.2 368.2l-.4-.8c-.4-.7-1.4-1-2.1-.6l-80.5 46.8c-.7.4-1 1.4-.6 2.1l.4.8c.3.5.8.8 1.4.8.3 0 .5-.1.8-.2l1-.6c0 .1.1.3.2.4l24.2 41.7c.2.4.7.7 1.2.7.2 0 .5-.1.7-.2l34.1-19.8c.3-.2.5-.5.6-.8.1-.4 0-.7-.1-1l-24.2-41.7-.3-.3 43.2-25.1c.4-.2.6-.5.7-1-.1-.4-.1-.8-.3-1.2z" />
|
||||
<!-- Flag stick -->
|
||||
<g>
|
||||
<path fill="#acacac" stroke="#B5B5B6" stroke-miterlimit="10"
|
||||
d="M200.8 369.5c-.2.6-.8 1-1.4.8l-.9-.2c-.6-.2-1-.8-.8-1.4l25.5-89.5c.2-.6.8-1 1.4-.8l.9.2c.6.2 1 .8.8 1.4l-25.5 89.5z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#263563" stroke="#B5B5B6" stroke-miterlimit="10"
|
||||
d="M262.9 334c-.1.5-.7.8-1.2.7l-46.4-13.2c-.5-.1-.8-.7-.7-1.2l10.8-38c.1-.5.7-.8 1.2-.7l46.4 13.2c.5.1.8.7.7 1.2l-10.8 38z" />
|
||||
<g fill-rule="evenodd" clip-rule="evenodd" fill="#263563"> <!-- #F9DA1E -->
|
||||
<path
|
||||
d="M249 311.1c.4.6.8 1.1 1.2 1.6.4.5.9.9.3 1.6.8.2 1.6.3 2.3.5-.1.4-.2.6-.2.9 0 .1.1.2.1.3.1-.1.2-.1.2-.2l.3-.9c.7.3 1.4.5 2.1.7.1-.8.1-.8 1-1.2.7-.3 1.3-.5 2-.8-.5-.7-.5-.7 0-1.3.1-.2.2-.4.4-.5-.5-.5-1.6.1-1.6-1.1-.4.3-.7.5-1 .7-.2.1-.4.1-.6.2 0-.2 0-.4.1-.6l.9-1.8c-.3.1-.6.1-.8.2-.2-.7-.3-1.3-.5-2-.5.5-1 .9-1.5 1.4l-.6-.6c-.1.8-.1 1.5-.2 2.3 0 .1-.1.3-.2.4-.1-.1-.3-.2-.3-.3-.2-.4-.3-.8-.5-1.2-.6.5-.6.5-1.3.2-.2-.1-.4-.1-.6-.2-.4.5.4 1.5-1 1.7z" />
|
||||
<path
|
||||
d="M260.2 298.6c-.6 1.1-1.2 2.2-1.8 3.4-.6 1.3-1.3 2.5-1.9 3.8-.4.8-.5.9-1.4.4.2-.8.4-1.6.5-2.4.1-.5.1-1 .2-1.5.1-1.8-1.4-3.7-3.2-3.9-.1 0-.4.2-.5.3-.9 1.6-1.7 3.3-2.5 5 0 .1-.1.2-.1.2-.2.2-.1.6-.6.4-.4-.2-.1-.4-.1-.7.2-.9.4-1.8.5-2.8 0-.7-.1-1.4-.3-2.1-.1-.4-.3-.5-.8-.4-1.8.7-3.3 1.7-4.5 3.1-2.5 2.6-4.3 5.6-5.2 9.1-.5 1.9-.5 3.8.3 5.6.8 1.7 1.2 1.8 2.8.8.7-.4 1.3-.9 2-1.4.3-.2.6-.3 1 0-1.2 1-2.4 2-3.7 2.9.7.6 1.6.8 2.6 1 2.5.4 4.6-.7 6.4-2.3.7-.6 1.2-.5 1.9-.2v.1c-2 2.2-4.2 4.1-7.3 4.3-2.3.2-4.4-.4-6.4-1.8-.2-.2-.5-.3-.8-.3-5.5.1-9.3-3.9-9-9.4 0-.7.1-1.4.2-2 .2-.6.4-1.3.5-1.9.1-.2.2-.3.3-.5.6-1.2 1.1-2.5 1.9-3.6 2.5-3.8 5.9-6.4 10.5-7.2 1.9-.3 3.9-.3 5.6.6 1.1.6 2.1.7 3.3.7.6 0 1.2.1 1.8.1.5.1.9.3 1.4.4.2.1.5.3.7.4.8.6 1.6 1.1 2.4 1.7.4.3.8.4 1.2.1.4-.2.7-.5 1.1-.7.3.5.7.6 1 .7zm-13.4-2c-.7-.5-2.1-.7-3.4-.6-2.1.2-3.8 1.2-5.3 2.4-2.4 2-4.2 4.6-5.5 7.5-.8 1.7-1.3 3.5-1.3 5.4 0 2.5.8 4.6 3.1 5.9.6.3 1.2.5 1.9.8 0-.1.1-.1.1-.2s-.1-.2-.1-.2c-1-1.5-1.4-3.1-1.4-4.9-.1-2.3.5-4.5 1.5-6.6 1.6-3.3 3.9-6.1 7.1-8 .9-.5 2.1-.9 3.3-1.5z" />
|
||||
<path
|
||||
d="M249 311.1c1.4-.1.5-1.1.8-1.8.2.1.4.1.6.2.7.3.7.3 1.3-.2.2.4.3.8.5 1.2l.3.3c.1-.1.2-.3.2-.4.1-.7.1-1.5.2-2.3l.6.6c.5-.4 1-.9 1.5-1.4.2.7.4 1.3.5 2 .3-.1.5-.1.8-.2-.3.7-.6 1.2-.9 1.8-.1.2-.1.4-.1.6.2-.1.4-.1.6-.2.3-.2.6-.4 1-.7 0 1.2 1.1.7 1.6 1.1-.1.2-.2.3-.4.5-.5.7-.5.7 0 1.3-.7.3-1.3.5-2 .8-.8.3-.8.3-1 1.2-.7-.2-1.3-.5-2.1-.7l-.3.9c0 .1-.2.2-.2.2 0-.1-.1-.2-.1-.3 0-.3.1-.5.2-.9-.7-.2-1.5-.3-2.3-.5.6-.7.1-1.2-.3-1.6-.1-.5-.5-1-1-1.5z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<script>
|
||||
// Use requestAnimationFrame for smooth animation performance
|
||||
let rafId = null;
|
||||
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
if (rafId) return;
|
||||
|
||||
rafId = requestAnimationFrame(() => {
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
const mouseX = e.clientX;
|
||||
const mouseY = e.clientY;
|
||||
|
||||
const xVal = (mouseX - width / 2) / width;
|
||||
const yVal = (mouseY - height / 2) / height;
|
||||
|
||||
const moon = document.querySelector('.moon');
|
||||
const stars = document.querySelector('.all-stars');
|
||||
const notFound = document.querySelector('.notfound-copy');
|
||||
|
||||
// Parallax factors - adjust multipliers to control speed/depth
|
||||
if (moon) moon.style.transform = `translate(${xVal * 40}px, ${yVal * 40}px)`;
|
||||
if (stars) stars.style.transform = `translate(${xVal * 20}px, ${yVal * 20}px)`;
|
||||
// Inverse movement for foreground to create depth
|
||||
if (notFound) notFound.style.transform = `translate(${xVal * -30}px, ${yVal * -30}px)`;
|
||||
|
||||
rafId = null;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -6,6 +6,7 @@ use App\Http\Controllers\Api\V1\Brand\BrandController;
|
||||
use App\Http\Controllers\Api\V1\Carousel\CarouselController;
|
||||
use App\Http\Controllers\Api\V1\CartController;
|
||||
use App\Http\Controllers\Api\V1\Category\CategoryController;
|
||||
use App\Http\Controllers\Api\V1\Category\SelectedCategoryController;
|
||||
use App\Http\Controllers\Api\V1\Channel\ChannelController;
|
||||
use App\Http\Controllers\Api\V1\Collection\CollectionController;
|
||||
use App\Http\Controllers\Api\V1\ContactMessageController;
|
||||
@@ -64,6 +65,10 @@ Route::get('categories', [CategoryController::class, 'index']);
|
||||
Route::get('categories/{category}', [CategoryController::class, 'show'])->where(['category' => '[0-9]+']);
|
||||
Route::get('categories/{category}/products', [CategoryController::class, 'products'])->where(['category' => '[0-9]+']);
|
||||
|
||||
// Selected Categories...
|
||||
Route::get('selected-categories', [SelectedCategoryController::class, 'index']);
|
||||
Route::get('selected-categories/{selectedCategory}', [SelectedCategoryController::class, 'show'])->where(['selectedCategory' => '[0-9]+']);
|
||||
|
||||
// Collections...
|
||||
Route::get('collections', [CollectionController::class, 'index']);
|
||||
Route::get('collections-paginated', [CollectionController::class, 'paginated']);
|
||||
@@ -87,6 +92,7 @@ Route::middleware('auth:sanctum')
|
||||
// Order settings...
|
||||
Route::get('order-time', [OrderController::class, 'time']);
|
||||
Route::get('order-payments', [OrderPaymentController::class, 'index']);
|
||||
Route::get('order-deliveries', [OrderController::class, 'deliveries']);
|
||||
|
||||
// Provinces...
|
||||
Route::get('provinces', [ProvinceController::class, 'index']);
|
||||
|
||||
@@ -217,7 +217,7 @@ test('can list related products', function () {
|
||||
// Then it selects product_ids from those categories.
|
||||
// It doesn't explicitly exclude the main product ID in the query shown in tool output?
|
||||
// Let's check the controller code again.
|
||||
// It selects `product_has_relations.product_id` where `productable_id` IN (categories of main product).
|
||||
// It selects `category_product.product_id` where `category_id` IN (categories of main product).
|
||||
// It does NOT seem to exclude the main product ID in the query.
|
||||
// However, `unique()` is used.
|
||||
// If the main product is returned, count would be 3. If excluded, 2.
|
||||
|
||||
Reference in New Issue
Block a user