Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d6f75bdc2 | ||
|
|
ca0aaaa84b | ||
|
|
8e1fe1336e | ||
|
|
f5927b8d08 | ||
|
|
14cb5a36ae | ||
|
|
a51a2cd436 | ||
|
|
2aa76db042 | ||
|
|
0799965212 | ||
|
|
783ae6925b | ||
|
|
d065ef1db9 | ||
|
|
a0e5cda432 | ||
|
|
11115c8dc0 | ||
|
|
bb3aafd89e | ||
|
|
419e8281e2 | ||
|
|
63b3d06d3a | ||
|
|
24bdfe9cc6 | ||
|
|
3059a923b4 | ||
|
|
6d1cb81e6b | ||
|
|
3ae3374eec | ||
|
|
c27ae1969f | ||
|
|
61ecbec994 | ||
|
|
03f044b8d3 | ||
|
|
136d6cf97e | ||
|
|
3b5bf80f39 | ||
|
|
50c956c051 | ||
|
|
ad957efcf0 | ||
|
|
27a04c6458 | ||
|
|
2b88cee10b | ||
|
|
5bbec0ee2b | ||
|
|
1656739ecd | ||
|
|
9000ea0052 | ||
|
|
0faccba476 | ||
|
|
3c2233d53e | ||
|
|
95afd46406 | ||
|
|
0f56303d59 | ||
|
|
a4eebef321 | ||
|
|
a57566c1fe | ||
|
|
7e1ecf35b9 | ||
|
|
ae008fbc9c | ||
|
|
8ef4383bd9 | ||
|
|
b575b42f22 | ||
|
|
553637d8e2 | ||
|
|
f5393f5110 | ||
|
|
068975d3b0 | ||
|
|
a34bea34d4 | ||
|
|
8b1b831ea2 | ||
|
|
617053c0ee | ||
|
|
bb05fb7747 | ||
|
|
03525280db | ||
|
|
6e2fd45803 | ||
|
|
4a4c8bd4e3 | ||
|
|
043d54bcd0 | ||
|
|
0427d1c62d | ||
|
|
aee7e4fd89 | ||
|
|
4aba99fcb5 | ||
|
|
78bf326622 | ||
|
|
77532aaac2 |
12
.ai/mcp/mcp.json
Normal file
12
.ai/mcp/mcp.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"angular-cli": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@angular/cli",
|
||||||
|
"mcp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -38,6 +38,8 @@ yarn-error.log
|
|||||||
testem.log
|
testem.log
|
||||||
/typings
|
/typings
|
||||||
__screenshots__/
|
__screenshots__/
|
||||||
|
*.cache
|
||||||
|
.php-cs-fixer.dist.php
|
||||||
|
|
||||||
# System files
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
3
.oxfmtrc.json
Normal file
3
.oxfmtrc.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"ignorePatterns": ["backend/**", "*.min.js"]
|
||||||
|
}
|
||||||
3
.phpactor.json
Normal file
3
.phpactor.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"indexer.exclude_patterns": ["/node_modules/**/*", "/backend/**/*"]
|
||||||
|
}
|
||||||
@ -2,7 +2,8 @@
|
|||||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"cli": {
|
"cli": {
|
||||||
"packageManager": "npm"
|
"packageManager": "npm",
|
||||||
|
"analytics": false
|
||||||
},
|
},
|
||||||
"newProjectRoot": "projects",
|
"newProjectRoot": "projects",
|
||||||
"projects": {
|
"projects": {
|
||||||
|
|||||||
@ -31,7 +31,7 @@ SESSION_DRIVER=database
|
|||||||
SESSION_LIFETIME=120
|
SESSION_LIFETIME=120
|
||||||
SESSION_ENCRYPT=false
|
SESSION_ENCRYPT=false
|
||||||
SESSION_PATH=/
|
SESSION_PATH=/
|
||||||
SESSION_DOMAIN=null
|
SESSION_DOMAIN=localhost
|
||||||
|
|
||||||
BROADCAST_CONNECTION=log
|
BROADCAST_CONNECTION=log
|
||||||
FILESYSTEM_DISK=local
|
FILESYSTEM_DISK=local
|
||||||
@ -64,3 +64,7 @@ AWS_USE_PATH_STYLE_ENDPOINT=false
|
|||||||
|
|
||||||
VITE_APP_NAME="${APP_NAME}"
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
FRONTEND_URL=http://localhost:4200
|
FRONTEND_URL=http://localhost:4200
|
||||||
|
SANCTUM_STATEFUL_DOMAINS=localhost:4200
|
||||||
|
|
||||||
|
STRIPE_SECRET_KEY=sk_test_51TCvFrJG0RVtUg4VTqHZC2szosam9Mf0Nq0Sh71tdIKdld5DnOUhUl4VvFBZVRWPM9G5hLPNVmH8YNXqm2R6fR5U00fsEsLb1d
|
||||||
|
STRIPE_WEBHOOK_KEY=
|
||||||
|
|||||||
1
backend/.gitignore
vendored
1
backend/.gitignore
vendored
@ -22,3 +22,4 @@
|
|||||||
Homestead.json
|
Homestead.json
|
||||||
Homestead.yaml
|
Homestead.yaml
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
laradumps.yaml
|
||||||
|
|||||||
2355
backend/.phpstorm.meta.php
Normal file
2355
backend/.phpstorm.meta.php
Normal file
File diff suppressed because it is too large
Load Diff
28657
backend/_ide_helper.php
Normal file
28657
backend/_ide_helper.php
Normal file
File diff suppressed because it is too large
Load Diff
307
backend/_ide_helper_models.php
Normal file
307
backend/_ide_helper_models.php
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
// phpcs:ignoreFile
|
||||||
|
/**
|
||||||
|
* A helper file for your Eloquent Models
|
||||||
|
* Copy the phpDocs from this file to the correct Model,
|
||||||
|
* And remove them from this file, to prevent double declarations.
|
||||||
|
*
|
||||||
|
* @author Barry vd. Heuvel <barryvdh@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
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<int, \App\Models\User> $users
|
||||||
|
* @property-read int|null $users_count
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address whereCity($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address whereFirstName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address whereLastName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address wherePin($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address whereState($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address whereStreet($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Address whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class IdeHelperAddress {}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace App\Models{
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $user_id
|
||||||
|
* @property \App\Enums\Cart\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<int, \App\Models\Product> $products
|
||||||
|
* @property-read int|null $products_count
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart active()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart whereStatus($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Cart whereUserId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|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 $cart
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Payment> $payments
|
||||||
|
* @property-read int|null $payments_count
|
||||||
|
* @property-read \App\Models\StripeSession|null $stripeSession
|
||||||
|
* @property-read mixed $total_amount
|
||||||
|
* @property-read \App\Models\User $user
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereCartId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereShippingCity($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereShippingFirstName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereShippingLastName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereShippingPin($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereShippingState($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereShippingStreet($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereStatus($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Order whereUserId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class IdeHelperOrder {}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace App\Models{
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $order_id
|
||||||
|
* @property string $transaction_id
|
||||||
|
* @property int $amount
|
||||||
|
* @property string $currency
|
||||||
|
* @property string $payment_method
|
||||||
|
* @property int $payment_status_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Order|null $order
|
||||||
|
* @property-read \App\Models\PaymentStatus|null $paymentStatus
|
||||||
|
* @property-read mixed $status
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment whereAmount($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment whereCurrency($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment whereOrderId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment wherePaymentMethod($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment wherePaymentStatusId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment whereTransactionId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Payment whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class IdeHelperPayment {}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace App\Models{
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $name
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PaymentStatus newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PaymentStatus newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PaymentStatus query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PaymentStatus whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|PaymentStatus whereName($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class IdeHelperPaymentStatus {}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<int, \App\Models\Cart> $carts
|
||||||
|
* @property-read int|null $carts_count
|
||||||
|
* @property-read \App\Models\ProductCategory|null $category
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $favoritedBy
|
||||||
|
* @property-read int|null $favorited_by_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ProductImage> $images
|
||||||
|
* @property-read int|null $images_count
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product active()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereActualPrice($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereDescription($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereIsActive($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereListPrice($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereProductCategoryId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereSlug($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Product whereTitle($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|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<static>|ProductCategory newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductCategory newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductCategory query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductCategory whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductCategory whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductCategory whereName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductCategory whereSlug($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|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<static>|ProductImage newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductImage newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductImage query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductImage whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductImage whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductImage wherePath($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductImage whereProductId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ProductImage whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class IdeHelperProductImage {}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace App\Models{
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $session_id
|
||||||
|
* @property int $order_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Order|null $order
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|StripeSession newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|StripeSession newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|StripeSession query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|StripeSession whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|StripeSession whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|StripeSession whereOrderId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|StripeSession whereSessionId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|StripeSession whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class IdeHelperStripeSession {}
|
||||||
|
}
|
||||||
|
|
||||||
|
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\User\UserRoles $role
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Address> $addresses
|
||||||
|
* @property-read int|null $addresses_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Cart> $carts
|
||||||
|
* @property-read int|null $carts_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Product> $favoriteProducts
|
||||||
|
* @property-read int|null $favorite_products_count
|
||||||
|
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||||
|
* @property-read int|null $notifications_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Order> $orders
|
||||||
|
* @property-read int|null $orders_count
|
||||||
|
* @method static \Database\Factories\UserFactory factory($count = null, $state = [])
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereCity($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereEmail($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereEmailVerifiedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereMobileNumber($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User wherePassword($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereRememberToken($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereRole($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class IdeHelperUser {}
|
||||||
|
}
|
||||||
|
|
||||||
19
backend/app/Actions/Address/DeleteUserAddressAction.php
Normal file
19
backend/app/Actions/Address/DeleteUserAddressAction.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Address;
|
||||||
|
|
||||||
|
use App\Models\Address;
|
||||||
|
|
||||||
|
final readonly class DeleteUserAddressAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(Address $address)
|
||||||
|
{
|
||||||
|
$address->users()->detach();
|
||||||
|
$address->delete();
|
||||||
|
|
||||||
|
return response()->noContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
22
backend/app/Actions/Address/SaveUserAddressAction.php
Normal file
22
backend/app/Actions/Address/SaveUserAddressAction.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Address;
|
||||||
|
|
||||||
|
use App\Data\Address\AddUserAddressRequestDTO;
|
||||||
|
use App\Data\Address\UserAddressResponseDTO;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
final readonly class SaveUserAddressAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(AddUserAddressRequestDTO $data, User $user)
|
||||||
|
{
|
||||||
|
return UserAddressResponseDTO::fromModel(
|
||||||
|
$user
|
||||||
|
->addresses()
|
||||||
|
->create($data->toArray())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
backend/app/Actions/Address/UpdateUserAddressAction.php
Normal file
21
backend/app/Actions/Address/UpdateUserAddressAction.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Address;
|
||||||
|
|
||||||
|
use App\Data\Address\UpdateUserAddressRequestDTO;
|
||||||
|
use App\Data\Address\UserAddressResponseDTO;
|
||||||
|
use App\Models\Address;
|
||||||
|
|
||||||
|
final readonly class UpdateUserAddressAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(UpdateUserAddressRequestDTO $data, Address $address)
|
||||||
|
{
|
||||||
|
$address->update($data->toArray());
|
||||||
|
$address->refresh();
|
||||||
|
|
||||||
|
return UserAddressResponseDTO::fromModel($address);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
backend/app/Actions/Cart/AddProductToCartAction.php
Normal file
46
backend/app/Actions/Cart/AddProductToCartAction.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Cart;
|
||||||
|
|
||||||
|
use App\Data\Cart\AddToCartDTO;
|
||||||
|
use App\Data\Cart\CartDTO;
|
||||||
|
use App\Enums\Cart\CartStatus;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
final readonly class AddProductToCartAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(AddToCartDTO $cartData, User $user)
|
||||||
|
{
|
||||||
|
$cart = $user->carts()->active()->firstOrCreate([
|
||||||
|
'status' => CartStatus::Active,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$price = Product::query()->whereId($cartData->productId)->value('actual_price');
|
||||||
|
|
||||||
|
$productInCart = $cart->products()->find($cartData->productId);
|
||||||
|
|
||||||
|
if ($productInCart) {
|
||||||
|
$newQuantity = $productInCart->pivot->quantity + $cartData->quantity;
|
||||||
|
|
||||||
|
$cart->products()->updateExistingPivot($cartData->productId, [
|
||||||
|
'quantity' => $newQuantity,
|
||||||
|
'price' => $price,
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$cart->products()->attach($cartData->productId, [
|
||||||
|
'quantity' => $cartData->quantity,
|
||||||
|
'price' => $price,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CartDTO::fromModel($cart->load(['products' => function ($query) {
|
||||||
|
$query->withPivot('quantity', 'price');
|
||||||
|
}]));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
17
backend/app/Actions/Cart/GetActiveUserCartAction.php
Normal file
17
backend/app/Actions/Cart/GetActiveUserCartAction.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Cart;
|
||||||
|
|
||||||
|
use App\Data\Cart\CartDTO;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
final readonly class GetActiveUserCartAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(User $user)
|
||||||
|
{
|
||||||
|
return CartDTO::fromModel($user->carts()->active()->withProducts()->first());
|
||||||
|
}
|
||||||
|
}
|
||||||
20
backend/app/Actions/Cart/MarkCartAsConvertedAction.php
Normal file
20
backend/app/Actions/Cart/MarkCartAsConvertedAction.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Cart;
|
||||||
|
|
||||||
|
use App\Enums\Cart\CartStatus;
|
||||||
|
use App\Models\Cart;
|
||||||
|
|
||||||
|
final readonly class MarkCartAsConvertedAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(Cart $cart): Cart
|
||||||
|
{
|
||||||
|
$cart->status = CartStatus::Converted;
|
||||||
|
$cart->save();
|
||||||
|
|
||||||
|
return $cart;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
backend/app/Actions/Cart/RemoveProductFromCartAction.php
Normal file
21
backend/app/Actions/Cart/RemoveProductFromCartAction.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Cart;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
final readonly class RemoveProductFromCartAction
|
||||||
|
{
|
||||||
|
public function __construct(private GetActiveUserCartAction $activeCartAction) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(int $productId, User $user)
|
||||||
|
{
|
||||||
|
$cart = $user->carts()->active()->sole();
|
||||||
|
$cart->products()->detach($productId);
|
||||||
|
|
||||||
|
return $this->activeCartAction->execute($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
backend/app/Actions/Cart/UpdateProductInCartAction.php
Normal file
34
backend/app/Actions/Cart/UpdateProductInCartAction.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Cart;
|
||||||
|
|
||||||
|
use App\Data\Cart\AddToCartDTO;
|
||||||
|
use App\Data\Cart\CartDTO;
|
||||||
|
use App\Models\User;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
final readonly class UpdateProductInCartAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function execute(AddToCartDTO $cartData, User $user)
|
||||||
|
{
|
||||||
|
$cart = $user->carts()->active()->sole();
|
||||||
|
|
||||||
|
$productInCart = $cart->products()->find($cartData->productId);
|
||||||
|
|
||||||
|
throw_if($productInCart === null, new InvalidArgumentException('Product not found'));
|
||||||
|
|
||||||
|
$cart->products()->updateExistingPivot($cartData->productId, [
|
||||||
|
'quantity' => $cartData->quantity,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return CartDTO::fromModel($cart->load(['products' => function ($query) {
|
||||||
|
$query->withPivot('quantity', 'price');
|
||||||
|
}]));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
48
backend/app/Actions/Order/CreateOrderAction.php
Normal file
48
backend/app/Actions/Order/CreateOrderAction.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Order;
|
||||||
|
|
||||||
|
use App\Data\Order\OrderRequestDTO;
|
||||||
|
use App\Enums\Cart\CartStatus;
|
||||||
|
use App\Exceptions\StaleCartException;
|
||||||
|
use App\Models\Address;
|
||||||
|
use App\Models\Cart;
|
||||||
|
use App\Models\Order;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
final readonly class CreateOrderAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*
|
||||||
|
* @throws StaleCartException
|
||||||
|
*/
|
||||||
|
public function execute(OrderRequestDTO $dto, User $user): Order
|
||||||
|
{
|
||||||
|
/** @var Cart $cart */
|
||||||
|
$cart = $user->carts()->where('id', $dto->cartId)->sole();
|
||||||
|
|
||||||
|
if ($cart->status !== CartStatus::Active) {
|
||||||
|
throw new StaleCartException(userId: $user->id, cartId: $cart->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Address $address */
|
||||||
|
$address = $user->addresses()->where('id', $dto->addressId)->sole();
|
||||||
|
|
||||||
|
// Check if user has already created an order with the same cart. If yes, then take that order.
|
||||||
|
/** @var Order $order */
|
||||||
|
$order = $user->orders()->firstOrNew(['cart_id' => $cart->id]);
|
||||||
|
|
||||||
|
$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 $order;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
backend/app/Actions/Payment/MarkPaymentAsPaidAction.php
Normal file
50
backend/app/Actions/Payment/MarkPaymentAsPaidAction.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Payment;
|
||||||
|
|
||||||
|
use App\Actions\Cart\MarkCartAsConvertedAction;
|
||||||
|
use App\Enums\Payment\PaymentStatusEnum;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentStatus;
|
||||||
|
use DB;
|
||||||
|
use Log;
|
||||||
|
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
final readonly class MarkPaymentAsPaidAction
|
||||||
|
{
|
||||||
|
public function __construct(private MarkCartAsConvertedAction $cartAsConvertedAction) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*
|
||||||
|
* @throws NotFoundResourceException|Throwable
|
||||||
|
*/
|
||||||
|
public function execute(Payment $payment): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
// get the cart and make the status to converted
|
||||||
|
$cart = $payment->order->cart;
|
||||||
|
$this->cartAsConvertedAction->execute($cart);
|
||||||
|
|
||||||
|
$status = PaymentStatus::whereName(PaymentStatusEnum::Paid->value)->value('id');
|
||||||
|
if (! $status) {
|
||||||
|
throw new NotFoundResourceException('Paid Status not found');
|
||||||
|
}
|
||||||
|
$payment->payment_status_id = $status;
|
||||||
|
|
||||||
|
$payment->save();
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
Log::error('Cannot mark order payment as paid', [$e->getMessage()]);
|
||||||
|
DB::rollBack();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
backend/app/Actions/Payment/ProcessOrderPaymentAction.php
Normal file
51
backend/app/Actions/Payment/ProcessOrderPaymentAction.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Payment;
|
||||||
|
|
||||||
|
use App\Data\Payment\PaymentResponseDTO;
|
||||||
|
use App\Enums\Payment\PaymentModes;
|
||||||
|
use App\Enums\Payment\PaymentStatusEnum;
|
||||||
|
use App\Models\Order;
|
||||||
|
use App\Models\PaymentStatus;
|
||||||
|
use App\Services\Payment\PaymentGatewayFactory;
|
||||||
|
use DB;
|
||||||
|
use Log;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
final readonly class ProcessOrderPaymentAction
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private PaymentGatewayFactory $paymentGatewayFactory,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(Order $order, PaymentModes $mode): PaymentResponseDTO
|
||||||
|
{
|
||||||
|
$gateway = $this->paymentGatewayFactory->make($mode);
|
||||||
|
try {
|
||||||
|
DB::beginTransaction();
|
||||||
|
$response = $gateway->charge($order);
|
||||||
|
|
||||||
|
if ($response->isSuccess) {
|
||||||
|
$order->payments()->create(
|
||||||
|
[
|
||||||
|
'transaction_id' => $response->transactionId,
|
||||||
|
'amount' => $response->amount,
|
||||||
|
'currency' => $response->currency,
|
||||||
|
'payment_method' => $response->method->value,
|
||||||
|
'payment_status_id' => PaymentStatus::getIdByName(PaymentStatusEnum::Unpaid->value),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
Log::error('Error occurred while processing the payment.', [$e->getMessage()]);
|
||||||
|
abort(500, 'Something went wrong. Please try again or contact us to get in touch with our support team. ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Actions;
|
namespace App\Actions\Product;
|
||||||
|
|
||||||
use App\Data\UploadImageDTO;
|
use App\Data\Upload\UploadImageDTO;
|
||||||
|
|
||||||
final readonly class CreateProductAction
|
final readonly class CreateProductAction
|
||||||
{
|
{
|
||||||
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Actions;
|
namespace App\Actions\Product;
|
||||||
|
|
||||||
use App\Data\ProductCategoryDTO;
|
use App\Data\Product\ProductCategoryDTO;
|
||||||
use App\Models\ProductCategory;
|
use App\Models\ProductCategory;
|
||||||
|
|
||||||
final readonly class GetAllProductCategory
|
final readonly class GetAllProductCategory
|
||||||
57
backend/app/Actions/Stripe/VerifyStripeSessionAction.php
Normal file
57
backend/app/Actions/Stripe/VerifyStripeSessionAction.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Stripe;
|
||||||
|
|
||||||
|
use App\Data\Payment\VerifiedCheckoutResponseDTO;
|
||||||
|
use App\Models\User;
|
||||||
|
use Exception;
|
||||||
|
use Log;
|
||||||
|
use Stripe\Exception\ApiErrorException;
|
||||||
|
use Stripe\StripeClient;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||||
|
|
||||||
|
final readonly class VerifyStripeSessionAction
|
||||||
|
{
|
||||||
|
public function __construct(private StripeClient $stripe) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action.
|
||||||
|
*/
|
||||||
|
public function execute(int $orderId, string $stripeSessionId, User $user): VerifiedCheckoutResponseDTO
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check if the order is actually made by user
|
||||||
|
*/
|
||||||
|
$order = $user->orders()
|
||||||
|
->whereId($orderId)
|
||||||
|
->first();
|
||||||
|
if (! $order) {
|
||||||
|
throw new AccessDeniedHttpException('Order is not made by you');
|
||||||
|
}
|
||||||
|
if (! $order->stripeSession()->where('session_id', $stripeSessionId)->exists()) {
|
||||||
|
throw new AccessDeniedHttpException('Stripe session is not made by you');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$session = $this->stripe->checkout->sessions->retrieve($stripeSessionId);
|
||||||
|
} catch (ApiErrorException $e) {
|
||||||
|
Log::error('Stripe api is not available: ', [$e->getMessage()]);
|
||||||
|
throw new ServiceUnavailableHttpException('Stripe api is not available');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
throw new NotFoundHttpException('Invalid Stripe session id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($session->payment_status !== 'paid' || $session->status !== 'complete') {
|
||||||
|
return VerifiedCheckoutResponseDTO::failure('Payment Unsuccessful');
|
||||||
|
}
|
||||||
|
|
||||||
|
return VerifiedCheckoutResponseDTO::success(
|
||||||
|
message: 'Payment Successful',
|
||||||
|
amount: $session->amount_total,
|
||||||
|
transactionId: $session->payment_intent,
|
||||||
|
mode: $session->payment_method_types[0],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Actions;
|
namespace App\Actions\Upload;
|
||||||
|
|
||||||
use App\Data\UploadImageDTO;
|
use App\Data\Upload\UploadImageDTO;
|
||||||
|
|
||||||
final readonly class UploadImageAction
|
final readonly class UploadImageAction
|
||||||
{
|
{
|
||||||
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Actions;
|
namespace App\Actions\User;
|
||||||
|
|
||||||
use App\Data\RegisterDTO;
|
use App\Data\User\RegisterDTO;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
|
||||||
final readonly class CreateUserAction
|
final readonly class CreateUserAction
|
||||||
63
backend/app/Console/Commands/MakeDtoCommand.php
Normal file
63
backend/app/Console/Commands/MakeDtoCommand.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\GeneratorCommand;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
|
||||||
|
class MakeDtoCommand extends GeneratorCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The console command name and signature.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $name = 'make:dto';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Create a new Data Transfer Object class';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of class being generated.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $type = 'DTO';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stub file for the generator.
|
||||||
|
*/
|
||||||
|
protected function getStub(): string
|
||||||
|
{
|
||||||
|
if ($this->option('output')) {
|
||||||
|
return base_path('stubs/dto.output.stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
return base_path('stubs/dto.input.stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default namespace for the class.
|
||||||
|
*
|
||||||
|
* @param string $rootNamespace
|
||||||
|
*/
|
||||||
|
protected function getDefaultNamespace($rootNamespace): string
|
||||||
|
{
|
||||||
|
return $rootNamespace.'\Data';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the console command options.
|
||||||
|
*/
|
||||||
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['input', 'i', InputOption::VALUE_NONE, 'Generate an Input DTO (default)'],
|
||||||
|
['output', 'o', InputOption::VALUE_NONE, 'Generate an Output DTO'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
11
backend/app/Contracts/PaymentGateway.php
Normal file
11
backend/app/Contracts/PaymentGateway.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Contracts;
|
||||||
|
|
||||||
|
use App\Data\Payment\PaymentResponseDTO;
|
||||||
|
use App\Models\Order;
|
||||||
|
|
||||||
|
interface PaymentGateway
|
||||||
|
{
|
||||||
|
public function charge(Order $order): PaymentResponseDTO;
|
||||||
|
}
|
||||||
45
backend/app/Data/Address/AddUserAddressRequestDTO.php
Normal file
45
backend/app/Data/Address/AddUserAddressRequestDTO.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Address;
|
||||||
|
|
||||||
|
use App\Contracts\InputDataTransferObject;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
final readonly class AddUserAddressRequestDTO implements InputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $firstName,
|
||||||
|
public string $lastName,
|
||||||
|
public string $street,
|
||||||
|
public string $city,
|
||||||
|
public string $state,
|
||||||
|
public string $pinCode
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function fromRequest(FormRequest $request): InputDataTransferObject
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
firstName: $request->firstName,
|
||||||
|
lastName: $request->lastName,
|
||||||
|
street: $request->street,
|
||||||
|
city: $request->city,
|
||||||
|
state: $request->state,
|
||||||
|
pinCode: $request->pinCode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'first_name' => $this->firstName,
|
||||||
|
'last_name' => $this->lastName,
|
||||||
|
'street' => $this->street,
|
||||||
|
'city' => $this->city,
|
||||||
|
'state' => $this->state,
|
||||||
|
'pin' => $this->pinCode,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
47
backend/app/Data/Address/UpdateUserAddressRequestDTO.php
Normal file
47
backend/app/Data/Address/UpdateUserAddressRequestDTO.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Address;
|
||||||
|
|
||||||
|
use App\Contracts\InputDataTransferObject;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
final readonly class UpdateUserAddressRequestDTO implements InputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?string $firstName = null,
|
||||||
|
public ?string $lastName = null,
|
||||||
|
public ?string $street = null,
|
||||||
|
public ?string $city = null,
|
||||||
|
public ?string $state = null,
|
||||||
|
public ?string $pinCode = null,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function fromRequest(FormRequest $request): InputDataTransferObject
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
firstName: $request->input('firstName'),
|
||||||
|
lastName: $request->input('lastName'),
|
||||||
|
street: $request->input('street'),
|
||||||
|
city: $request->input('city'),
|
||||||
|
state: $request->input('state'),
|
||||||
|
pinCode: $request->input('pinCode'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string = null = null, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'first_name' => $this->firstName,
|
||||||
|
'last_name' => $this->lastName,
|
||||||
|
'street' => $this->street,
|
||||||
|
'city' => $this->city,
|
||||||
|
'state' => $this->state,
|
||||||
|
'pin' => $this->pinCode,
|
||||||
|
];
|
||||||
|
|
||||||
|
return array_filter($data, fn ($value) => $value !== null);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
backend/app/Data/Address/UserAddressResponseDTO.php
Normal file
48
backend/app/Data/Address/UserAddressResponseDTO.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Address;
|
||||||
|
|
||||||
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
use App\Models\Address;
|
||||||
|
|
||||||
|
final readonly class UserAddressResponseDTO implements OutputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public int $id,
|
||||||
|
public string $firstName,
|
||||||
|
public string $lastName,
|
||||||
|
public string $street,
|
||||||
|
public string $city,
|
||||||
|
public string $state,
|
||||||
|
public string $pinCode
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function fromModel(Address $address): OutputDataTransferObject
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
id: $address->id,
|
||||||
|
firstName: $address->first_name,
|
||||||
|
lastName: $address->last_name,
|
||||||
|
street: $address->street,
|
||||||
|
city: $address->city,
|
||||||
|
state: $address->state,
|
||||||
|
pinCode: $address->pin
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'firstName' => $this->firstName,
|
||||||
|
'lastName' => $this->lastName,
|
||||||
|
'street' => $this->street,
|
||||||
|
'city' => $this->city,
|
||||||
|
'state' => $this->state,
|
||||||
|
'pinCode' => $this->pinCode,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
33
backend/app/Data/Cart/AddToCartDTO.php
Normal file
33
backend/app/Data/Cart/AddToCartDTO.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Cart;
|
||||||
|
|
||||||
|
use App\Contracts\InputDataTransferObject;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
final readonly class AddToCartDTO implements InputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public int $productId,
|
||||||
|
public int $quantity
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function fromRequest(FormRequest $request): InputDataTransferObject
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
productId: $request->productId,
|
||||||
|
quantity: $request->quantity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'productId' => $this->productId,
|
||||||
|
'quantity' => $this->quantity,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
49
backend/app/Data/Cart/CartDTO.php
Normal file
49
backend/app/Data/Cart/CartDTO.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Cart;
|
||||||
|
|
||||||
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
use App\Models\Cart;
|
||||||
|
|
||||||
|
final readonly class CartDTO implements OutputDataTransferObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param CartItemDTO[] $items
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
public int $id,
|
||||||
|
public ?int $itemsCount = null,
|
||||||
|
public ?int $totalPrice = null,
|
||||||
|
public array $items = []
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function fromModel(Cart $cart)
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
id: $cart->id,
|
||||||
|
itemsCount: $cart->products->count(),
|
||||||
|
totalPrice: $cart->products->sum(fn ($product) => $product->pivot->price * $product->pivot->quantity),
|
||||||
|
items: $cart->products->map(fn ($product) => new CartItemDTO(
|
||||||
|
id: $product->id,
|
||||||
|
title: $product->title,
|
||||||
|
quantity: $product->pivot->quantity,
|
||||||
|
price: $product->actual_price,
|
||||||
|
subtotal: $product->actual_price * $product->pivot->quantity,
|
||||||
|
image: $product->images->first()->path,
|
||||||
|
))->toArray()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'itemsCount' => $this->itemsCount,
|
||||||
|
'totalPrice' => $this->totalPrice,
|
||||||
|
'items' => $this->items,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
32
backend/app/Data/Cart/CartItemDTO.php
Normal file
32
backend/app/Data/Cart/CartItemDTO.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Cart;
|
||||||
|
|
||||||
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
|
||||||
|
final readonly class CartItemDTO implements OutputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public int $id,
|
||||||
|
public string $title,
|
||||||
|
public int $quantity,
|
||||||
|
public float $price,
|
||||||
|
public float $subtotal,
|
||||||
|
public string $image
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'title' => $this->title,
|
||||||
|
'quantity' => $this->quantity,
|
||||||
|
'price' => $this->price,
|
||||||
|
'subtotal' => $this->subtotal,
|
||||||
|
'image' => $this->image,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
29
backend/app/Data/Order/OrderCreatedResponseDTO.php
Normal file
29
backend/app/Data/Order/OrderCreatedResponseDTO.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Order;
|
||||||
|
|
||||||
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
final readonly class OrderCreatedResponseDTO implements OutputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
// TODO: Define your properties here
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function fromModel(Model $model): OutputDataTransferObject
|
||||||
|
{
|
||||||
|
return new self;
|
||||||
|
// TODO: Map model data to properties
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
// TODO: Map properties to array
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
33
backend/app/Data/Order/OrderRequestDTO.php
Normal file
33
backend/app/Data/Order/OrderRequestDTO.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Order;
|
||||||
|
|
||||||
|
use App\Contracts\InputDataTransferObject;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
final readonly class OrderRequestDTO implements InputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public int $cartId,
|
||||||
|
public string $addressId,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function fromRequest(FormRequest $request): OrderRequestDTO
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
cartId: $request->cartId,
|
||||||
|
addressId: $request->addressId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'cart_id' => $this->cartId,
|
||||||
|
'address_id' => $this->addressId,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
63
backend/app/Data/Payment/PaymentResponseDTO.php
Normal file
63
backend/app/Data/Payment/PaymentResponseDTO.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Payment;
|
||||||
|
|
||||||
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
use App\Enums\Payment\PaymentModes;
|
||||||
|
|
||||||
|
final readonly class PaymentResponseDTO implements OutputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public bool $isSuccess,
|
||||||
|
public int $amount,
|
||||||
|
public string $currency,
|
||||||
|
public PaymentModes $method,
|
||||||
|
public ?string $transactionId = null,
|
||||||
|
public ?string $errorMessage = null,
|
||||||
|
public ?string $redirectUrl = null,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function success(
|
||||||
|
string $transactionId,
|
||||||
|
int $amount,
|
||||||
|
string $currency,
|
||||||
|
PaymentModes $method,
|
||||||
|
?string $redirectUrl = null
|
||||||
|
): self {
|
||||||
|
return new self(
|
||||||
|
isSuccess: true,
|
||||||
|
amount: $amount,
|
||||||
|
currency: $currency,
|
||||||
|
method: $method,
|
||||||
|
transactionId: $transactionId,
|
||||||
|
redirectUrl: $redirectUrl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function failure(int $amount, string $currency, PaymentModes $method, string $errorMessage): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
isSuccess: false,
|
||||||
|
amount: $amount,
|
||||||
|
currency: $currency,
|
||||||
|
method: $method,
|
||||||
|
errorMessage: $errorMessage,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'isSuccess' => $this->isSuccess,
|
||||||
|
'transactionId' => $this->transactionId,
|
||||||
|
'amount' => $this->amount,
|
||||||
|
'currency' => $this->currency,
|
||||||
|
'method' => $this->method,
|
||||||
|
'redirectUrl' => $this->redirectUrl,
|
||||||
|
'errorMessage' => $this->errorMessage,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
41
backend/app/Data/Payment/VerifiedCheckoutResponseDTO.php
Normal file
41
backend/app/Data/Payment/VerifiedCheckoutResponseDTO.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Payment;
|
||||||
|
|
||||||
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
|
||||||
|
final readonly class VerifiedCheckoutResponseDTO implements OutputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public bool $isSuccess,
|
||||||
|
public string $message,
|
||||||
|
public ?int $amount = null,
|
||||||
|
public ?string $transactionId = null,
|
||||||
|
public ?string $mode = null
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function failure(string $message): VerifiedCheckoutResponseDTO
|
||||||
|
{
|
||||||
|
return new self(isSuccess: false, message: $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function success(string $message, int $amount, string $transactionId, string $mode): VerifiedCheckoutResponseDTO
|
||||||
|
{
|
||||||
|
return new self(isSuccess: true, message: $message, amount: $amount, transactionId: $transactionId,
|
||||||
|
mode: $mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'isSuccess' => $this->isSuccess,
|
||||||
|
'message' => $this->message,
|
||||||
|
'amount' => $this->amount,
|
||||||
|
'transactionId' => $this->transactionId,
|
||||||
|
'paymentMethod' => $this->mode,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Data;
|
namespace App\Data\Product;
|
||||||
|
|
||||||
use App\Contracts\OutputDataTransferObject;
|
use App\Contracts\OutputDataTransferObject;
|
||||||
use App\Models\ProductCategory;
|
use App\Models\ProductCategory;
|
||||||
@ -13,6 +13,15 @@ public function __construct(
|
|||||||
public string $slug,
|
public string $slug,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
public static function fromModel(ProductCategory $category): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
id: $category->id,
|
||||||
|
name: $category->name,
|
||||||
|
slug: $category->slug,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string, mixed>
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
@ -24,13 +33,4 @@ public function toArray(): array
|
|||||||
'slug' => $this->slug,
|
'slug' => $this->slug,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromModel(ProductCategory $category): self
|
|
||||||
{
|
|
||||||
return new self(
|
|
||||||
id: $category->id,
|
|
||||||
name: $category->name,
|
|
||||||
slug: $category->slug,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Data;
|
namespace App\Data\Product;
|
||||||
|
|
||||||
use App\Contracts\OutputDataTransferObject;
|
use App\Contracts\OutputDataTransferObject;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
@ -22,8 +22,27 @@ public function __construct(
|
|||||||
public array $productImages,
|
public array $productImages,
|
||||||
public ?string $updatedAt = null,
|
public ?string $updatedAt = null,
|
||||||
public ?string $createdAt = null,
|
public ?string $createdAt = null,
|
||||||
|
public ?bool $isFavorite = null
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
public static function fromModel(Product $product): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
id: $product->id,
|
||||||
|
title: $product->title,
|
||||||
|
slug: $product->slug,
|
||||||
|
description: $product->description,
|
||||||
|
actualPrice: $product->actual_price,
|
||||||
|
listPrice: $product->list_price,
|
||||||
|
category: ProductCategoryDTO::fromModel($product->category),
|
||||||
|
productImages: $product->images->map(fn (ProductImage $productImage) => ProductImageDTO::fromModel($productImage))->all(),
|
||||||
|
updatedAt: $product->updated_at,
|
||||||
|
createdAt: $product->created_at,
|
||||||
|
// this column is added by where exists query
|
||||||
|
isFavorite: $product->favorited_by_exists,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string, mixed>
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
@ -41,22 +60,7 @@ public function toArray(): array
|
|||||||
$this->productImages),
|
$this->productImages),
|
||||||
'updatedAt' => $this->updatedAt,
|
'updatedAt' => $this->updatedAt,
|
||||||
'createdAt' => $this->createdAt,
|
'createdAt' => $this->createdAt,
|
||||||
|
'isFavorite' => $this->isFavorite,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromModel(Product $product): self
|
|
||||||
{
|
|
||||||
return new self(
|
|
||||||
id: $product->id,
|
|
||||||
title: $product->title,
|
|
||||||
slug: $product->slug,
|
|
||||||
description: $product->description,
|
|
||||||
actualPrice: $product->actual_price,
|
|
||||||
listPrice: $product->list_price,
|
|
||||||
category: ProductCategoryDTO::fromModel($product->category),
|
|
||||||
productImages: $product->images->map(fn (ProductImage $productImage) => ProductImageDTO::fromModel($productImage))->all(),
|
|
||||||
updatedAt: $product->updated_at,
|
|
||||||
createdAt: $product->created_at,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Data;
|
namespace App\Data\Product;
|
||||||
|
|
||||||
use App\Contracts\OutputDataTransferObject;
|
use App\Contracts\OutputDataTransferObject;
|
||||||
use App\Models\ProductImage;
|
use App\Models\ProductImage;
|
||||||
@ -13,6 +13,15 @@ public function __construct(
|
|||||||
public ?int $productId = null,
|
public ?int $productId = null,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
public static function fromModel(ProductImage $productImage): self
|
||||||
|
{
|
||||||
|
return new self(
|
||||||
|
$productImage->id,
|
||||||
|
$productImage->path,
|
||||||
|
$productImage->product_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string, mixed>
|
* @return array<string, mixed>
|
||||||
*/
|
*/
|
||||||
@ -24,13 +33,4 @@ public function toArray(): array
|
|||||||
'productId' => $this->productId,
|
'productId' => $this->productId,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromModel(ProductImage $productImage): self
|
|
||||||
{
|
|
||||||
return new self(
|
|
||||||
$productImage->id,
|
|
||||||
$productImage->path,
|
|
||||||
$productImage->product_id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
35
backend/app/Data/Stripe/StripeLineItemDTO.php
Normal file
35
backend/app/Data/Stripe/StripeLineItemDTO.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Stripe;
|
||||||
|
|
||||||
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
use App\Enums\Stripe\StripeCurrency;
|
||||||
|
|
||||||
|
final readonly class StripeLineItemDTO implements OutputDataTransferObject
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public StripeCurrency $currency,
|
||||||
|
public int $price,
|
||||||
|
public string $productName,
|
||||||
|
public string $productDescription,
|
||||||
|
public int $quantity
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, int|string>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'price_data' => [
|
||||||
|
'currency' => $this->currency->value,
|
||||||
|
'unit_amount' => $this->price,
|
||||||
|
'product_data' => [
|
||||||
|
'name' => $this->productName,
|
||||||
|
'description' => $this->productDescription,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'quantity' => $this->quantity,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
32
backend/app/Data/Stripe/StripeSessionDataDTO.php
Normal file
32
backend/app/Data/Stripe/StripeSessionDataDTO.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Stripe;
|
||||||
|
|
||||||
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
use App\Enums\Stripe\StripePaymentMode;
|
||||||
|
|
||||||
|
final readonly class StripeSessionDataDTO implements OutputDataTransferObject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param StripeLineItemDTO[] $lineItems
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
public array $lineItems,
|
||||||
|
public StripePaymentMode $mode,
|
||||||
|
public string $successUrl,
|
||||||
|
public string $cancelUrl
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'line_items' => array_map(fn (StripeLineItemDTO $dto) => $dto->toArray(), $this->lineItems),
|
||||||
|
'mode' => $this->mode->value,
|
||||||
|
'success_url' => $this->successUrl,
|
||||||
|
'cancel_url' => $this->cancelUrl,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Data;
|
namespace App\Data\Upload;
|
||||||
|
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Data;
|
namespace App\Data\User;
|
||||||
|
|
||||||
use App\Contracts\InputDataTransferObject;
|
use App\Contracts\InputDataTransferObject;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Data;
|
namespace App\Data\User;
|
||||||
|
|
||||||
use App\Contracts\OutputDataTransferObject;
|
use App\Contracts\OutputDataTransferObject;
|
||||||
|
|
||||||
11
backend/app/Enums/Cart/CartStatus.php
Normal file
11
backend/app/Enums/Cart/CartStatus.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Cart;
|
||||||
|
|
||||||
|
enum CartStatus: string
|
||||||
|
{
|
||||||
|
case Active = 'active'; // freshly created
|
||||||
|
case Converted = 'converted'; // user ordered
|
||||||
|
case Abandoned = 'abandoned'; // older than 24hrs
|
||||||
|
case Expired = 'expired'; // left for a long period
|
||||||
|
}
|
||||||
15
backend/app/Enums/Order/OrderStatus.php
Normal file
15
backend/app/Enums/Order/OrderStatus.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open -> 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';
|
||||||
|
}
|
||||||
9
backend/app/Enums/Payment/PaymentModes.php
Normal file
9
backend/app/Enums/Payment/PaymentModes.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Payment;
|
||||||
|
|
||||||
|
enum PaymentModes: string
|
||||||
|
{
|
||||||
|
case StripeCheckout = 'stripeCheckout';
|
||||||
|
case CashOnDelivery = 'cashOnDelivery';
|
||||||
|
}
|
||||||
11
backend/app/Enums/Payment/PaymentStatusEnum.php
Normal file
11
backend/app/Enums/Payment/PaymentStatusEnum.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Payment;
|
||||||
|
|
||||||
|
enum PaymentStatusEnum: string
|
||||||
|
{
|
||||||
|
case Unpaid = 'unpaid';
|
||||||
|
case Paid = 'paid';
|
||||||
|
case Refunded = 'refunded';
|
||||||
|
case Failed = 'failed';
|
||||||
|
}
|
||||||
9
backend/app/Enums/Stripe/StripeCurrency.php
Normal file
9
backend/app/Enums/Stripe/StripeCurrency.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Stripe;
|
||||||
|
|
||||||
|
enum StripeCurrency: string
|
||||||
|
{
|
||||||
|
case INR = 'inr';
|
||||||
|
case USD = 'usd';
|
||||||
|
}
|
||||||
8
backend/app/Enums/Stripe/StripeEventType.php
Normal file
8
backend/app/Enums/Stripe/StripeEventType.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Stripe;
|
||||||
|
|
||||||
|
enum StripeEventType: string
|
||||||
|
{
|
||||||
|
case CheckoutSessionCompleted = 'checkout.session.completed';
|
||||||
|
}
|
||||||
8
backend/app/Enums/Stripe/StripePaymentMode.php
Normal file
8
backend/app/Enums/Stripe/StripePaymentMode.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums\Stripe;
|
||||||
|
|
||||||
|
enum StripePaymentMode: string
|
||||||
|
{
|
||||||
|
case Payment = 'payment';
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums\User;
|
||||||
|
|
||||||
enum UserRoles: string
|
enum UserRoles: string
|
||||||
{
|
{
|
||||||
30
backend/app/Exceptions/StaleCartException.php
Normal file
30
backend/app/Exceptions/StaleCartException.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
class StaleCartException extends Exception
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public readonly int|string $userId,
|
||||||
|
public readonly int|string $cartId,
|
||||||
|
public $message = 'Attempt to create a order with a stale cart',
|
||||||
|
) {
|
||||||
|
parent::__construct($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function context(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'user_id' => $this->userId,
|
||||||
|
'cart_id' => $this->cartId,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render(): JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json(['message' => 'Cart is stale'], 409);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Data\UserDTO;
|
use App\Data\User\UserDTO;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
|||||||
83
backend/app/Http/Controllers/CartController.php
Normal file
83
backend/app/Http/Controllers/CartController.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Actions\Cart\AddProductToCartAction;
|
||||||
|
use App\Actions\Cart\GetActiveUserCartAction;
|
||||||
|
use App\Actions\Cart\RemoveProductFromCartAction;
|
||||||
|
use App\Actions\Cart\UpdateProductInCartAction;
|
||||||
|
use App\Data\Cart\AddToCartDTO;
|
||||||
|
use App\Http\Requests\AddProductToCartRequest;
|
||||||
|
use App\Http\Requests\RemoveProductFromCartRequest;
|
||||||
|
use App\Http\Requests\UpdateProductInCartRequest;
|
||||||
|
use App\Http\Resources\Cart\CartResource;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class CartController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(AddProductToCartRequest $request, AddProductToCartAction $addProductAction)
|
||||||
|
{
|
||||||
|
$addToCartData = AddToCartDTO::fromRequest($request);
|
||||||
|
|
||||||
|
$cart = $addProductAction->execute($addToCartData, Auth::user());
|
||||||
|
|
||||||
|
return new CartResource($cart);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(GetActiveUserCartAction $action)
|
||||||
|
{
|
||||||
|
return new CartResource($action->execute(Auth::user()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(UpdateProductInCartRequest $request, UpdateProductInCartAction $action)
|
||||||
|
{
|
||||||
|
$updateCartData = AddToCartDTO::fromRequest($request);
|
||||||
|
$cart = $action->execute($updateCartData, $request->user());
|
||||||
|
|
||||||
|
return new CartResource($cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(RemoveProductFromCartRequest $request, RemoveProductFromCartAction $action)
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
try {
|
||||||
|
$cart = $action->execute($request->productId, $user);
|
||||||
|
|
||||||
|
return new CartResource($cart);
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
|
||||||
|
Log::error('No active cart found when removing a product from cart.', [
|
||||||
|
'user' => $user->id,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'No active cart found.',
|
||||||
|
], 404);
|
||||||
|
|
||||||
|
} catch (MultipleRecordsFoundException $e) {
|
||||||
|
Log::error('Multiple active carts found for the user', [
|
||||||
|
'user' => $user->id,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Multiple Active carts found.',
|
||||||
|
], 409);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
36
backend/app/Http/Controllers/FavouriteProductController.php
Normal file
36
backend/app/Http/Controllers/FavouriteProductController.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Resources\Product\FavouriteProductResource;
|
||||||
|
use App\Models\FavouriteProduct;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class FavouriteProductController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return FavouriteProductResource::collection(FavouriteProduct::all());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toggle(Request $request, Product $product)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var User $user
|
||||||
|
*/
|
||||||
|
$user = $request->user();
|
||||||
|
|
||||||
|
$changes = $user->favoriteProducts()->toggle($product);
|
||||||
|
Log::info('hi again');
|
||||||
|
// If changes has any item, that means a product has been attached.
|
||||||
|
$isFavorite = count($changes['attached']) > 0;
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => $isFavorite ? 'Product added to favorites' : 'Product removed from favorites',
|
||||||
|
'isFavorite' => $isFavorite,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
backend/app/Http/Controllers/OrderController.php
Normal file
60
backend/app/Http/Controllers/OrderController.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Actions\Order\CreateOrderAction;
|
||||||
|
use App\Data\Order\OrderRequestDTO;
|
||||||
|
use App\Exceptions\StaleCartException;
|
||||||
|
use App\Http\Requests\StoreOrderRequest;
|
||||||
|
use App\Http\Requests\UpdateOrderRequest;
|
||||||
|
use App\Models\Order;
|
||||||
|
|
||||||
|
class OrderController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @throws StaleCartException
|
||||||
|
*/
|
||||||
|
public function store(StoreOrderRequest $request, CreateOrderAction $action)
|
||||||
|
{
|
||||||
|
$order = $action->execute(OrderRequestDTO::fromRequest($request), $request->user());
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Order created successfully',
|
||||||
|
'orderId' => $order->id,
|
||||||
|
], 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
44
backend/app/Http/Controllers/PaymentController.php
Normal file
44
backend/app/Http/Controllers/PaymentController.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Actions\Payment\ProcessOrderPaymentAction;
|
||||||
|
use App\Actions\Stripe\VerifyStripeSessionAction;
|
||||||
|
use App\Enums\Payment\PaymentModes;
|
||||||
|
use App\Http\Requests\PaymentRequest;
|
||||||
|
use App\Http\Requests\VerifyPaymentRequest;
|
||||||
|
use App\Http\Resources\Payment\PaymentResource;
|
||||||
|
use App\Models\Order;
|
||||||
|
use App\Models\Payment;
|
||||||
|
|
||||||
|
class PaymentController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return PaymentResource::collection(Payment::all());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(PaymentRequest $request, Order $order, ProcessOrderPaymentAction $action)
|
||||||
|
{
|
||||||
|
$response = $action->execute($order, PaymentModes::tryFrom($request->mode));
|
||||||
|
|
||||||
|
return new PaymentResource($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verify(VerifyPaymentRequest $request, VerifyStripeSessionAction $action)
|
||||||
|
{
|
||||||
|
return $action->execute($request->orderId, $request->sessionId, $request->user())->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Payment $payment)
|
||||||
|
{
|
||||||
|
return new PaymentResource($payment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(PaymentRequest $request, Payment $payment)
|
||||||
|
{
|
||||||
|
$payment->update($request->validated());
|
||||||
|
|
||||||
|
return new PaymentResource($payment);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Actions\GetAllProductCategory;
|
use App\Actions\Product\GetAllProductCategory;
|
||||||
|
|
||||||
class ProductCategoryController extends Controller
|
class ProductCategoryController extends Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,18 +2,20 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Data\ProductDTO;
|
use App\Data\Product\ProductDTO;
|
||||||
use App\Http\Requests\CreateProductRequest;
|
use App\Http\Requests\CreateProductRequest;
|
||||||
use App\Http\Resources\ProductResource;
|
use App\Http\Resources\Product\ProductResource;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
|
use App\Queries\GetProductsQuery;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class ProductController extends Controller
|
class ProductController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
public function index(GetProductsQuery $getProductsQuery)
|
||||||
{
|
{
|
||||||
$paginator = Product::query()->with(['category:id,name,slug', 'images:id,path,product_id'])->paginate();
|
$products = $getProductsQuery->get(Auth::user());
|
||||||
$paginatedDtos = $paginator->through(fn ($product) => ProductDTO::fromModel($product));
|
$paginatedDtos = $products->through(fn ($product) => ProductDTO::fromModel($product));
|
||||||
|
|
||||||
return ProductResource::collection($paginatedDtos);
|
return ProductResource::collection($paginatedDtos);
|
||||||
}
|
}
|
||||||
@ -25,7 +27,10 @@ public function store(CreateProductRequest $request)
|
|||||||
|
|
||||||
public function show(string $slug)
|
public function show(string $slug)
|
||||||
{
|
{
|
||||||
$product = Product::where('slug', $slug)->with(['category:id,name,slug', 'images:id,path,product_id'])->firstOrFail();
|
$product = Product::where('slug', $slug)
|
||||||
|
->with(['category:id,name,slug', 'images:id,path,product_id'])
|
||||||
|
->withExists('favoritedBy')
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
return new ProductResource(ProductDTO::fromModel($product));
|
return new ProductResource(ProductDTO::fromModel($product));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Actions\UploadImageAction;
|
use App\Actions\Upload\UploadImageAction;
|
||||||
use App\Data\UploadImageDTO;
|
use App\Data\Upload\UploadImageDTO;
|
||||||
use App\Http\Requests\UploadImageRequest;
|
use App\Http\Requests\UploadImageRequest;
|
||||||
use App\Models\ProductImages;
|
use App\Models\ProductImages;
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Actions\CreateUserAction;
|
use App\Actions\User\CreateUserAction;
|
||||||
use App\Data\RegisterDTO;
|
use App\Data\User\RegisterDTO;
|
||||||
use App\Http\Requests\RegisterUserRequest;
|
use App\Http\Requests\RegisterUserRequest;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
|||||||
53
backend/app/Http/Controllers/StripeWebhookController.php
Normal file
53
backend/app/Http/Controllers/StripeWebhookController.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Actions\Payment\MarkPaymentAsPaidAction;
|
||||||
|
use App\Enums\Stripe\StripeEventType;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Log;
|
||||||
|
use Stripe\Exception\SignatureVerificationException;
|
||||||
|
use Stripe\Webhook;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
|
||||||
|
class StripeWebhookController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(private readonly MarkPaymentAsPaidAction $paidAction) {}
|
||||||
|
|
||||||
|
public function __invoke(Request $request)
|
||||||
|
{
|
||||||
|
$payload = $request->getContent();
|
||||||
|
$sigHeader = $request->header('Stripe-Signature');
|
||||||
|
try {
|
||||||
|
$event = Webhook::constructEvent($payload, $sigHeader, config('services.stripe.webhook'));
|
||||||
|
} catch (SignatureVerificationException|UnexpectedValueException $e) {
|
||||||
|
Log::error('Stripe webhook signature verification error.', [$e->getMessage()]);
|
||||||
|
throw new BadRequestHttpException('Invalid Signature');
|
||||||
|
}
|
||||||
|
if ($event->type === StripeEventType::CheckoutSessionCompleted->value) {
|
||||||
|
$sessionId = $event->data->object->id ?? null;
|
||||||
|
if ($sessionId) {
|
||||||
|
$this->handleCheckoutSessionCompleted($sessionId);
|
||||||
|
} else {
|
||||||
|
throw new NotFoundHttpException('Session id not found in event');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleCheckoutSessionCompleted(string $sessionId): void
|
||||||
|
{
|
||||||
|
$payment = Payment::where('transaction_id', $sessionId)->first();
|
||||||
|
|
||||||
|
if (! $payment) {
|
||||||
|
Log::error('Stripe Webhook: Payment record not found.', ['session_id' => $sessionId]);
|
||||||
|
throw new NotFoundHttpException('Payment record not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->paidAction->execute($payment);
|
||||||
|
|
||||||
|
Log::info('Stripe Webhook: Payment successfully marked as paid', ['order_id' => $payment->order_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
61
backend/app/Http/Controllers/UserAddressController.php
Normal file
61
backend/app/Http/Controllers/UserAddressController.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Actions\Address\DeleteUserAddressAction;
|
||||||
|
use App\Actions\Address\SaveUserAddressAction;
|
||||||
|
use App\Actions\Address\UpdateUserAddressAction;
|
||||||
|
use App\Data\Address\AddUserAddressRequestDTO;
|
||||||
|
use App\Data\Address\UpdateUserAddressRequestDTO;
|
||||||
|
use App\Data\Address\UserAddressResponseDTO;
|
||||||
|
use App\Http\Requests\AddUserAddressRequest;
|
||||||
|
use App\Http\Requests\UpdateUserAddressRequest;
|
||||||
|
use App\Http\Resources\Address\AddressResource;
|
||||||
|
use App\Models\Address;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class UserAddressController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$addresses = $request->user()->addresses;
|
||||||
|
$data = $addresses->map(fn ($address) => UserAddressResponseDTO::fromModel($address));
|
||||||
|
|
||||||
|
return AddressResource::collection($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(AddUserAddressRequest $request, SaveUserAddressAction $action)
|
||||||
|
{
|
||||||
|
return new AddressResource($action->execute(AddUserAddressRequestDTO::fromRequest($request), $request->user()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(Address $address)
|
||||||
|
{
|
||||||
|
return new AddressResource(UserAddressResponseDTO::fromModel($address));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(UpdateUserAddressRequest $request, Address $address, UpdateUserAddressAction $action)
|
||||||
|
{
|
||||||
|
return new AddressResource($action->execute(UpdateUserAddressRequestDTO::fromRequest($request), $address));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Address $address, DeleteUserAddressAction $action)
|
||||||
|
{
|
||||||
|
return $action->execute($address);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/Http/Requests/AddProductToCartRequest.php
Normal file
30
backend/app/Http/Requests/AddProductToCartRequest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class AddProductToCartRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'productId' => 'required|exists:products,id',
|
||||||
|
'quantity' => 'required|numeric|min:1',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
34
backend/app/Http/Requests/AddUserAddressRequest.php
Normal file
34
backend/app/Http/Requests/AddUserAddressRequest.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class AddUserAddressRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'firstName' => 'required|string|min:3|max:50',
|
||||||
|
'lastName' => 'required|string|min:3|max:50',
|
||||||
|
'street' => 'required|string|min:3|max:100',
|
||||||
|
'city' => 'required|string|min:3|max:20',
|
||||||
|
'state' => 'required|string|min:3|max:40',
|
||||||
|
'pinCode' => 'required|string|min:3|max:10',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
22
backend/app/Http/Requests/PaymentRequest.php
Normal file
22
backend/app/Http/Requests/PaymentRequest.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Enums\Payment\PaymentModes;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class PaymentRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'mode' => ['required', Rule::enum(PaymentModes::class)],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rules\Password;
|
use Illuminate\Validation\Rules\Password;
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ public function authorize(): bool
|
|||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
*/
|
*/
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
|
|||||||
29
backend/app/Http/Requests/RemoveProductFromCartRequest.php
Normal file
29
backend/app/Http/Requests/RemoveProductFromCartRequest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class RemoveProductFromCartRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'productId' => ['required', 'exists:products,id'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/Http/Requests/StoreOrderRequest.php
Normal file
30
backend/app/Http/Requests/StoreOrderRequest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreOrderRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'cartId' => 'required|exists:carts,id',
|
||||||
|
'addressId' => 'required|exists:addresses,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
29
backend/app/Http/Requests/UpdateOrderRequest.php
Normal file
29
backend/app/Http/Requests/UpdateOrderRequest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UpdateOrderRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/Http/Requests/UpdateProductInCartRequest.php
Normal file
30
backend/app/Http/Requests/UpdateProductInCartRequest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UpdateProductInCartRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'productId' => ['required', 'exists:products,id'],
|
||||||
|
'quantity' => ['required', 'min:0', 'max:10'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
35
backend/app/Http/Requests/UpdateUserAddressRequest.php
Normal file
35
backend/app/Http/Requests/UpdateUserAddressRequest.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UpdateUserAddressRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'firstName' => 'sometimes|string|min:3|max:50',
|
||||||
|
'lastName' => 'sometimes|string|min:3|max:50',
|
||||||
|
'street' => 'sometimes|string|min:3|max:100',
|
||||||
|
'city' => 'sometimes|string|min:3|max:20',
|
||||||
|
'state' => 'sometimes|string|min:3|max:40',
|
||||||
|
'pinCode' => 'sometimes|string|min:3|max:10',
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class UploadImageRequest extends FormRequest
|
class UploadImageRequest extends FormRequest
|
||||||
@ -17,7 +18,7 @@ public function authorize(): bool
|
|||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
*/
|
*/
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
|
|||||||
30
backend/app/Http/Requests/VerifyPaymentRequest.php
Normal file
30
backend/app/Http/Requests/VerifyPaymentRequest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class VerifyPaymentRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'sessionId' => 'required|exists:stripe_sessions,session_id',
|
||||||
|
'orderId' => 'required|exists:orders,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
19
backend/app/Http/Resources/Address/AddressCollection.php
Normal file
19
backend/app/Http/Resources/Address/AddressCollection.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Address;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class AddressCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource collection into an array.
|
||||||
|
*
|
||||||
|
* @return array<int|string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return parent::toArray($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
backend/app/Http/Resources/Address/AddressResource.php
Normal file
33
backend/app/Http/Resources/Address/AddressResource.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Address;
|
||||||
|
|
||||||
|
use App\Data\Address\UserAddressResponseDTO;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property UserAddressResponseDTO $resource
|
||||||
|
*/
|
||||||
|
class AddressResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->resource->id,
|
||||||
|
'firstName' => $this->resource->firstName,
|
||||||
|
'lastName' => $this->resource->lastName,
|
||||||
|
'street' => $this->resource->street,
|
||||||
|
'city' => $this->resource->city,
|
||||||
|
'state' => $this->resource->state,
|
||||||
|
'pinCode' => $this->resource->pinCode,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
19
backend/app/Http/Resources/Cart/CartItemCollection.php
Normal file
19
backend/app/Http/Resources/Cart/CartItemCollection.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Cart;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
|
||||||
|
class CartItemCollection extends ResourceCollection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource collection into an array.
|
||||||
|
*
|
||||||
|
* @return array<int|string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return parent::toArray($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/Http/Resources/Cart/CartItemResource.php
Normal file
31
backend/app/Http/Resources/Cart/CartItemResource.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Cart;
|
||||||
|
|
||||||
|
use App\Data\Cart\CartItemDTO;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property CartItemDTO $resource
|
||||||
|
*/
|
||||||
|
class CartItemResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->resource->id,
|
||||||
|
'title' => $this->resource->title,
|
||||||
|
'quantity' => $this->resource->quantity,
|
||||||
|
'price' => $this->resource->price,
|
||||||
|
'subtotal' => $this->resource->subtotal,
|
||||||
|
'image' => Storage::disk('public')->url($this->resource->image),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/Http/Resources/Cart/CartResource.php
Normal file
30
backend/app/Http/Resources/Cart/CartResource.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Cart;
|
||||||
|
|
||||||
|
use App\Data\Cart\CartDTO;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property CartDTO $resource
|
||||||
|
*/
|
||||||
|
class CartResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->resource->id,
|
||||||
|
'itemsCount' => $this->resource->itemsCount,
|
||||||
|
'totalPrice' => $this->resource->totalPrice,
|
||||||
|
'items' => CartItemResource::collection($this->resource->items),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
19
backend/app/Http/Resources/Order/OrderResource.php
Normal file
19
backend/app/Http/Resources/Order/OrderResource.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Order;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class OrderResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return parent::toArray($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/Http/Resources/Payment/PaymentResource.php
Normal file
30
backend/app/Http/Resources/Payment/PaymentResource.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Payment;
|
||||||
|
|
||||||
|
use App\Data\Payment\PaymentResponseDTO;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin Payment
|
||||||
|
*
|
||||||
|
* @property PaymentResponseDTO $resource
|
||||||
|
*/
|
||||||
|
class PaymentResource extends JsonResource
|
||||||
|
{
|
||||||
|
public static $wrap = null;
|
||||||
|
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'success' => $this->resource->isSuccess,
|
||||||
|
'amount' => $this->resource->amount,
|
||||||
|
'currency' => $this->resource->currency,
|
||||||
|
'method' => $this->resource->method,
|
||||||
|
'redirectUrl' => $this->resource->redirectUrl,
|
||||||
|
'errorMessage' => $this->resource->errorMessage,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources\Product;
|
||||||
|
|
||||||
|
use App\Models\FavouriteProduct;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/** @mixin FavouriteProduct */
|
||||||
|
class FavouriteProductResource extends JsonResource
|
||||||
|
{
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'created_at' => $this->created_at,
|
||||||
|
'updated_at' => $this->updated_at,
|
||||||
|
|
||||||
|
'user_id' => $this->user_id,
|
||||||
|
'product_id' => $this->product_id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources\Product;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources\Product;
|
||||||
|
|
||||||
use App\Data\ProductDTO;
|
use App\Data\Product\ProductDTO;
|
||||||
use App\Data\ProductImageDTO;
|
use App\Data\Product\ProductImageDTO;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
@ -30,6 +30,7 @@ public function toArray(Request $request): array
|
|||||||
return Storage::disk('public')->url($productImage->path);
|
return Storage::disk('public')->url($productImage->path);
|
||||||
}, $this->resource->productImages),
|
}, $this->resource->productImages),
|
||||||
'updatedAt' => $this->resource->updatedAt,
|
'updatedAt' => $this->resource->updatedAt,
|
||||||
|
'isFavorite' => $this->resource->isFavorite,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
19
backend/app/Models/Address.php
Normal file
19
backend/app/Models/Address.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperAddress
|
||||||
|
*/
|
||||||
|
class Address extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['first_name', 'last_name', 'street', 'city', 'state', 'pin'];
|
||||||
|
|
||||||
|
public function users(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
59
backend/app/Models/Cart.php
Normal file
59
backend/app/Models/Cart.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\Cart\CartStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperCart
|
||||||
|
*/
|
||||||
|
class Cart extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['user_id', 'status'];
|
||||||
|
|
||||||
|
public function products(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Product::class)
|
||||||
|
->withPivot('price', 'quantity')
|
||||||
|
->withTimestamps();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function order(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Order::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => CartStatus::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Scope]
|
||||||
|
protected function active(Builder $query)
|
||||||
|
{
|
||||||
|
return $query->where('status', CartStatus::Active);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Scope]
|
||||||
|
protected function withProducts(Builder $query)
|
||||||
|
{
|
||||||
|
return $query->with(['products' => function ($product) {
|
||||||
|
$product->withPivot('quantity', 'price');
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
}
|
||||||
55
backend/app/Models/Order.php
Normal file
55
backend/app/Models/Order.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperOrder
|
||||||
|
*/
|
||||||
|
class Order extends Model
|
||||||
|
{
|
||||||
|
public $fillable = [
|
||||||
|
'user_id', 'cart_id', 'status', 'shipping_city', 'shipping_street', 'shipping_last_name', 'shipping_first_name',
|
||||||
|
'shipping_state', 'shipping_pin',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cart(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Cart::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stripe session id helps to update status later from webhook
|
||||||
|
*
|
||||||
|
* @return HasOne<StripeSession>
|
||||||
|
*/
|
||||||
|
public function stripeSession(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(StripeSession::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return HasMany<Payment>
|
||||||
|
*/
|
||||||
|
public function payments(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Payment::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function totalAmount(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
fn () => $this->cart?->products->sum(fn ($product) => $product->pivot->price * $product->pivot->quantity) ?? 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
backend/app/Models/Payment.php
Normal file
40
backend/app/Models/Payment.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperPayment
|
||||||
|
*/
|
||||||
|
class Payment extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'order_id',
|
||||||
|
'transaction_id',
|
||||||
|
'amount',
|
||||||
|
'currency',
|
||||||
|
'payment_method',
|
||||||
|
'payment_status_id',
|
||||||
|
'error_message',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $with = ['paymentStatus'];
|
||||||
|
|
||||||
|
public function order(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Order::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paymentStatus(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PaymentStatus::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function status(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(fn () => $this->paymentStatus?->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
backend/app/Models/PaymentStatus.php
Normal file
22
backend/app/Models/PaymentStatus.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperPaymentStatus
|
||||||
|
*/
|
||||||
|
class PaymentStatus extends Model
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function getIdByName(string $name): ?int
|
||||||
|
{
|
||||||
|
return static::where('name', $name)->value('id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,11 +2,17 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperProduct
|
||||||
|
*/
|
||||||
class Product extends Model
|
class Product extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
@ -28,6 +34,22 @@ public function images(): HasMany
|
|||||||
return $this->hasMany(ProductImage::class, 'product_id', 'id');
|
return $this->hasMany(ProductImage::class, 'product_id', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function favoritedBy(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class, 'favorite_products');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function carts()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Cart::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Scope]
|
||||||
|
protected function active(Builder $query): Builder
|
||||||
|
{
|
||||||
|
return $query->where('is_active', true);
|
||||||
|
}
|
||||||
|
|
||||||
protected static function booted(): void
|
protected static function booted(): void
|
||||||
{
|
{
|
||||||
static::saving(function ($product) {
|
static::saving(function ($product) {
|
||||||
@ -36,4 +58,11 @@ protected static function booted(): void
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function casts()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'is_active' => 'boolean',
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperProductCategory
|
||||||
|
*/
|
||||||
class ProductCategory extends Model
|
class ProductCategory extends Model
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
|||||||
@ -5,6 +5,9 @@
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperProductImage
|
||||||
|
*/
|
||||||
class ProductImage extends Model
|
class ProductImage extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
|||||||
19
backend/app/Models/StripeSession.php
Normal file
19
backend/app/Models/StripeSession.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperStripeSession
|
||||||
|
*/
|
||||||
|
class StripeSession extends Model
|
||||||
|
{
|
||||||
|
public $fillable = ['session_id', 'order_id'];
|
||||||
|
|
||||||
|
public function order(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(Order::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,15 +3,23 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use App\Enums\UserRoles;
|
use App\Enums\User\UserRoles;
|
||||||
|
use Database\Factories\UserFactory;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
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\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin IdeHelperUser
|
||||||
|
*/
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
/** @use HasFactory<UserFactory> */
|
||||||
use HasFactory, Notifiable;
|
use HasFactory;
|
||||||
|
|
||||||
|
use Notifiable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
@ -37,6 +45,40 @@ class User extends Authenticatable
|
|||||||
'remember_token',
|
'remember_token',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function hasFavorited(Product $product): bool
|
||||||
|
{
|
||||||
|
return $this->favoriteProducts()->where('product_id', $product->id)->exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function favoriteProducts(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Product::class, 'favorite_products', 'user_id', 'product_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return HasMany<Cart>
|
||||||
|
*/
|
||||||
|
public function carts(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Cart::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BelongsToMany<Address>
|
||||||
|
*/
|
||||||
|
public function addresses(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Address::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return HasMany<Order>
|
||||||
|
*/
|
||||||
|
public function orders(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Order::class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the attributes that should be cast.
|
* Get the attributes that should be cast.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Stripe\StripeClient;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@ -11,7 +12,7 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
//
|
$this->app->singleton(StripeClient::class, fn () => new StripeClient(config('services.stripe.secret')));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
27
backend/app/Queries/GetProductsQuery.php
Normal file
27
backend/app/Queries/GetProductsQuery.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Queries;
|
||||||
|
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
|
||||||
|
final readonly class GetProductsQuery
|
||||||
|
{
|
||||||
|
public function get(?User $user = null): LengthAwarePaginator
|
||||||
|
{
|
||||||
|
return Product::query()
|
||||||
|
->active()
|
||||||
|
->when($user, function (Builder $query) use ($user) {
|
||||||
|
$query->withExists(
|
||||||
|
[
|
||||||
|
'favoritedBy' => fn (Builder $query) => $query->where('user_id', $user->id),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
})
|
||||||
|
->with(['category:id,name,slug', 'images:id,path,product_id'])
|
||||||
|
->paginate();
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user