From 36a6a53a4b4bcb338293b575c8908546f798015f Mon Sep 17 00:00:00 2001 From: Amina Zeb Date: Wed, 20 Aug 2025 07:48:50 +0500 Subject: [PATCH 1/3] integrations --- .env.testing | 2 +- app/Http/Controllers/InventoryController.php | 5 +++- app/Http/Controllers/ProductController.php | 21 +++++++++++-- app/Http/Controllers/PurchaseController.php | 2 ++ app/Http/Controllers/SaleController.php | 11 ++++--- app/Http/Controllers/UserController.php | 7 +++-- app/Http/Resources/InventoryResource.php | 29 ++++++++++++++++++ app/Http/Resources/ProductResource.php | 30 +++++++++++++++++++ app/Http/Resources/PurchaseResource.php | 19 ++++++++++++ app/Http/Resources/SaleResource.php | 19 ++++++++++++ app/Listeners/CreateInventory.php | 4 ++- database/factories/ProductFactory.php | 1 + database/factories/PurchaseFactory.php | 6 ++-- database/factories/SaleFactory.php | 3 +- ...025_08_08_123150_create_products_table.php | 1 + .../2025_08_08_191147_create_sales_table.php | 4 +-- ...25_08_08_193356_create_purchases_table.php | 2 +- routes/orion.php | 2 +- 18 files changed, 148 insertions(+), 20 deletions(-) create mode 100644 app/Http/Resources/InventoryResource.php create mode 100644 app/Http/Resources/ProductResource.php create mode 100644 app/Http/Resources/PurchaseResource.php create mode 100644 app/Http/Resources/SaleResource.php diff --git a/.env.testing b/.env.testing index 66029aa..5b3761c 100644 --- a/.env.testing +++ b/.env.testing @@ -1,5 +1,5 @@ APP_NAME=Laravel -APP_ENV=local +APP_ENV=testing APP_KEY= APP_DEBUG=true APP_URL=http://localhost diff --git a/app/Http/Controllers/InventoryController.php b/app/Http/Controllers/InventoryController.php index bd3071b..de6e13d 100644 --- a/app/Http/Controllers/InventoryController.php +++ b/app/Http/Controllers/InventoryController.php @@ -3,12 +3,15 @@ namespace App\Http\Controllers; use App\Models\Inventory; +use App\Policies\InventoryPolicy; use Orion\Http\Controllers\Controller; +use App\Http\Resources\InventoryResource; class InventoryController extends Controller { protected $model = Inventory::class; - protected $policy = \App\Policies\InventoryPolicy::class; + protected $policy = InventoryPolicy::class; + protected $resource = InventoryResource::class; public function includes(): array { diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index 78402af..d27e098 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -2,15 +2,19 @@ namespace App\Http\Controllers; -use App\Events\ProductCreated; use App\Models\Product; +use App\Events\ProductCreated; +use App\Policies\ProductPolicy; +use Orion\Http\Requests\Request; use Orion\Http\Controllers\Controller; -use Illuminate\Http\Request; +use App\Http\Resources\ProductResource; +use Illuminate\Database\Eloquent\Builder; class ProductController extends Controller { protected $model = Product::class; - protected $policy = \App\Policies\ProductPolicy::class; + protected $policy = ProductPolicy::class; + protected $resource = ProductResource::class; public function includes(): array { @@ -32,8 +36,19 @@ public function searchableBy(): array return ['id', 'name', 'description', 'color', 'image_url', 'price']; } + protected function buildIndexFetchQuery(Request $request, array $requestedRelations): Builder + { + $query = parent::buildIndexFetchQuery($request, $requestedRelations); + return $query->withTrashed(); + } + protected function afterStore(Request $request, $model) { ProductCreated::dispatch($model); } + + protected function afterDestroy(Request $request, $entity) + { + $entity->inventory()->delete(); + } } diff --git a/app/Http/Controllers/PurchaseController.php b/app/Http/Controllers/PurchaseController.php index 9f25d5d..a51f096 100644 --- a/app/Http/Controllers/PurchaseController.php +++ b/app/Http/Controllers/PurchaseController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Events\ProductsPurchased; +use App\Http\Resources\PurchaseResource; use App\Models\Purchase; use Illuminate\Http\Request; use App\Policies\PurchasePolicy; @@ -14,6 +15,7 @@ class PurchaseController extends Controller { protected $model = Purchase::class; protected $policy = PurchasePolicy::class; + protected $resource = PurchaseResource::class; public function includes(): array { diff --git a/app/Http/Controllers/SaleController.php b/app/Http/Controllers/SaleController.php index afb5114..fc68c2c 100644 --- a/app/Http/Controllers/SaleController.php +++ b/app/Http/Controllers/SaleController.php @@ -2,18 +2,21 @@ namespace App\Http\Controllers; -use App\Events\ProductsSold; use App\Models\Sale; use App\Models\Product; -use Illuminate\Database\Eloquent\Model; +use App\Events\ProductsSold; +use App\Policies\SalePolicy; +use Orion\Http\Requests\Request; +use App\Http\Resources\SaleResource; use Illuminate\Support\Facades\Auth; use Orion\Http\Controllers\Controller; -use Orion\Http\Requests\Request; +use Illuminate\Database\Eloquent\Model; class SaleController extends Controller { protected $model = Sale::class; - protected $policy = \App\Policies\SalePolicy::class; + protected $policy = SalePolicy::class; + protected $resource = SaleResource::class; public function includes(): array { diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index d88d63e..6cd4762 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -3,13 +3,16 @@ namespace App\Http\Controllers; use App\Models\User; -use Orion\Http\Controllers\Controller; +use App\Policies\UserPolicy; use Illuminate\Http\Request; +use App\Http\Resources\UserResource; +use Orion\Http\Controllers\Controller; class UserController extends Controller { protected $model = User::class; - protected $policy = \App\Policies\UserPolicy::class; + protected $policy = UserPolicy::class; + protected $resource = UserResource::class; public function includes(): array { diff --git a/app/Http/Resources/InventoryResource.php b/app/Http/Resources/InventoryResource.php new file mode 100644 index 0000000..50d7726 --- /dev/null +++ b/app/Http/Resources/InventoryResource.php @@ -0,0 +1,29 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'id' => $this->id, + 'name' => $this->product?->name ?: "", + 'color' => $this->product?->color ?: "", + 'image_url' => $this->product?->image_url ?: "", + 'price' => $this->product?->price ?: "", + 'quantity' => $this->quantity, + 'last_updated' => $this->last_stocked_at, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/app/Http/Resources/ProductResource.php b/app/Http/Resources/ProductResource.php new file mode 100644 index 0000000..321f242 --- /dev/null +++ b/app/Http/Resources/ProductResource.php @@ -0,0 +1,30 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'description' => $this->description, + 'color' => $this->color, + 'image_url' => $this->image_url, + 'price' => $this->price, + 'meta' => $this->meta, + 'status' => $this->deleted_at ? 'archived' : 'active', + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/app/Http/Resources/PurchaseResource.php b/app/Http/Resources/PurchaseResource.php new file mode 100644 index 0000000..5a01d10 --- /dev/null +++ b/app/Http/Resources/PurchaseResource.php @@ -0,0 +1,19 @@ + + */ + public function toArray(Request $request): array + { + return parent::toArray($request); + } +} diff --git a/app/Http/Resources/SaleResource.php b/app/Http/Resources/SaleResource.php new file mode 100644 index 0000000..165ed87 --- /dev/null +++ b/app/Http/Resources/SaleResource.php @@ -0,0 +1,19 @@ + + */ + public function toArray(Request $request): array + { + return parent::toArray($request); + } +} diff --git a/app/Listeners/CreateInventory.php b/app/Listeners/CreateInventory.php index 3f9bc9b..54ed433 100644 --- a/app/Listeners/CreateInventory.php +++ b/app/Listeners/CreateInventory.php @@ -13,12 +13,14 @@ public function handle(ProductCreated $event): void $product = $event->product; if (!$product?->inventory) { - Inventory::create([ + $inventory = Inventory::create([ 'product_id' => $product->id, 'quantity' => $product->meta['quantity'], 'storage_location' => $product->meta['storage_location'], 'last_stocked_at' => now(), ]); + + $product->inventory_id = $inventory->id; $product->meta = null; $product->save(); } diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php index ee6cedc..fa0368e 100644 --- a/database/factories/ProductFactory.php +++ b/database/factories/ProductFactory.php @@ -18,6 +18,7 @@ public function definition(): array { return [ 'name' => fake()->words(2, true), + 'inventory_id' => fake()->randomDigitNotNull(), 'description' => fake()->sentence(), 'color' => fake()->randomElement(['red', 'blue', 'green', 'black', 'white']), 'image_url' => fake()->imageUrl(), diff --git a/database/factories/PurchaseFactory.php b/database/factories/PurchaseFactory.php index a08c20a..0368cdd 100644 --- a/database/factories/PurchaseFactory.php +++ b/database/factories/PurchaseFactory.php @@ -2,7 +2,7 @@ namespace Database\Factories; -use App\Models\Product; +use App\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; /** @@ -18,9 +18,9 @@ class PurchaseFactory extends Factory public function definition(): array { return [ - 'product_id' => Product::factory(), + 'product_id' => fake()->randomDigitNotNull(), 'quantity' => fake()->numberBetween(1, 1000), - 'user_id' => fake()->randomDigitNotNull(), + 'user_id' => User::factory(), 'supplier' => fake()->company(), 'manufacturer' => fake()->company(), 'cost_per_unit' => fake()->randomFloat(2, 0.5, 50), diff --git a/database/factories/SaleFactory.php b/database/factories/SaleFactory.php index f01118e..27bc248 100644 --- a/database/factories/SaleFactory.php +++ b/database/factories/SaleFactory.php @@ -3,6 +3,7 @@ namespace Database\Factories; use App\Models\Product; +use App\Models\User; use Illuminate\Database\Eloquent\Factories\Factory; /** @@ -19,7 +20,7 @@ public function definition(): array { return [ 'product_id' => Product::factory(), - 'user_id' => fake()->randomDigitNotNull(), + 'user_id' => User::factory(), 'quantity' => fake()->numberBetween(1, 1000), 'amount' => fake()->randomFloat(2, 0.5, 50), 'action' => fake()->randomElement(['sold', 'returned']), diff --git a/database/migrations/2025_08_08_123150_create_products_table.php b/database/migrations/2025_08_08_123150_create_products_table.php index 008d24f..c4eab0a 100644 --- a/database/migrations/2025_08_08_123150_create_products_table.php +++ b/database/migrations/2025_08_08_123150_create_products_table.php @@ -13,6 +13,7 @@ public function up(): void { Schema::create('products', function (Blueprint $table) { $table->id(); + $table->integer('inventory_id')->nullable(); $table->string('name', 255); $table->string('description', 255)->nullable(); $table->string('color', 255)->nullable(); diff --git a/database/migrations/2025_08_08_191147_create_sales_table.php b/database/migrations/2025_08_08_191147_create_sales_table.php index 93222f0..76d5219 100644 --- a/database/migrations/2025_08_08_191147_create_sales_table.php +++ b/database/migrations/2025_08_08_191147_create_sales_table.php @@ -13,8 +13,8 @@ public function up(): void { Schema::create('sales', function (Blueprint $table) { $table->id(); - $table->integer('product_id'); - $table->integer('user_id'); + $table->foreignId('product_id')->constrained(); + $table->foreignId('user_id')->constrained(); $table->string('customer_email')->nullable(); $table->json('meta')->nullable(); $table->integer('quantity'); diff --git a/database/migrations/2025_08_08_193356_create_purchases_table.php b/database/migrations/2025_08_08_193356_create_purchases_table.php index e484772..1a424b5 100644 --- a/database/migrations/2025_08_08_193356_create_purchases_table.php +++ b/database/migrations/2025_08_08_193356_create_purchases_table.php @@ -14,7 +14,7 @@ public function up(): void Schema::create('purchases', function (Blueprint $table) { $table->id(); $table->integer('product_id')->nullable(); - $table->integer('user_id'); + $table->foreignId('user_id')->constrained(); $table->string('supplier'); $table->string('manufacturer'); $table->decimal('cost_per_unit', 10, 2); diff --git a/routes/orion.php b/routes/orion.php index b606429..c384655 100644 --- a/routes/orion.php +++ b/routes/orion.php @@ -10,7 +10,7 @@ use App\Actions\ExportInventory; Route::middleware('auth:sanctum')->group(function () { - Orion::resource('products', ProductController::class); + Orion::resource('products', ProductController::class)->withSoftDeletes(); Orion::resource('inventory', InventoryController::class); Orion::resource('users', UserController::class)->only('index', 'search', 'show', 'update'); Orion::resource('purchases', PurchaseController::class); From 10052c53c7088d183d08de498863d8b7473b7f1a Mon Sep 17 00:00:00 2001 From: Amina Zeb Date: Thu, 21 Aug 2025 05:48:08 +0500 Subject: [PATCH 2/3] integrations --- .php-cs-fixer.cache | 2 +- app/Actions/UploadImage.php | 25 ++++++++++++++++++++++ app/Http/Controllers/ProductController.php | 6 ++++++ app/Http/Resources/PurchaseResource.php | 18 +++++++++++++++- app/Http/Resources/UserResource.php | 2 +- app/Models/Sale.php | 2 +- routes/api.php | 3 +++ 7 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 app/Actions/UploadImage.php diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache index 7fd1c4c..5586427 100644 --- a/.php-cs-fixer.cache +++ b/.php-cs-fixer.cache @@ -1 +1 @@ -{"php":"8.4.11","version":"3.85.1:v3.85.1#2fb6d7f6c3398dca5786a1635b27405d73a417ba","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_parentheses":true,"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true},"hashes":{"app\/Providers\/AppServiceProvider.php":"50869d5235b70741292b4181483fb3a1","app\/Providers\/TelescopeServiceProvider.php":"50d77d91eb762925829c525b616b8ede","app\/Providers\/AuthServiceProvider.php":"9ed5c3030497fc6c2a47f8e8826be16d","app\/Providers\/RouteServiceProvider.php":"2c8cf6e7e10996320f03213cf6fd80c9","app\/Providers\/HorizonServiceProvider.php":"3e77ce1476fe086c39ab902a16466867","app\/Providers\/EventServiceProvider.php":"34134ae301e25e33b1c9ec617568517f","app\/Models\/Sale.php":"3185fb625054cb0307c381f2a95b6031","app\/Models\/Inventory.php":"bcf3b8fdff335bb1bea129368f16dd49","app\/Models\/Product.php":"c393b5ea82bf6a0f0a94222ad310c7fa","app\/Models\/Purchase.php":"0c8e2d61f21462761a4759d312f1fc7b","app\/Models\/User.php":"34e86f5ca68b584e124e81eb3d3f45e1","app\/Models\/Role.php":"26c273b5302f20e7ba86cb377d5ca30d","app\/Models\/Permission.php":"ec9f1430ebf6d98abb1e496e6909e9f7","app\/Saloon\/Connectors\/TextbeltConnector.php":"bee6b70c66a9efc22add60d9fe33d88d","app\/Saloon\/Middlewares\/SaloonLogger.php":"105c98edd63c4b3d8319efd1a0ffd598","app\/Saloon\/Requests\/VerifyTextbeltOTP.php":"6ab3989a6d5267bf63a1618a8ed1a6f6","app\/Saloon\/Requests\/GenerateTextbeltOTP.php":"bc22c4cafdc3bf9687470863645bfe00","app\/Policies\/InventoryPolicy.php":"85fc6635cb57c108d4b0484fb08b0b9a","app\/Policies\/PurchasePolicy.php":"550ab44c86fa6257bcb5f61e1ef19a02","app\/Policies\/ProductPolicy.php":"0384857d1d1ddf1670fd59f13ac08e97","app\/Policies\/UserPolicy.php":"73d992a08e36de2193c252f6f85851a6","app\/Policies\/SalePolicy.php":"6e573fe5e8875e729f648cbf9ece3b34","app\/Exports\/InventoryExport.php":"702cfefafec0fa02f6904cbc03b4ce95","app\/Http\/Middleware\/ApiLocalization.php":"7df372cb93193297702f9d03c13ace76","app\/Http\/Controllers\/UserController.php":"a710cd139d253bb7ecc39416351a85b2","app\/Http\/Controllers\/PurchaseController.php":"5bf4177505312ad861d9322c20235e92","app\/Http\/Controllers\/AuthController.php":"ddfb72a54d6d1ec0b9dc7d5d96539378","app\/Http\/Controllers\/SaleController.php":"bf091ecb4c4dd6445db5cec7672e9d97","app\/Http\/Controllers\/InventoryController.php":"0a1c7d667146b857d85cbbd7b216065c","app\/Http\/Controllers\/ProductController.php":"a1b4ec750a74a6fba4a8c24027f57735","app\/Http\/Kernel.php":"e62999818bb65d413780164884c90960","app\/Actions\/ExportInventory.php":"a0650617c8921d03eb6e5adc506689ac","app\/Events\/ProductsSold.php":"bc0c0bc7ca203bbf7612f4cb913efb01","app\/Events\/UserCreated.php":"9c854425a69334cddb46c752065d8988","app\/Events\/ProductsPurchased.php":"89ccd011c461d49b9fad2a45c5f096ed","app\/Listeners\/SendUserVerificationNotifications.php":"52aefd22fd2907dba1c0cd1b62103b10","app\/Listeners\/UpdateProduct.php":"d6ef0bc9493dd90076eaa2f5ce9f9556","app\/Listeners\/CreateProduct.php":"edb7a12d9cad824b0c190c7861a85dd6","app\/Listeners\/UpdateInventory.php":"147758a50f0c6c71f6e37fb4bb5d78b3","app\/Listeners\/CreateInventory.php":"abd01b446f5f60da5407f3d40aeb9802","app\/Notifications\/SendPhoneVerificationNotification.php":"61d4cb57170fd42a8dc83e7bbaaba612","app\/Notifications\/Contracts\/TextbeltMessage.php":"eae9bb4b7182aab740cbea159c516888","app\/Notifications\/Channels\/TextbeltChannel.php":"c47379b8dd0b252de39b7992da7d3c01","app\/Events\/ProductCreated.php":"1fa7d37bdfd1c57cce06b4746d1979fc","app\/Listeners\/UpdateProductImageUrl.php":"506670cd825c3dde6c2c9c3e806877b4","app\/Http\/Resources\/RoleResource.php":"74c49f71f6b8d35dc512f885e11aca2a","app\/Http\/Resources\/UserResource.php":"deeec5be8483364fec89064984769f22"}} \ No newline at end of file +{"php":"8.4.11","version":"3.85.1:v3.85.1#2fb6d7f6c3398dca5786a1635b27405d73a417ba","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_parentheses":true,"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true},"hashes":{"app\/Providers\/AppServiceProvider.php":"50869d5235b70741292b4181483fb3a1","app\/Providers\/TelescopeServiceProvider.php":"50d77d91eb762925829c525b616b8ede","app\/Providers\/AuthServiceProvider.php":"9ed5c3030497fc6c2a47f8e8826be16d","app\/Providers\/RouteServiceProvider.php":"2c8cf6e7e10996320f03213cf6fd80c9","app\/Providers\/HorizonServiceProvider.php":"3e77ce1476fe086c39ab902a16466867","app\/Providers\/EventServiceProvider.php":"34134ae301e25e33b1c9ec617568517f","app\/Models\/Sale.php":"75153feaf2619fcccee4bf8873afa0ee","app\/Models\/Inventory.php":"bcf3b8fdff335bb1bea129368f16dd49","app\/Models\/Product.php":"c393b5ea82bf6a0f0a94222ad310c7fa","app\/Models\/Purchase.php":"0c8e2d61f21462761a4759d312f1fc7b","app\/Models\/User.php":"34e86f5ca68b584e124e81eb3d3f45e1","app\/Models\/Role.php":"26c273b5302f20e7ba86cb377d5ca30d","app\/Models\/Permission.php":"ec9f1430ebf6d98abb1e496e6909e9f7","app\/Saloon\/Connectors\/TextbeltConnector.php":"bee6b70c66a9efc22add60d9fe33d88d","app\/Saloon\/Middlewares\/SaloonLogger.php":"105c98edd63c4b3d8319efd1a0ffd598","app\/Saloon\/Requests\/VerifyTextbeltOTP.php":"6ab3989a6d5267bf63a1618a8ed1a6f6","app\/Saloon\/Requests\/GenerateTextbeltOTP.php":"bc22c4cafdc3bf9687470863645bfe00","app\/Policies\/InventoryPolicy.php":"85fc6635cb57c108d4b0484fb08b0b9a","app\/Policies\/PurchasePolicy.php":"550ab44c86fa6257bcb5f61e1ef19a02","app\/Policies\/ProductPolicy.php":"0384857d1d1ddf1670fd59f13ac08e97","app\/Policies\/UserPolicy.php":"73d992a08e36de2193c252f6f85851a6","app\/Policies\/SalePolicy.php":"6e573fe5e8875e729f648cbf9ece3b34","app\/Exports\/InventoryExport.php":"702cfefafec0fa02f6904cbc03b4ce95","app\/Http\/Middleware\/ApiLocalization.php":"7df372cb93193297702f9d03c13ace76","app\/Http\/Controllers\/UserController.php":"c5cd48c1c358b7161388a14ef700f982","app\/Http\/Controllers\/PurchaseController.php":"53050317a02f1ddf8acdfa52eef513ec","app\/Http\/Controllers\/AuthController.php":"ddfb72a54d6d1ec0b9dc7d5d96539378","app\/Http\/Controllers\/SaleController.php":"65a04c708fddb5296158b4639489ace5","app\/Http\/Controllers\/InventoryController.php":"7195e3051f73c6b1276dcafc4f3b4371","app\/Http\/Controllers\/ProductController.php":"382d2747b334c3c110c1da38b276a5a7","app\/Http\/Kernel.php":"e62999818bb65d413780164884c90960","app\/Actions\/ExportInventory.php":"a0650617c8921d03eb6e5adc506689ac","app\/Events\/ProductsSold.php":"bc0c0bc7ca203bbf7612f4cb913efb01","app\/Events\/UserCreated.php":"9c854425a69334cddb46c752065d8988","app\/Events\/ProductsPurchased.php":"89ccd011c461d49b9fad2a45c5f096ed","app\/Listeners\/SendUserVerificationNotifications.php":"52aefd22fd2907dba1c0cd1b62103b10","app\/Listeners\/UpdateProduct.php":"d6ef0bc9493dd90076eaa2f5ce9f9556","app\/Listeners\/CreateProduct.php":"edb7a12d9cad824b0c190c7861a85dd6","app\/Listeners\/UpdateInventory.php":"147758a50f0c6c71f6e37fb4bb5d78b3","app\/Listeners\/CreateInventory.php":"f3a32bfc3eaae14c499feea0b82b7794","app\/Notifications\/SendPhoneVerificationNotification.php":"61d4cb57170fd42a8dc83e7bbaaba612","app\/Notifications\/Contracts\/TextbeltMessage.php":"eae9bb4b7182aab740cbea159c516888","app\/Notifications\/Channels\/TextbeltChannel.php":"c47379b8dd0b252de39b7992da7d3c01","app\/Events\/ProductCreated.php":"1fa7d37bdfd1c57cce06b4746d1979fc","app\/Listeners\/UpdateProductImageUrl.php":"506670cd825c3dde6c2c9c3e806877b4","app\/Http\/Resources\/RoleResource.php":"74c49f71f6b8d35dc512f885e11aca2a","app\/Http\/Resources\/UserResource.php":"672ed11dc3cd71b66d6a0048592e9887","app\/Http\/Resources\/ProductResource.php":"79a4339c22f1335a49dad3a6dc67d2a0","app\/Http\/Resources\/PurchaseResource.php":"bd23e432f5f41a4f8d56d0dd052edf05","app\/Http\/Resources\/SaleResource.php":"80c09fc6b4754301b970743d9e9775ba","app\/Http\/Resources\/InventoryResource.php":"2aa5931065e8a5a1f877752d330be7b4","app\/Actions\/UploadImage.php":"280dcfe3c370a9f5e237d1b57e41a331"}} \ No newline at end of file diff --git a/app/Actions/UploadImage.php b/app/Actions/UploadImage.php new file mode 100644 index 0000000..26a97c6 --- /dev/null +++ b/app/Actions/UploadImage.php @@ -0,0 +1,25 @@ +validate([ + 'image' => 'required|image|max:5120', // max 5MB + ]); + + $file = $request->file('image'); + $filename = 'temp/' . Str::random(40) . '.' . $file->getClientOriginalExtension(); + Storage::disk('s3')->putFileAs('temp', $file, basename($filename), 'public'); + $url = Storage::disk('s3')->url($filename); + + return response()->json(['url' => $url]); + } +} diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index d27e098..29b4ebc 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -9,6 +9,7 @@ use Orion\Http\Controllers\Controller; use App\Http\Resources\ProductResource; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Model; class ProductController extends Controller { @@ -51,4 +52,9 @@ protected function afterDestroy(Request $request, $entity) { $entity->inventory()->delete(); } + + protected function afterRestore(Request $request, Model $entity) + { + $entity->inventory()->restore(); + } } diff --git a/app/Http/Resources/PurchaseResource.php b/app/Http/Resources/PurchaseResource.php index 5a01d10..084676a 100644 --- a/app/Http/Resources/PurchaseResource.php +++ b/app/Http/Resources/PurchaseResource.php @@ -14,6 +14,22 @@ class PurchaseResource extends JsonResource */ public function toArray(Request $request): array { - return parent::toArray($request); + return [ + 'id' => $this->id, + 'product_id' => $this->product_id, + 'user_id' => $this->user_id, + 'supplier' => $this->supplier, + 'manufacturer' => $this->manufacturer, + 'cost_per_unit' => $this->cost_per_unit, + 'amount' => $this->amount, + 'product' => [ + 'id' => $this->product_id, + 'name' => $this->product?->name, + ], + 'quantity' => $this->quantity, + 'meta' => $this->meta, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; } } diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php index 547caa7..8d22c82 100644 --- a/app/Http/Resources/UserResource.php +++ b/app/Http/Resources/UserResource.php @@ -17,7 +17,7 @@ class UserResource extends JsonResource */ public function toArray(Request $request): array { - $isLoginRoute = Route::getCurrentRoute()?->getController() instanceof AuthController && Str::after(Route::getCurrentRoute()->getActionName(), '@') === 'login'; + $isLoginRoute = Route::getCurrentRoute()?->getController() instanceof AuthController && in_array(Str::after(Route::getCurrentRoute()->getActionName(), '@'), ['register', 'login']); return [ 'id' => $this->id, diff --git a/app/Models/Sale.php b/app/Models/Sale.php index 6e3650f..1fce622 100644 --- a/app/Models/Sale.php +++ b/app/Models/Sale.php @@ -15,7 +15,7 @@ class Sale extends Model protected $fillable = [ 'product_id', 'user_id', - 'customer_id', + 'customer_email', 'meta', 'quantity', 'amount', diff --git a/routes/api.php b/routes/api.php index c686b18..8cd8b7b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -14,5 +14,8 @@ Route::get('/email/verify', function () { return view('auth.verify-email'); })->middleware('auth:sanctum')->name('verification.notice'); + +Route::post('/upload/image', \App\Actions\UploadImage::class); + Route::post('/email/verification-notification', [AuthController::class, 'resendEmailVerification']) ->middleware(['auth:sanctum'])->name('verification.send'); From 51c43be717baf01adf670f394ab6c28e3ac9d590 Mon Sep 17 00:00:00 2001 From: Amina Zeb Date: Thu, 21 Aug 2025 06:20:35 +0500 Subject: [PATCH 3/3] integrations --- routes/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/api.php b/routes/api.php index 8cd8b7b..6759c00 100644 --- a/routes/api.php +++ b/routes/api.php @@ -15,7 +15,7 @@ return view('auth.verify-email'); })->middleware('auth:sanctum')->name('verification.notice'); -Route::post('/upload/image', \App\Actions\UploadImage::class); +Route::post('/upload/image', \App\Actions\UploadImage::class)->middleware('auth:sanctum'); Route::post('/email/verification-notification', [AuthController::class, 'resendEmailVerification']) ->middleware(['auth:sanctum'])->name('verification.send');