diff --git a/backend/.phpstorm.meta.php b/backend/.phpstorm.meta.php index e910e49..1ccc6df 100644 --- a/backend/.phpstorm.meta.php +++ b/backend/.phpstorm.meta.php @@ -2220,7 +2220,9 @@ 'cache.headers','can','guest','password.confirm','precognitive', 'signed','throttle','verified',); registerArgumentsSet('routes', -'sanctum.csrf-cookie','cart.show','cart.update','cart.store','cart.destroy','products.index','products.store','products.show','products.update', +'sanctum.csrf-cookie','cart.show','cart.update','cart.store','cart.destroy', +'user.addresses.index','user.addresses.store','addresses.show','addresses.update','addresses.destroy', +'users.orders.index','users.orders.store','orders.show','orders.update','orders.destroy','products.index','products.store','products.show','products.update', 'products.destroy', 'storage.local','storage.local.upload',); registerArgumentsSet('views', diff --git a/backend/_ide_helper_models.php b/backend/_ide_helper_models.php new file mode 100644 index 0000000..0d51db2 --- /dev/null +++ b/backend/_ide_helper_models.php @@ -0,0 +1,234 @@ + + */ + + +namespace App\Models{ +/** + * @property int $id + * @property string $first_name + * @property string $last_name + * @property string $street + * @property string $city + * @property string $state + * @property string $pin + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $users + * @property-read int|null $users_count + * @method static \Illuminate\Database\Eloquent\Builder|Address newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Address newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Address query() + * @method static \Illuminate\Database\Eloquent\Builder|Address whereCity($value) + * @method static \Illuminate\Database\Eloquent\Builder|Address whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Address whereFirstName($value) + * @method static \Illuminate\Database\Eloquent\Builder|Address whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Address whereLastName($value) + * @method static \Illuminate\Database\Eloquent\Builder|Address wherePin($value) + * @method static \Illuminate\Database\Eloquent\Builder|Address whereState($value) + * @method static \Illuminate\Database\Eloquent\Builder|Address whereStreet($value) + * @method static \Illuminate\Database\Eloquent\Builder|Address whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperAddress {} +} + +namespace App\Models{ +/** + * @property int $id + * @property int $user_id + * @property \App\Enums\CartStatus $status + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\Order|null $order + * @property-read \Illuminate\Database\Eloquent\Collection $products + * @property-read int|null $products_count + * @property-read \App\Models\User|null $user + * @method static \Illuminate\Database\Eloquent\Builder|Cart active() + * @method static \Illuminate\Database\Eloquent\Builder|Cart newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Cart newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Cart query() + * @method static \Illuminate\Database\Eloquent\Builder|Cart whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Cart whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Cart whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|Cart whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Cart whereUserId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Cart withProducts() + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperCart {} +} + +namespace App\Models{ +/** + * @property int $id + * @property int $user_id + * @property int $cart_id + * @property string $status + * @property string $shipping_first_name + * @property string $shipping_last_name + * @property string $shipping_street + * @property string $shipping_city + * @property string $shipping_state + * @property string $shipping_pin + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\Cart|null $cart + * @property-read \App\Models\User $user + * @method static \Illuminate\Database\Eloquent\Builder|Order newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Order newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Order query() + * @method static \Illuminate\Database\Eloquent\Builder|Order whereCartId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereShippingCity($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereShippingFirstName($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereShippingLastName($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereShippingPin($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereShippingState($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereShippingStreet($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Order whereUserId($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperOrder {} +} + +namespace App\Models{ +/** + * @property int $id + * @property string $title + * @property string|null $slug + * @property string $description + * @property numeric $actual_price + * @property numeric $list_price + * @property int $product_category_id + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property bool $is_active + * @property-read \Illuminate\Database\Eloquent\Collection $carts + * @property-read int|null $carts_count + * @property-read \App\Models\ProductCategory|null $category + * @property-read \Illuminate\Database\Eloquent\Collection $favoritedBy + * @property-read int|null $favorited_by_count + * @property-read \Illuminate\Database\Eloquent\Collection $images + * @property-read int|null $images_count + * @method static \Illuminate\Database\Eloquent\Builder|Product active() + * @method static \Illuminate\Database\Eloquent\Builder|Product newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Product newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Product query() + * @method static \Illuminate\Database\Eloquent\Builder|Product whereActualPrice($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereIsActive($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereListPrice($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereProductCategoryId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereSlug($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereTitle($value) + * @method static \Illuminate\Database\Eloquent\Builder|Product whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperProduct {} +} + +namespace App\Models{ +/** + * @property int $id + * @property string $name + * @property string $slug + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory query() + * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereSlug($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperProductCategory {} +} + +namespace App\Models{ +/** + * @property int $id + * @property string $path + * @property int $product_id + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\Product|null $product + * @method static \Illuminate\Database\Eloquent\Builder|ProductImage newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|ProductImage newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|ProductImage query() + * @method static \Illuminate\Database\Eloquent\Builder|ProductImage whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProductImage whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProductImage wherePath($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProductImage whereProductId($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProductImage whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperProductImage {} +} + +namespace App\Models{ +/** + * @property int $id + * @property string $name + * @property string $email + * @property \Illuminate\Support\Carbon|null $email_verified_at + * @property string $password + * @property string|null $remember_token + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property string $mobile_number + * @property string $city + * @property \App\Enums\UserRoles $role + * @property-read \Illuminate\Database\Eloquent\Collection $addresses + * @property-read int|null $addresses_count + * @property-read \Illuminate\Database\Eloquent\Collection $carts + * @property-read int|null $carts_count + * @property-read \Illuminate\Database\Eloquent\Collection $favoriteProducts + * @property-read int|null $favorite_products_count + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read int|null $notifications_count + * @property-read \Illuminate\Database\Eloquent\Collection $orders + * @property-read int|null $orders_count + * @method static \Database\Factories\UserFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|User newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|User query() + * @method static \Illuminate\Database\Eloquent\Builder|User whereCity($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereEmail($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereEmailVerifiedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereMobileNumber($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|User wherePassword($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereRememberToken($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereRole($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereUpdatedAt($value) + * @mixin \Eloquent + */ + #[\AllowDynamicProperties] + class IdeHelperUser {} +} + diff --git a/backend/app/Actions/CreateOrderAction.php b/backend/app/Actions/CreateOrderAction.php new file mode 100644 index 0000000..ec17b24 --- /dev/null +++ b/backend/app/Actions/CreateOrderAction.php @@ -0,0 +1,55 @@ +where('id', $dto->cartId)->sole(); + + if ($cart->status !== CartStatus::Active) { + throw new StaleCartException(userId: $user->id, cartId: $cart->id); + } + + // check if the user has an order with the same cart id + if ($user->orders()->where('cart_id', $cart->id)->exists()) { + return response()->json([ + 'message' => 'User already has an order with this cart' + ]); + } + + /** @var Address $address */ + $address = $user->addresses()->where('id', $dto->addressId)->sole(); + + /** @var Order $order */ + $order = $user->orders()->make(); + + $order->cart_id = $cart->id; + $order->shipping_first_name = $address->first_name; + $order->shipping_last_name = $address->last_name; + $order->shipping_street = $address->street; + $order->shipping_city = $address->city; + $order->shipping_state = $address->state; + $order->shipping_pin = $address->pin; + $order->save(); + + return response()->json([ + 'message' => 'Order created successfully' + ], 201); + } +} diff --git a/backend/app/Data/OrderRequestDTO.php b/backend/app/Data/OrderRequestDTO.php new file mode 100644 index 0000000..0855509 --- /dev/null +++ b/backend/app/Data/OrderRequestDTO.php @@ -0,0 +1,33 @@ + + */ + public function toArray(): array + { + return [ + 'cart_id' => $this->cartId, + 'address_id' => $this->addressId, + ]; + } + + public static function fromRequest(FormRequest $request): OrderRequestDTO + { + return new self( + cartId: $request->cartId, + addressId: $request->addressId, + ); + } +} diff --git a/backend/app/Data/OrderResponeDTO.php b/backend/app/Data/OrderResponeDTO.php new file mode 100644 index 0000000..a496ca4 --- /dev/null +++ b/backend/app/Data/OrderResponeDTO.php @@ -0,0 +1,30 @@ + + */ + public function toArray(): array + { + return [ + // TODO: Map properties to array + ]; + } + + public static function fromModel(Model $model): OutputDataTransferObject + { + return new self( + // TODO: Map model data to properties + ); + } +} diff --git a/backend/app/Enums/OrderStatus.php b/backend/app/Enums/OrderStatus.php new file mode 100644 index 0000000..a02e72f --- /dev/null +++ b/backend/app/Enums/OrderStatus.php @@ -0,0 +1,15 @@ + The order was placed or created. There is work to do for the order, which can include processing payment, fulfilling, or processing returns. + * Archived -> The order was manually or automatically archived. Usually, this means the order was fulfilled. + * Canceled -> The order was canceled. If a canceled order was not fully refunded, then there might be work remaining for the order. + */ +enum OrderStatus: string +{ + case Open = 'open'; + case Archived = 'archived'; + case Closed = 'closed'; +} diff --git a/backend/app/Exceptions/StaleCartException.php b/backend/app/Exceptions/StaleCartException.php new file mode 100644 index 0000000..a73920b --- /dev/null +++ b/backend/app/Exceptions/StaleCartException.php @@ -0,0 +1,30 @@ + $this->userId, + 'cart_id' => $this->cartId, + ]; + } + + public function render(): JsonResponse + { + return response()->json(['message' => 'Cart is stale'], 409); + } +} diff --git a/backend/app/Http/Controllers/OrderController.php b/backend/app/Http/Controllers/OrderController.php new file mode 100644 index 0000000..f15410b --- /dev/null +++ b/backend/app/Http/Controllers/OrderController.php @@ -0,0 +1,53 @@ +execute(OrderRequestDTO::fromRequest($request), $request->user()); + } + + /** + * Display the specified resource. + */ + public function show(Order $order) + { + // + } + + /** + * Update the specified resource in storage. + */ + public function update(UpdateOrderRequest $request, Order $order) + { + // + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Order $order) + { + // + } +} diff --git a/backend/app/Http/Requests/StoreOrderRequest.php b/backend/app/Http/Requests/StoreOrderRequest.php new file mode 100644 index 0000000..c55523d --- /dev/null +++ b/backend/app/Http/Requests/StoreOrderRequest.php @@ -0,0 +1,30 @@ +|string> + */ + public function rules(): array + { + return [ + 'cartId' => 'required|exists:carts,id', + 'addressId' => 'required|exists:addresses,id', + ]; + } +} diff --git a/backend/app/Http/Requests/UpdateOrderRequest.php b/backend/app/Http/Requests/UpdateOrderRequest.php new file mode 100644 index 0000000..086c3e5 --- /dev/null +++ b/backend/app/Http/Requests/UpdateOrderRequest.php @@ -0,0 +1,29 @@ +|string> + */ + public function rules(): array + { + return [ + // + ]; + } +} diff --git a/backend/app/Http/Resources/AddressResource.php b/backend/app/Http/Resources/AddressResource.php index 9092be5..33faea5 100644 --- a/backend/app/Http/Resources/AddressResource.php +++ b/backend/app/Http/Resources/AddressResource.php @@ -12,6 +12,7 @@ class AddressResource extends JsonResource { public static $wrap = null; + /** * Transform the resource into an array. * diff --git a/backend/app/Http/Resources/OrderResource.php b/backend/app/Http/Resources/OrderResource.php new file mode 100644 index 0000000..7f7f379 --- /dev/null +++ b/backend/app/Http/Resources/OrderResource.php @@ -0,0 +1,19 @@ + + */ + public function toArray(Request $request): array + { + return parent::toArray($request); + } +} diff --git a/backend/app/Models/Address.php b/backend/app/Models/Address.php index a797fdf..3844236 100644 --- a/backend/app/Models/Address.php +++ b/backend/app/Models/Address.php @@ -8,35 +8,7 @@ use Illuminate\Support\Carbon; /** - * @property-read User|null $user - * - * @method static \Illuminate\Database\Eloquent\Builder|Address newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|Address newQuery() - * @method static \Illuminate\Database\Eloquent\Builder|Address query() - * - * @property-read Collection $users - * @property-read int|null $users_count - * @property int $id - * @property string $first_name - * @property string $last_name - * @property string $street - * @property string $city - * @property string $state - * @property string $pin - * @property Carbon|null $created_at - * @property Carbon|null $updated_at - * - * @method static \Illuminate\Database\Eloquent\Builder|Address whereCity($value) - * @method static \Illuminate\Database\Eloquent\Builder|Address whereCreatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|Address whereFirstName($value) - * @method static \Illuminate\Database\Eloquent\Builder|Address whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|Address whereLastName($value) - * @method static \Illuminate\Database\Eloquent\Builder|Address wherePin($value) - * @method static \Illuminate\Database\Eloquent\Builder|Address whereState($value) - * @method static \Illuminate\Database\Eloquent\Builder|Address whereStreet($value) - * @method static \Illuminate\Database\Eloquent\Builder|Address whereUpdatedAt($value) - * - * @mixin \Eloquent + * @mixin IdeHelperAddress */ class Address extends Model { diff --git a/backend/app/Models/Cart.php b/backend/app/Models/Cart.php index b208e7d..7345b90 100644 --- a/backend/app/Models/Cart.php +++ b/backend/app/Models/Cart.php @@ -7,54 +7,44 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Support\Carbon; /** - * @property int $id - * @property int $user_id - * @property CartStatus $status - * @property Carbon|null $created_at - * @property Carbon|null $updated_at - * @property-read Collection $products - * @property-read int|null $products_count - * @property-read User|null $user - * - * @method static Builder|Cart active() - * @method static Builder|Cart newModelQuery() - * @method static Builder|Cart newQuery() - * @method static Builder|Cart query() - * @method static Builder|Cart whereCreatedAt($value) - * @method static Builder|Cart whereId($value) - * @method static Builder|Cart whereStatus($value) - * @method static Builder|Cart whereUpdatedAt($value) - * @method static Builder|Cart whereUserId($value) - * @method static Builder|Cart withProducts() - * - * @mixin \Eloquent + * @mixin IdeHelperCart */ class Cart extends Model { protected $fillable = ['user_id', 'status']; - protected function casts() + /** + * @return array + */ + protected function casts(): array { return [ 'status' => CartStatus::class, ]; } - public function products() + public function products(): BelongsToMany { return $this->belongsToMany(Product::class) ->withPivot('price', 'quantity') ->withTimestamps(); } - public function user() + public function user(): BelongsTo { return $this->belongsTo(User::class); } + public function order(): BelongsTo + { + return $this->belongsTo(Order::class); + } + #[Scope] protected function active(Builder $query) { diff --git a/backend/app/Models/Order.php b/backend/app/Models/Order.php new file mode 100644 index 0000000..bf12f79 --- /dev/null +++ b/backend/app/Models/Order.php @@ -0,0 +1,28 @@ +belongsTo(User::class); + } + + public function cart(): HasOne + { + return $this->hasOne(Cart::class); + } +} diff --git a/backend/app/Models/Product.php b/backend/app/Models/Product.php index da9380d..f5f07c4 100644 --- a/backend/app/Models/Product.php +++ b/backend/app/Models/Product.php @@ -13,40 +13,7 @@ use Illuminate\Support\Str; /** - * @property int $id - * @property string $title - * @property string|null $slug - * @property string $description - * @property numeric $actual_price - * @property numeric $list_price - * @property int $product_category_id - * @property Carbon|null $created_at - * @property Carbon|null $updated_at - * @property bool $is_active - * @property-read Collection $carts - * @property-read int|null $carts_count - * @property-read ProductCategory|null $category - * @property-read Collection $favoritedBy - * @property-read int|null $favorited_by_count - * @property-read Collection $images - * @property-read int|null $images_count - * - * @method static Builder|Product active() - * @method static Builder|Product newModelQuery() - * @method static Builder|Product newQuery() - * @method static Builder|Product query() - * @method static Builder|Product whereActualPrice($value) - * @method static Builder|Product whereCreatedAt($value) - * @method static Builder|Product whereDescription($value) - * @method static Builder|Product whereId($value) - * @method static Builder|Product whereIsActive($value) - * @method static Builder|Product whereListPrice($value) - * @method static Builder|Product whereProductCategoryId($value) - * @method static Builder|Product whereSlug($value) - * @method static Builder|Product whereTitle($value) - * @method static Builder|Product whereUpdatedAt($value) - * - * @mixin \Eloquent + * @mixin IdeHelperProduct */ class Product extends Model { diff --git a/backend/app/Models/ProductCategory.php b/backend/app/Models/ProductCategory.php index 15f9184..4fe59a1 100644 --- a/backend/app/Models/ProductCategory.php +++ b/backend/app/Models/ProductCategory.php @@ -6,22 +6,7 @@ use Illuminate\Support\Carbon; /** - * @property int $id - * @property string $name - * @property string $slug - * @property Carbon|null $created_at - * @property Carbon|null $updated_at - * - * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory newQuery() - * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory query() - * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereCreatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereName($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereSlug($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProductCategory whereUpdatedAt($value) - * - * @mixin \Eloquent + * @mixin IdeHelperProductCategory */ class ProductCategory extends Model { diff --git a/backend/app/Models/ProductImage.php b/backend/app/Models/ProductImage.php index b1284a6..de726ff 100644 --- a/backend/app/Models/ProductImage.php +++ b/backend/app/Models/ProductImage.php @@ -7,23 +7,7 @@ use Illuminate\Support\Carbon; /** - * @property int $id - * @property string $path - * @property int $product_id - * @property Carbon|null $created_at - * @property Carbon|null $updated_at - * @property-read Product|null $product - * - * @method static \Illuminate\Database\Eloquent\Builder|ProductImage newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|ProductImage newQuery() - * @method static \Illuminate\Database\Eloquent\Builder|ProductImage query() - * @method static \Illuminate\Database\Eloquent\Builder|ProductImage whereCreatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProductImage whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProductImage wherePath($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProductImage whereProductId($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProductImage whereUpdatedAt($value) - * - * @mixin \Eloquent + * @mixin IdeHelperProductImage */ class ProductImage extends Model { diff --git a/backend/app/Models/User.php b/backend/app/Models/User.php index da8c296..899e968 100644 --- a/backend/app/Models/User.php +++ b/backend/app/Models/User.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\DatabaseNotification; use Illuminate\Notifications\DatabaseNotificationCollection; @@ -15,41 +16,7 @@ use Illuminate\Support\Carbon; /** - * @property int $id - * @property string $name - * @property string $email - * @property Carbon|null $email_verified_at - * @property string $password - * @property string|null $remember_token - * @property Carbon|null $created_at - * @property Carbon|null $updated_at - * @property string $mobile_number - * @property string $city - * @property UserRoles $role - * @property-read Collection $carts - * @property-read int|null $carts_count - * @property-read Collection $favoriteProducts - * @property-read int|null $favorite_products_count - * @property-read DatabaseNotificationCollection $notifications - * @property-read int|null $notifications_count - * - * @method static \Database\Factories\UserFactory factory($count = null, $state = []) - * @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery() - * @method static \Illuminate\Database\Eloquent\Builder|User newQuery() - * @method static \Illuminate\Database\Eloquent\Builder|User query() - * @method static \Illuminate\Database\Eloquent\Builder|User whereCity($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereCreatedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereEmail($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereEmailVerifiedAt($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereMobileNumber($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereName($value) - * @method static \Illuminate\Database\Eloquent\Builder|User wherePassword($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereRememberToken($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereRole($value) - * @method static \Illuminate\Database\Eloquent\Builder|User whereUpdatedAt($value) - * - * @mixin \Eloquent + * @mixin IdeHelperUser */ class User extends Authenticatable { @@ -106,13 +73,27 @@ public function hasFavorited(Product $product): bool return $this->favoriteProducts()->where('product_id', $product->id)->exists(); } - public function carts() + /** + * @return HasMany + */ + public function carts():HasMany { return $this->hasMany(Cart::class); } + /** + * @return BelongsToMany
+ */ public function addresses(): BelongsToMany { return $this->belongsToMany(Address::class); } + + /** + * @return HasMany + */ + public function orders(): HasMany + { + return $this->hasMany(Order::class); + } } diff --git a/backend/composer.json b/backend/composer.json index 0ded43b..352f37e 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -45,6 +45,7 @@ "@php artisan migrate --force" ], "dev": [ + "Composer\\Config::disableProcessTimeout", "@php artisan serve" ], "test": [ @@ -59,7 +60,8 @@ "@php artisan vendor:publish --tag=laravel-assets --ansi --force", "@php artisan vendor:publish --tag=laravel-assets --ansi --force", "@php artisan ide-helper:generate", - "@php artisan ide-helper:meta" + "@php artisan ide-helper:meta", + "@php artisan ide-helper:model --write-mixin" ], "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" diff --git a/backend/composer.lock b/backend/composer.lock index abe7e9a..08f82f3 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -9716,5 +9716,5 @@ "php": "^8.2" }, "platform-dev": {}, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/backend/database/migrations/2026_03_17_120130_create_orders_table.php b/backend/database/migrations/2026_03_17_120130_create_orders_table.php new file mode 100644 index 0000000..80c3889 --- /dev/null +++ b/backend/database/migrations/2026_03_17_120130_create_orders_table.php @@ -0,0 +1,39 @@ +id(); + $table->foreignIdFor(User::class)->constrained()->cascadeOnDelete(); + $table->foreignIdFor(Cart::class)->constrained()->cascadeOnDelete(); + $table->enum('status', array_column(OrderStatus::cases(), 'value')); + $table->string('shipping_first_name'); + $table->string('shipping_last_name'); + $table->string('shipping_street'); + $table->string('shipping_city'); + $table->string('shipping_state'); + $table->string('shipping_pin'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('orders'); + } +}; diff --git a/backend/routes/api.php b/backend/routes/api.php index 84d0b54..b92250a 100644 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -3,6 +3,7 @@ use App\Http\Controllers\AuthenticatedUserController; use App\Http\Controllers\CartController; use App\Http\Controllers\FavouriteProductController; +use App\Http\Controllers\OrderController; use App\Http\Controllers\ProductCategoryController; use App\Http\Controllers\ProductController; use App\Http\Controllers\ProductImagesController; @@ -27,6 +28,7 @@ ->destroyable(); Route::apiResource('user.addresses', UserAddressController::class)->shallow(); + Route::apiResource('users.orders', OrderController::class)->shallow(); }); Route::get('/categories', [ProductCategoryController::class, 'index']); Route::apiResource('products', ProductController::class);