Jelajahi Sumber

Merge branch 'feature/GINC-GAB-CB007-fluxo-produtos' of Softpar/sfp_api_laravel_ginastica_cerebro into development

Gabriel Alves 1 bulan lalu
induk
melakukan
8f2fe80561

+ 32 - 32
.phpstorm.meta.php

@@ -46,8 +46,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -112,8 +112,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -178,8 +178,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -244,8 +244,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -310,8 +310,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -376,8 +376,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -442,8 +442,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -508,8 +508,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -574,8 +574,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -640,8 +640,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -706,8 +706,8 @@
             'events' => \Illuminate\Events\Dispatcher::class,
             'files' => \Illuminate\Filesystem\Filesystem::class,
             'filesystem' => \Illuminate\Filesystem\FilesystemManager::class,
-            'filesystem.cloud' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
-            'filesystem.disk' => \Illuminate\Filesystem\LocalFilesystemAdapter::class,
+            'filesystem.cloud' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
+            'filesystem.disk' => \Illuminate\Filesystem\AwsS3V3Adapter::class,
             'hash' => \Illuminate\Hashing\HashManager::class,
             'hash.driver' => \Illuminate\Hashing\BcryptHasher::class,
             'log' => \Illuminate\Log\LogManager::class,
@@ -990,7 +990,7 @@
             'filesystems.disks.s3.endpoint' => 'NULL',
             'filesystems.disks.s3.use_path_style_endpoint' => 'boolean',
             'filesystems.disks.s3.throw' => 'boolean',
-            'filesystems.links./home/ghalves/workspace/ginastica_cerebro/api/public/storage' => 'string',
+            'filesystems.links./home/alves/workspace/ginastica_cerebro/sfp_api_laravel_ginastica_cerebro/public/storage' => 'string',
             'logging.default' => 'string',
             'logging.deprecations.channel' => 'NULL',
             'logging.deprecations.trace' => 'boolean',
@@ -1129,9 +1129,9 @@
             'session.http_only' => 'boolean',
             'session.same_site' => 'string',
             'session.partitioned' => 'boolean',
+            'concurrency.default' => 'string',
             'view.paths' => 'array',
             'view.compiled' => 'string',
-            'concurrency.default' => 'string',
             'hashing.driver' => 'string',
             'hashing.bcrypt.rounds' => 'string',
             'hashing.bcrypt.verify' => 'boolean',
@@ -1408,7 +1408,7 @@
             'filesystems.disks.s3.endpoint' => 'NULL',
             'filesystems.disks.s3.use_path_style_endpoint' => 'boolean',
             'filesystems.disks.s3.throw' => 'boolean',
-            'filesystems.links./home/ghalves/workspace/ginastica_cerebro/api/public/storage' => 'string',
+            'filesystems.links./home/alves/workspace/ginastica_cerebro/sfp_api_laravel_ginastica_cerebro/public/storage' => 'string',
             'logging.default' => 'string',
             'logging.deprecations.channel' => 'NULL',
             'logging.deprecations.trace' => 'boolean',
@@ -1547,9 +1547,9 @@
             'session.http_only' => 'boolean',
             'session.same_site' => 'string',
             'session.partitioned' => 'boolean',
+            'concurrency.default' => 'string',
             'view.paths' => 'array',
             'view.compiled' => 'string',
-            'concurrency.default' => 'string',
             'hashing.driver' => 'string',
             'hashing.bcrypt.rounds' => 'string',
             'hashing.bcrypt.verify' => 'boolean',
@@ -1826,7 +1826,7 @@
             'filesystems.disks.s3.endpoint' => 'NULL',
             'filesystems.disks.s3.use_path_style_endpoint' => 'boolean',
             'filesystems.disks.s3.throw' => 'boolean',
-            'filesystems.links./home/ghalves/workspace/ginastica_cerebro/api/public/storage' => 'string',
+            'filesystems.links./home/alves/workspace/ginastica_cerebro/sfp_api_laravel_ginastica_cerebro/public/storage' => 'string',
             'logging.default' => 'string',
             'logging.deprecations.channel' => 'NULL',
             'logging.deprecations.trace' => 'boolean',
@@ -1965,9 +1965,9 @@
             'session.http_only' => 'boolean',
             'session.same_site' => 'string',
             'session.partitioned' => 'boolean',
+            'concurrency.default' => 'string',
             'view.paths' => 'array',
             'view.compiled' => 'string',
-            'concurrency.default' => 'string',
             'hashing.driver' => 'string',
             'hashing.bcrypt.rounds' => 'string',
             'hashing.bcrypt.verify' => 'boolean',
@@ -2096,7 +2096,7 @@
 'filesystems.disks.local.driver','filesystems.disks.local.root','filesystems.disks.local.throw','filesystems.disks.public.driver','filesystems.disks.public.root',
 'filesystems.disks.public.url','filesystems.disks.public.visibility','filesystems.disks.public.throw','filesystems.disks.s3.driver','filesystems.disks.s3.key',
 'filesystems.disks.s3.secret','filesystems.disks.s3.region','filesystems.disks.s3.bucket','filesystems.disks.s3.url','filesystems.disks.s3.endpoint',
-'filesystems.disks.s3.use_path_style_endpoint','filesystems.disks.s3.throw','filesystems.links./home/ghalves/workspace/ginastica_cerebro/api/public/storage','logging.default','logging.deprecations.channel',
+'filesystems.disks.s3.use_path_style_endpoint','filesystems.disks.s3.throw','filesystems.links./home/alves/workspace/ginastica_cerebro/sfp_api_laravel_ginastica_cerebro/public/storage','logging.default','logging.deprecations.channel',
 'logging.deprecations.trace','logging.channels.stack.driver','logging.channels.stack.channels','logging.channels.stack.ignore_exceptions','logging.channels.single.driver',
 'logging.channels.single.path','logging.channels.single.level','logging.channels.single.replace_placeholders','logging.channels.daily.driver','logging.channels.daily.path',
 'logging.channels.daily.level','logging.channels.daily.days','logging.channels.daily.replace_placeholders','logging.channels.slack.driver','logging.channels.slack.url',
@@ -2124,7 +2124,7 @@
 'session.driver','session.lifetime','session.expire_on_close','session.encrypt','session.files',
 'session.connection','session.table','session.store','session.lottery','session.cookie',
 'session.path','session.domain','session.secure','session.http_only','session.same_site',
-'session.partitioned','view.paths','view.compiled','concurrency.default','hashing.driver',
+'session.partitioned','concurrency.default','view.paths','view.compiled','hashing.driver',
 'hashing.bcrypt.rounds','hashing.bcrypt.verify','hashing.bcrypt.limit','hashing.argon.memory','hashing.argon.threads',
 'hashing.argon.time','hashing.argon.verify','hashing.rehash_on_login','ide-helper.filename','ide-helper.models_filename',
 'ide-helper.meta_filename','ide-helper.include_fluent','ide-helper.include_factory_builders','ide-helper.write_model_magic_where','ide-helper.write_model_external_builder_methods',
@@ -2190,8 +2190,8 @@
 'messages.buyer_not_allowed','validation.cannot_delete_related','validation.event_full','validation.payment_cant_be_refunded','validation.refund_value_greater_than_payment_value',);
         registerArgumentsSet('env', 
 'APP_NAME','APP_ENV','APP_KEY','APP_DEBUG','APP_TIMEZONE',
-'APP_URL','FRANCHISOR_URL','FRANCHISEE_URL','APP_LOCALE','APP_FALLBACK_LOCALE',
-'APP_FAKER_LOCALE','APP_MAINTENANCE_DRIVER','APP_MAINTENANCE_STORE','BCRYPT_ROUNDS','LOG_CHANNEL',
+'APP_URL','APP_LOCALE','APP_FALLBACK_LOCALE','APP_FAKER_LOCALE','APP_MAINTENANCE_DRIVER',
+'APP_MAINTENANCE_STORE','FRANCHISOR_URL','FRANCHISEE_URL','BCRYPT_ROUNDS','LOG_CHANNEL',
 'LOG_STACK','LOG_DEPRECATIONS_CHANNEL','LOG_LEVEL','DB_CONNECTION','DB_HOST',
 'DB_PORT','DB_DATABASE','DB_USERNAME','DB_PASSWORD','SESSION_DRIVER',
 'SESSION_LIFETIME','SESSION_ENCRYPT','SESSION_PATH','SESSION_DOMAIN','BROADCAST_CONNECTION',

+ 90 - 108
_ide_helper.php

@@ -19541,7 +19541,7 @@ class Storage {
          * Get a filesystem instance.
          *
          * @param string|null $name
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function drive($name = null)
@@ -19554,7 +19554,7 @@ public static function drive($name = null)
          * Get a filesystem instance.
          *
          * @param string|null $name
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function disk($name = null)
@@ -19579,7 +19579,7 @@ public static function cloud()
          * Build an on-demand disk.
          *
          * @param string|array $config
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function build($config)
@@ -19593,7 +19593,7 @@ public static function build($config)
          *
          * @param array $config
          * @param string $name
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function createLocalDriver($config, $name = 'local')
@@ -19606,7 +19606,7 @@ public static function createLocalDriver($config, $name = 'local')
          * Create an instance of the ftp driver.
          *
          * @param array $config
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function createFtpDriver($config)
@@ -19619,7 +19619,7 @@ public static function createFtpDriver($config)
          * Create an instance of the sftp driver.
          *
          * @param array $config
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function createSftpDriver($config)
@@ -19645,7 +19645,7 @@ public static function createS3Driver($config)
          * Create a scoped driver.
          *
          * @param array $config
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function createScopedDriver($config)
@@ -19745,6 +19745,20 @@ public static function setApplication($app)
             return $instance->setApplication($app);
         }
 
+        /**
+         * Get the URL for the file at the given path.
+         *
+         * @param string $path
+         * @return string
+         * @throws \RuntimeException
+         * @static
+         */
+        public static function url($path)
+        {
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
+            return $instance->url($path);
+        }
+
         /**
          * Determine if temporary URLs can be generated.
          *
@@ -19753,7 +19767,7 @@ public static function setApplication($app)
          */
         public static function providesTemporaryUrls()
         {
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->providesTemporaryUrls();
         }
 
@@ -19768,35 +19782,35 @@ public static function providesTemporaryUrls()
          */
         public static function temporaryUrl($path, $expiration, $options = [])
         {
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->temporaryUrl($path, $expiration, $options);
         }
 
         /**
-         * Specify the name of the disk the adapter is managing.
+         * Get a temporary upload URL for the file at the given path.
          *
-         * @param string $disk
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @param string $path
+         * @param \DateTimeInterface $expiration
+         * @param array $options
+         * @return array
          * @static
          */
-        public static function diskName($disk)
+        public static function temporaryUploadUrl($path, $expiration, $options = [])
         {
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
-            return $instance->diskName($disk);
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
+            return $instance->temporaryUploadUrl($path, $expiration, $options);
         }
 
         /**
-         * Indicate that signed URLs should serve the corresponding files.
+         * Get the underlying S3 client.
          *
-         * @param bool $serve
-         * @param \Closure|null $urlGeneratorResolver
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Aws\S3\S3Client
          * @static
          */
-        public static function shouldServeSignedUrls($serve = true, $urlGeneratorResolver = null)
+        public static function getClient()
         {
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
-            return $instance->shouldServeSignedUrls($serve, $urlGeneratorResolver);
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
+            return $instance->getClient();
         }
 
         /**
@@ -19804,13 +19818,13 @@ public static function shouldServeSignedUrls($serve = true, $urlGeneratorResolve
          *
          * @param string|array $path
          * @param string|null $content
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function assertExists($path, $content = null)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->assertExists($path, $content);
         }
 
@@ -19820,13 +19834,13 @@ public static function assertExists($path, $content = null)
          * @param string $path
          * @param int $count
          * @param bool $recursive
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function assertCount($path, $count, $recursive = false)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->assertCount($path, $count, $recursive);
         }
 
@@ -19834,13 +19848,13 @@ public static function assertCount($path, $count, $recursive = false)
          * Assert that the given file or directory does not exist.
          *
          * @param string|array $path
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function assertMissing($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->assertMissing($path);
         }
 
@@ -19848,13 +19862,13 @@ public static function assertMissing($path)
          * Assert that the given directory is empty.
          *
          * @param string $path
-         * @return \Illuminate\Filesystem\LocalFilesystemAdapter
+         * @return \Illuminate\Filesystem\AwsS3V3Adapter
          * @static
          */
         public static function assertDirectoryEmpty($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->assertDirectoryEmpty($path);
         }
 
@@ -19868,7 +19882,7 @@ public static function assertDirectoryEmpty($path)
         public static function exists($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->exists($path);
         }
 
@@ -19882,7 +19896,7 @@ public static function exists($path)
         public static function missing($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->missing($path);
         }
 
@@ -19896,7 +19910,7 @@ public static function missing($path)
         public static function fileExists($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->fileExists($path);
         }
 
@@ -19910,7 +19924,7 @@ public static function fileExists($path)
         public static function fileMissing($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->fileMissing($path);
         }
 
@@ -19924,7 +19938,7 @@ public static function fileMissing($path)
         public static function directoryExists($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->directoryExists($path);
         }
 
@@ -19938,7 +19952,7 @@ public static function directoryExists($path)
         public static function directoryMissing($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->directoryMissing($path);
         }
 
@@ -19952,7 +19966,7 @@ public static function directoryMissing($path)
         public static function path($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->path($path);
         }
 
@@ -19966,7 +19980,7 @@ public static function path($path)
         public static function get($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->get($path);
         }
 
@@ -19981,7 +19995,7 @@ public static function get($path)
         public static function json($path, $flags = 0)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->json($path, $flags);
         }
 
@@ -19998,7 +20012,7 @@ public static function json($path, $flags = 0)
         public static function response($path, $name = null, $headers = [], $disposition = 'inline')
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->response($path, $name, $headers, $disposition);
         }
 
@@ -20015,7 +20029,7 @@ public static function response($path, $name = null, $headers = [], $disposition
         public static function serve($request, $path, $name = null, $headers = [])
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->serve($request, $path, $name, $headers);
         }
 
@@ -20031,7 +20045,7 @@ public static function serve($request, $path, $name = null, $headers = [])
         public static function download($path, $name = null, $headers = [])
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->download($path, $name, $headers);
         }
 
@@ -20047,7 +20061,7 @@ public static function download($path, $name = null, $headers = [])
         public static function put($path, $contents, $options = [])
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->put($path, $contents, $options);
         }
 
@@ -20063,7 +20077,7 @@ public static function put($path, $contents, $options = [])
         public static function putFile($path, $file = null, $options = [])
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->putFile($path, $file, $options);
         }
 
@@ -20080,7 +20094,7 @@ public static function putFile($path, $file = null, $options = [])
         public static function putFileAs($path, $file, $name = null, $options = [])
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->putFileAs($path, $file, $name, $options);
         }
 
@@ -20094,7 +20108,7 @@ public static function putFileAs($path, $file, $name = null, $options = [])
         public static function getVisibility($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->getVisibility($path);
         }
 
@@ -20109,7 +20123,7 @@ public static function getVisibility($path)
         public static function setVisibility($path, $visibility)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->setVisibility($path, $visibility);
         }
 
@@ -20126,7 +20140,7 @@ public static function prepend($path, $data, $separator = '
 ')
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->prepend($path, $data, $separator);
         }
 
@@ -20143,7 +20157,7 @@ public static function append($path, $data, $separator = '
 ')
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->append($path, $data, $separator);
         }
 
@@ -20157,7 +20171,7 @@ public static function append($path, $data, $separator = '
         public static function delete($paths)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->delete($paths);
         }
 
@@ -20172,7 +20186,7 @@ public static function delete($paths)
         public static function copy($from, $to)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->copy($from, $to);
         }
 
@@ -20187,7 +20201,7 @@ public static function copy($from, $to)
         public static function move($from, $to)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->move($from, $to);
         }
 
@@ -20201,7 +20215,7 @@ public static function move($from, $to)
         public static function size($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->size($path);
         }
 
@@ -20215,7 +20229,7 @@ public static function size($path)
         public static function checksum($path, $options = [])
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->checksum($path, $options);
         }
 
@@ -20229,7 +20243,7 @@ public static function checksum($path, $options = [])
         public static function mimeType($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->mimeType($path);
         }
 
@@ -20243,7 +20257,7 @@ public static function mimeType($path)
         public static function lastModified($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->lastModified($path);
         }
 
@@ -20257,7 +20271,7 @@ public static function lastModified($path)
         public static function readStream($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->readStream($path);
         }
 
@@ -20273,42 +20287,10 @@ public static function readStream($path)
         public static function writeStream($path, $resource, $options = [])
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->writeStream($path, $resource, $options);
         }
 
-        /**
-         * Get the URL for the file at the given path.
-         *
-         * @param string $path
-         * @return string
-         * @throws \RuntimeException
-         * @static
-         */
-        public static function url($path)
-        {
-            //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
-            return $instance->url($path);
-        }
-
-        /**
-         * Get a temporary upload URL for the file at the given path.
-         *
-         * @param string $path
-         * @param \DateTimeInterface $expiration
-         * @param array $options
-         * @return array
-         * @throws \RuntimeException
-         * @static
-         */
-        public static function temporaryUploadUrl($path, $expiration, $options = [])
-        {
-            //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
-            return $instance->temporaryUploadUrl($path, $expiration, $options);
-        }
-
         /**
          * Get an array of all files in a directory.
          *
@@ -20320,7 +20302,7 @@ public static function temporaryUploadUrl($path, $expiration, $options = [])
         public static function files($directory = null, $recursive = false)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->files($directory, $recursive);
         }
 
@@ -20334,7 +20316,7 @@ public static function files($directory = null, $recursive = false)
         public static function allFiles($directory = null)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->allFiles($directory);
         }
 
@@ -20349,7 +20331,7 @@ public static function allFiles($directory = null)
         public static function directories($directory = null, $recursive = false)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->directories($directory, $recursive);
         }
 
@@ -20363,7 +20345,7 @@ public static function directories($directory = null, $recursive = false)
         public static function allDirectories($directory = null)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->allDirectories($directory);
         }
 
@@ -20377,7 +20359,7 @@ public static function allDirectories($directory = null)
         public static function makeDirectory($path)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->makeDirectory($path);
         }
 
@@ -20391,7 +20373,7 @@ public static function makeDirectory($path)
         public static function deleteDirectory($directory)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->deleteDirectory($directory);
         }
 
@@ -20404,7 +20386,7 @@ public static function deleteDirectory($directory)
         public static function getDriver()
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->getDriver();
         }
 
@@ -20417,7 +20399,7 @@ public static function getDriver()
         public static function getAdapter()
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->getAdapter();
         }
 
@@ -20430,7 +20412,7 @@ public static function getAdapter()
         public static function getConfig()
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->getConfig();
         }
 
@@ -20444,7 +20426,7 @@ public static function getConfig()
         public static function serveUsing($callback)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             $instance->serveUsing($callback);
         }
 
@@ -20458,7 +20440,7 @@ public static function serveUsing($callback)
         public static function buildTemporaryUrlsUsing($callback)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             $instance->buildTemporaryUrlsUsing($callback);
         }
 
@@ -20475,7 +20457,7 @@ public static function buildTemporaryUrlsUsing($callback)
          */
         public static function when($value = null, $callback = null, $default = null)
         {
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->when($value, $callback, $default);
         }
 
@@ -20492,7 +20474,7 @@ public static function when($value = null, $callback = null, $default = null)
          */
         public static function unless($value = null, $callback = null, $default = null)
         {
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->unless($value, $callback, $default);
         }
 
@@ -20508,7 +20490,7 @@ public static function unless($value = null, $callback = null, $default = null)
         public static function macro($name, $macro)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            \Illuminate\Filesystem\LocalFilesystemAdapter::macro($name, $macro);
+            \Illuminate\Filesystem\AwsS3V3Adapter::macro($name, $macro);
         }
 
         /**
@@ -20523,7 +20505,7 @@ public static function macro($name, $macro)
         public static function mixin($mixin, $replace = true)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            \Illuminate\Filesystem\LocalFilesystemAdapter::mixin($mixin, $replace);
+            \Illuminate\Filesystem\AwsS3V3Adapter::mixin($mixin, $replace);
         }
 
         /**
@@ -20536,7 +20518,7 @@ public static function mixin($mixin, $replace = true)
         public static function hasMacro($name)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            return \Illuminate\Filesystem\LocalFilesystemAdapter::hasMacro($name);
+            return \Illuminate\Filesystem\AwsS3V3Adapter::hasMacro($name);
         }
 
         /**
@@ -20548,7 +20530,7 @@ public static function hasMacro($name)
         public static function flushMacros()
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            \Illuminate\Filesystem\LocalFilesystemAdapter::flushMacros();
+            \Illuminate\Filesystem\AwsS3V3Adapter::flushMacros();
         }
 
         /**
@@ -20563,7 +20545,7 @@ public static function flushMacros()
         public static function macroCall($method, $parameters)
         {
             //Method inherited from \Illuminate\Filesystem\FilesystemAdapter 
-            /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */
+            /** @var \Illuminate\Filesystem\AwsS3V3Adapter $instance */
             return $instance->macroCall($method, $parameters);
         }
 

+ 59 - 0
app/Http/Controllers/ProductController.php

@@ -4,6 +4,9 @@
 
 use App\Services\ProductService;
 use App\Http\Requests\ProductRequest;
+use App\Http\Requests\ProductStockRequest;
+use Illuminate\Http\Request;
+use PhpOffice\PhpSpreadsheet\IOFactory;
 use App\Http\Resources\ProductResource;
 use Illuminate\Http\JsonResponse;
 
@@ -48,4 +51,60 @@ public function destroy(int $id): JsonResponse
         $this->service->delete($id);
         return $this->successResponse(message: __('messages.deleted'), code: 204);
     }
+
+    public function import(Request $request): JsonResponse
+    {
+        $request->validate(['file' => 'required|file|mimes:xlsx,xls,csv']);
+
+        $spreadsheet = IOFactory::load($request->file('file')->getRealPath());
+        $rows        = $spreadsheet->getActiveSheet()->toArray();
+
+        if (empty($rows)) {
+            return $this->errorResponse('Arquivo vazio.', 422);
+        }
+
+        $headers = array_map(fn($h) => mb_strtolower(trim((string) $h)), $rows[0]);
+
+        $colName  = null;
+        $colQty   = null;
+        $colPrice = null;
+
+        foreach ($headers as $i => $h) {
+            if ($colName  === null && str_contains($h, 'descri')) $colName  = $i;
+            if ($colQty   === null && (str_contains($h, 'qtd') || str_contains($h, 'quant'))) $colQty = $i;
+            if ($colPrice === null && (str_contains($h, 'pre') || str_contains($h, 'valor'))) $colPrice = $i;
+        }
+
+        if ($colName === null || $colQty === null || $colPrice === null) {
+            return $this->errorResponse('Colunas não encontradas. O arquivo deve conter: Descrição, Qtd, Preço.', 422);
+        }
+
+        $imported = [];
+
+        for ($i = 1; $i < count($rows); $i++) {
+            $row  = $rows[$i];
+            $name = trim((string) ($row[$colName] ?? ''));
+
+            if ($name === '') continue;
+
+            $qty   = (int)   ($row[$colQty]   ?? 0);
+            $price = (float) ($row[$colPrice]  ?? 0);
+
+            $product = $this->service->importRow($name, $qty, $price);
+            $imported[] = new ProductResource($product);
+        }
+
+        return $this->successResponse(payload: $imported);
+    }
+
+    public function adjustStock(ProductStockRequest $request, int $id): JsonResponse
+    {
+        $result = $this->service->adjustStock($id, $request->type, $request->quantity);
+
+        if (isset($result['error'])) {
+            return $this->errorResponse($result['error'], 422);
+        }
+
+        return $this->successResponse(payload: new ProductResource($result['product']), message: __('messages.updated'));
+    }
 }

+ 9 - 7
app/Http/Requests/ProductRequest.php

@@ -9,15 +9,17 @@ class ProductRequest extends FormRequest
     public function rules(): array
     {
         $rules = [
-            // Add your validation rules here
-            //'field' => 'sometimes|string|max:255',
+            'name'        => 'sometimes|string|max:255',
+            'description' => 'sometimes|nullable|string|max:2000',
+            'price_sale'  => 'sometimes|numeric|min:0',
+            'quantity'    => 'sometimes|integer|min:0',
         ];
 
-        // Different rules for creation
-        //if ($this->isMethod('POST')) {
-            // Make fields required if needed
-            // $rules['field'] = 'required|string|max:255';
-        //}
+        if ($this->isMethod('POST')) {
+            $rules['name']       = 'required|string|max:255';
+            $rules['price_sale'] = 'required|numeric|min:0';
+            $rules['quantity']   = 'required|integer|min:0';
+        }
 
         return $rules;
     }

+ 16 - 0
app/Http/Requests/ProductStockRequest.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ProductStockRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'type'     => 'required|in:entrada,saida',
+            'quantity' => 'required|integer|min:1',
+        ];
+    }
+}

+ 7 - 13
app/Http/Resources/ProductResource.php

@@ -18,19 +18,13 @@ class ProductResource extends JsonResource
     public function toArray(Request $request): array
     {
         return [
-            'id' => $this->id,
-            'name' => $this->name,
-            'created_at' => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
-            'updated_at' => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),
-            // Add your fields here
-
-            // Conditional fields
-            // $this->mergeWhen($request->user()?->isAdmin(), [
-            //     'internal_notes' => $this->internal_notes,
-            // ]),
-
-            // Relationships
-            // 'user' => new UserResource($this->whenLoaded('user')),
+            'id'          => $this->id,
+            'name'        => $this->name,
+            'description' => $this->description,
+            'price_sale'  => $this->price_sale,
+            'quantity'    => $this->quantity,
+            'created_at'  => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
+            'updated_at'  => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),
         ];
     }
 

+ 2 - 1
app/Models/Product.php

@@ -4,6 +4,7 @@
 
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\SoftDeletes;
 
 /**
  * @property int $id
@@ -43,7 +44,7 @@
  */
 class Product extends Model
 {
-    use HasFactory;
+    use HasFactory, SoftDeletes;
 
     protected $table = 'products';
 

+ 29 - 2
app/Services/ProductService.php

@@ -9,7 +9,7 @@ class ProductService
 {
     public function getAll(): Collection
     {
-        return Product::orderBy('created_at', 'desc')->get();
+        return Product::orderBy('name')->get();
     }
 
     public function getAllForSelect(): Collection
@@ -50,5 +50,32 @@ public function delete(int $id): bool
         return $model->delete();
     }
 
-    // Add custom business logic methods here
+    public function importRow(string $name, int $quantity, float $price): Product
+    {
+        return Product::updateOrCreate(
+            ['name' => $name],
+            ['price_sale' => $price, 'quantity' => $quantity]
+        );
+    }
+
+    public function adjustStock(int $id, string $type, int $quantity): array
+    {
+        $product = $this->findById($id);
+
+        if (!$product) {
+            return ['error' => 'Produto não encontrado.'];
+        }
+
+        if ($type === 'saida' && $product->quantity < $quantity) {
+            return ['error' => "Estoque insuficiente. Disponível: {$product->quantity}"];
+        }
+
+        $product->quantity = $type === 'entrada'
+            ? $product->quantity + $quantity
+            : $product->quantity - $quantity;
+
+        $product->save();
+
+        return ['product' => $product->fresh()];
+    }
 }

+ 2 - 1
composer.json

@@ -13,7 +13,8 @@
         "laravel/framework": "^12.0",
         "laravel/sanctum": "^4.0",
         "laravel/tinker": "^2.9",
-        "league/flysystem-aws-s3-v3": "^3.0"
+        "league/flysystem-aws-s3-v3": "^3.0",
+        "phpoffice/phpspreadsheet": "^5.7"
     },
     "require-dev": {
         "barryvdh/laravel-ide-helper": "^3.6",

+ 374 - 80
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "b7b8a0825559a45ee8015f0048c9eeea",
+    "content-hash": "2eaa837ed7d3c567db3034d8fe361eb0",
     "packages": [
         {
             "name": "aws/aws-crt-php",
@@ -286,6 +286,85 @@
             ],
             "time": "2024-02-09T16:56:22+00:00"
         },
+        {
+            "name": "composer/pcre",
+            "version": "3.3.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/pcre.git",
+                "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+                "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.4 || ^8.0"
+            },
+            "conflict": {
+                "phpstan/phpstan": "<1.11.10"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.12 || ^2",
+                "phpstan/phpstan-strict-rules": "^1 || ^2",
+                "phpunit/phpunit": "^8 || ^9"
+            },
+            "type": "library",
+            "extra": {
+                "phpstan": {
+                    "includes": [
+                        "extension.neon"
+                    ]
+                },
+                "branch-alias": {
+                    "dev-main": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\Pcre\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+            "keywords": [
+                "PCRE",
+                "preg",
+                "regex",
+                "regular expression"
+            ],
+            "support": {
+                "issues": "https://github.com/composer/pcre/issues",
+                "source": "https://github.com/composer/pcre/tree/3.3.2"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-11-12T16:29:46+00:00"
+        },
         {
             "name": "dflydev/dot-access-data",
             "version": "v3.0.3",
@@ -2339,6 +2418,191 @@
             ],
             "time": "2024-12-08T08:18:47+00:00"
         },
+        {
+            "name": "maennchen/zipstream-php",
+            "version": "3.2.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/maennchen/ZipStream-PHP.git",
+                "reference": "77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e",
+                "reference": "77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "ext-zlib": "*",
+                "php-64bit": "^8.3"
+            },
+            "require-dev": {
+                "brianium/paratest": "^7.7",
+                "ext-zip": "*",
+                "friendsofphp/php-cs-fixer": "^3.86",
+                "guzzlehttp/guzzle": "^7.5",
+                "mikey179/vfsstream": "^1.6",
+                "php-coveralls/php-coveralls": "^2.5",
+                "phpunit/phpunit": "^12.0",
+                "vimeo/psalm": "^6.0"
+            },
+            "suggest": {
+                "guzzlehttp/psr7": "^2.4",
+                "psr/http-message": "^2.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "ZipStream\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paul Duncan",
+                    "email": "pabs@pablotron.org"
+                },
+                {
+                    "name": "Jonatan Männchen",
+                    "email": "jonatan@maennchen.ch"
+                },
+                {
+                    "name": "Jesse Donat",
+                    "email": "donatj@gmail.com"
+                },
+                {
+                    "name": "András Kolesár",
+                    "email": "kolesar@kolesar.hu"
+                }
+            ],
+            "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
+            "keywords": [
+                "stream",
+                "zip"
+            ],
+            "support": {
+                "issues": "https://github.com/maennchen/ZipStream-PHP/issues",
+                "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/maennchen",
+                    "type": "github"
+                }
+            ],
+            "time": "2026-04-11T18:38:28+00:00"
+        },
+        {
+            "name": "markbaker/complex",
+            "version": "3.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/MarkBaker/PHPComplex.git",
+                "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
+                "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0"
+            },
+            "require-dev": {
+                "dealerdirect/phpcodesniffer-composer-installer": "dev-master",
+                "phpcompatibility/php-compatibility": "^9.3",
+                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
+                "squizlabs/php_codesniffer": "^3.7"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Complex\\": "classes/src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mark Baker",
+                    "email": "mark@lange.demon.co.uk"
+                }
+            ],
+            "description": "PHP Class for working with complex numbers",
+            "homepage": "https://github.com/MarkBaker/PHPComplex",
+            "keywords": [
+                "complex",
+                "mathematics"
+            ],
+            "support": {
+                "issues": "https://github.com/MarkBaker/PHPComplex/issues",
+                "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
+            },
+            "time": "2022-12-06T16:21:08+00:00"
+        },
+        {
+            "name": "markbaker/matrix",
+            "version": "3.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/MarkBaker/PHPMatrix.git",
+                "reference": "728434227fe21be27ff6d86621a1b13107a2562c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
+                "reference": "728434227fe21be27ff6d86621a1b13107a2562c",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "dealerdirect/phpcodesniffer-composer-installer": "dev-master",
+                "phpcompatibility/php-compatibility": "^9.3",
+                "phpdocumentor/phpdocumentor": "2.*",
+                "phploc/phploc": "^4.0",
+                "phpmd/phpmd": "2.*",
+                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
+                "sebastian/phpcpd": "^4.0",
+                "squizlabs/php_codesniffer": "^3.7"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Matrix\\": "classes/src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mark Baker",
+                    "email": "mark@demon-angel.eu"
+                }
+            ],
+            "description": "PHP Class for working with matrices",
+            "homepage": "https://github.com/MarkBaker/PHPMatrix",
+            "keywords": [
+                "mathematics",
+                "matrix",
+                "vector"
+            ],
+            "support": {
+                "issues": "https://github.com/MarkBaker/PHPMatrix/issues",
+                "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
+            },
+            "time": "2022-12-02T22:17:43+00:00"
+        },
         {
             "name": "monolog/monolog",
             "version": "3.9.0",
@@ -2906,6 +3170,115 @@
             ],
             "time": "2025-05-08T08:14:37+00:00"
         },
+        {
+            "name": "phpoffice/phpspreadsheet",
+            "version": "5.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
+                "reference": "9f55d3b9b7bcb1084fda8340e4b7ce4ed10cd0c8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/9f55d3b9b7bcb1084fda8340e4b7ce4ed10cd0c8",
+                "reference": "9f55d3b9b7bcb1084fda8340e4b7ce4ed10cd0c8",
+                "shasum": ""
+            },
+            "require": {
+                "composer/pcre": "^1||^2||^3",
+                "ext-ctype": "*",
+                "ext-dom": "*",
+                "ext-fileinfo": "*",
+                "ext-filter": "*",
+                "ext-gd": "*",
+                "ext-iconv": "*",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-simplexml": "*",
+                "ext-xml": "*",
+                "ext-xmlreader": "*",
+                "ext-xmlwriter": "*",
+                "ext-zip": "*",
+                "ext-zlib": "*",
+                "maennchen/zipstream-php": "^2.1 || ^3.0",
+                "markbaker/complex": "^3.0",
+                "markbaker/matrix": "^3.0",
+                "php": "^8.1",
+                "psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
+            },
+            "require-dev": {
+                "dealerdirect/phpcodesniffer-composer-installer": "dev-main",
+                "dompdf/dompdf": "^2.0 || ^3.0",
+                "ext-intl": "*",
+                "friendsofphp/php-cs-fixer": "^3.2",
+                "mitoteam/jpgraph": "^10.5",
+                "mpdf/mpdf": "^8.1.1",
+                "phpcompatibility/php-compatibility": "^9.3",
+                "phpstan/phpstan": "^1.1 || ^2.0",
+                "phpstan/phpstan-deprecation-rules": "^1.0 || ^2.0",
+                "phpstan/phpstan-phpunit": "^1.0 || ^2.0",
+                "phpunit/phpunit": "^10.5",
+                "squizlabs/php_codesniffer": "^3.7",
+                "tecnickcom/tcpdf": "^6.5"
+            },
+            "suggest": {
+                "dompdf/dompdf": "Option for rendering PDF with PDF Writer",
+                "ext-intl": "PHP Internationalization Functions, required for NumberFormat Wizard and StringHelper::setLocale()",
+                "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
+                "mpdf/mpdf": "Option for rendering PDF with PDF Writer",
+                "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Maarten Balliauw",
+                    "homepage": "https://blog.maartenballiauw.be"
+                },
+                {
+                    "name": "Mark Baker",
+                    "homepage": "https://markbakeruk.net"
+                },
+                {
+                    "name": "Franck Lefevre",
+                    "homepage": "https://rootslabs.net"
+                },
+                {
+                    "name": "Erik Tilt"
+                },
+                {
+                    "name": "Adrien Crivelli"
+                },
+                {
+                    "name": "Owen Leibman"
+                }
+            ],
+            "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
+            "homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
+            "keywords": [
+                "OpenXML",
+                "excel",
+                "gnumeric",
+                "ods",
+                "php",
+                "spreadsheet",
+                "xls",
+                "xlsx"
+            ],
+            "support": {
+                "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
+                "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/5.7.0"
+            },
+            "time": "2026-04-20T02:42:17+00:00"
+        },
         {
             "name": "phpoption/phpoption",
             "version": "1.9.3",
@@ -6463,85 +6836,6 @@
             ],
             "time": "2025-08-20T18:52:43+00:00"
         },
-        {
-            "name": "composer/pcre",
-            "version": "3.3.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/composer/pcre.git",
-                "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
-                "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.4 || ^8.0"
-            },
-            "conflict": {
-                "phpstan/phpstan": "<1.11.10"
-            },
-            "require-dev": {
-                "phpstan/phpstan": "^1.12 || ^2",
-                "phpstan/phpstan-strict-rules": "^1 || ^2",
-                "phpunit/phpunit": "^8 || ^9"
-            },
-            "type": "library",
-            "extra": {
-                "phpstan": {
-                    "includes": [
-                        "extension.neon"
-                    ]
-                },
-                "branch-alias": {
-                    "dev-main": "3.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Composer\\Pcre\\": "src"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jordi Boggiano",
-                    "email": "j.boggiano@seld.be",
-                    "homepage": "http://seld.be"
-                }
-            ],
-            "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
-            "keywords": [
-                "PCRE",
-                "preg",
-                "regex",
-                "regular expression"
-            ],
-            "support": {
-                "issues": "https://github.com/composer/pcre/issues",
-                "source": "https://github.com/composer/pcre/tree/3.3.2"
-            },
-            "funding": [
-                {
-                    "url": "https://packagist.com",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/composer",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2024-11-12T16:29:46+00:00"
-        },
         {
             "name": "fakerphp/faker",
             "version": "v1.24.1",

+ 36 - 0
database/migrations/2026_05_14_000001_alter_products_table_nullable_and_description.php

@@ -0,0 +1,36 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::table('products', function (Blueprint $table) {
+            $table->text('description')->nullable()->after('name');
+            $table->string('sku')->nullable()->change();
+            $table->string('barcode')->nullable()->change();
+            $table->string('measure_unit')->nullable()->change();
+            $table->decimal('price_cost', 10, 2)->nullable()->change();
+            $table->decimal('weight', 10, 3)->nullable()->change();
+            $table->decimal('length', 10, 3)->nullable()->change();
+            $table->decimal('height', 10, 3)->nullable()->change();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::table('products', function (Blueprint $table) {
+            $table->dropColumn('description');
+            $table->string('sku')->nullable(false)->change();
+            $table->string('barcode')->nullable(false)->change();
+            $table->string('measure_unit')->nullable(false)->change();
+            $table->decimal('price_cost', 10, 2)->nullable(false)->change();
+            $table->decimal('weight', 10, 3)->nullable(false)->change();
+            $table->decimal('length', 10, 3)->nullable(false)->change();
+            $table->decimal('height', 10, 3)->nullable(false)->change();
+        });
+    }
+};

+ 22 - 0
database/migrations/2026_05_14_000002_add_quantity_to_products_table.php

@@ -0,0 +1,22 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::table('products', function (Blueprint $table) {
+            $table->unsignedInteger('quantity')->default(0)->after('price_sale');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::table('products', function (Blueprint $table) {
+            $table->dropColumn('quantity');
+        });
+    }
+};

+ 1 - 142
database/seeders/DeveloperTestSeeder.php

@@ -2,153 +2,12 @@
 
 namespace Database\Seeders;
 
-use App\Models\Product;
 use Illuminate\Database\Seeder;
 
 class DeveloperTestSeeder extends Seeder
 {
     public function run(): void
     {
-        $this->seedProducts();
-    }
-
-    private function seedProducts(): void
-    {
-        $products = [
-            [
-                'name'               => 'Apostila Nível 1',
-                'sku'                => 'AP-NV1',
-                'barcode'            => '7890001000001',
-                'price_cost'         => 18.00,
-                'price_sale'         => 35.00,
-                'measure_unit'       => 'UN',
-                'kit'                => false,
-                'visible_franchisee' => true,
-                'weight'             => 0.300,
-                'length'             => 29.7,
-                'height'             => 21.0,
-            ],
-            [
-                'name'               => 'Apostila Nível 2',
-                'sku'                => 'AP-NV2',
-                'barcode'            => '7890001000002',
-                'price_cost'         => 18.00,
-                'price_sale'         => 35.00,
-                'measure_unit'       => 'UN',
-                'kit'                => false,
-                'visible_franchisee' => true,
-                'weight'             => 0.300,
-                'length'             => 29.7,
-                'height'             => 21.0,
-            ],
-            [
-                'name'               => 'Apostila Nível 3',
-                'sku'                => 'AP-NV3',
-                'barcode'            => '7890001000003',
-                'price_cost'         => 18.00,
-                'price_sale'         => 35.00,
-                'measure_unit'       => 'UN',
-                'kit'                => false,
-                'visible_franchisee' => true,
-                'weight'             => 0.300,
-                'length'             => 29.7,
-                'height'             => 21.0,
-            ],
-            [
-                'name'               => 'Kit Material Didático Básico',
-                'sku'                => 'KIT-MAT-BAS',
-                'barcode'            => '7890001000010',
-                'price_cost'         => 45.00,
-                'price_sale'         => 89.90,
-                'measure_unit'       => 'KIT',
-                'kit'                => true,
-                'visible_franchisee' => true,
-                'weight'             => 0.800,
-                'length'             => 30.0,
-                'height'             => 22.0,
-            ],
-            [
-                'name'               => 'Kit Material Didático Completo',
-                'sku'                => 'KIT-MAT-COMP',
-                'barcode'            => '7890001000011',
-                'price_cost'         => 90.00,
-                'price_sale'         => 169.90,
-                'measure_unit'       => 'KIT',
-                'kit'                => true,
-                'visible_franchisee' => true,
-                'weight'             => 1.500,
-                'length'             => 30.0,
-                'height'             => 22.0,
-            ],
-            [
-                'name'               => 'Caderno de Atividades',
-                'sku'                => 'CAD-ATI',
-                'barcode'            => '7890001000020',
-                'price_cost'         => 12.00,
-                'price_sale'         => 24.90,
-                'measure_unit'       => 'UN',
-                'kit'                => false,
-                'visible_franchisee' => true,
-                'weight'             => 0.200,
-                'length'             => 29.7,
-                'height'             => 21.0,
-            ],
-            [
-                'name'               => 'Livro do Aluno — Ginástica do Cérebro',
-                'sku'                => 'LV-ALUNO-GC',
-                'barcode'            => '7890001000030',
-                'price_cost'         => 32.00,
-                'price_sale'         => 59.90,
-                'measure_unit'       => 'UN',
-                'kit'                => false,
-                'visible_franchisee' => true,
-                'weight'             => 0.450,
-                'length'             => 23.0,
-                'height'             => 16.0,
-            ],
-            [
-                'name'               => 'Camiseta Ginástica do Cérebro',
-                'sku'                => 'CAM-GC',
-                'barcode'            => '7890001000040',
-                'price_cost'         => 20.00,
-                'price_sale'         => 49.90,
-                'measure_unit'       => 'UN',
-                'kit'                => false,
-                'visible_franchisee' => true,
-                'weight'             => 0.200,
-                'length'             => 30.0,
-                'height'             => 20.0,
-            ],
-            [
-                'name'               => 'Pasta do Aluno',
-                'sku'                => 'PAST-ALUNO',
-                'barcode'            => '7890001000050',
-                'price_cost'         => 5.00,
-                'price_sale'         => 12.90,
-                'measure_unit'       => 'UN',
-                'kit'                => false,
-                'visible_franchisee' => true,
-                'weight'             => 0.100,
-                'length'             => 33.0,
-                'height'             => 23.0,
-            ],
-            [
-                'name'               => 'Certificado de Conclusão',
-                'sku'                => 'CERT-CONCL',
-                'barcode'            => '7890001000060',
-                'price_cost'         => 2.00,
-                'price_sale'         => 5.00,
-                'measure_unit'       => 'UN',
-                'kit'                => false,
-                'visible_franchisee' => false,
-                'weight'             => 0.050,
-                'length'             => 29.7,
-                'height'             => 21.0,
-            ],
-        ];
-
-        foreach ($products as $product) {
-            Product::firstOrCreate(['sku' => $product['sku']], $product);
-        }
+        //
     }
 }

+ 303 - 10
database/seeders/PermissionSeeder.php

@@ -23,7 +23,7 @@ public function run(): void
             ],
             [
                 "scope"       => "franchisee",
-                "description" => "Franchisee",
+                "description" => "Franqueados",
                 "bits"        => Permission::MENU | Permission::VIEW,
                 "children"    => [
                     [
@@ -32,8 +32,15 @@ public function run(): void
                         "bits"        => Permission::ALL_PERMS,
                         "children"    => [],
                     ],
+                    [
+                        "scope"       => "franchisee-unit",
+                        "description" => "Unidades do Franqueado",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
                 ],
             ],
+            // Pacotes / Aulas
             [
                 "scope"       => "class-package",
                 "description" => "Pacotes (Franqueadora)",
@@ -46,6 +53,57 @@ public function run(): void
                 "bits"        => Permission::ALL_PERMS,
                 "children"    => [],
             ],
+            [
+                "scope"       => "class-package-franchisee",
+                "description" => "Pacotes (Franqueado)",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [],
+            ],
+            [
+                "scope"       => "class",
+                "description" => "Aulas",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [
+                    [
+                        "scope"       => "class-attendance",
+                        "description" => "Frequência de Aulas",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
+            [
+                "scope"       => "modality",
+                "description" => "Modalidades",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [],
+            ],
+            // Alunos
+            [
+                "scope"       => "student",
+                "description" => "Alunos",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [
+                    [
+                        "scope"       => "student-history",
+                        "description" => "Histórico de Alunos",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "student-media",
+                        "description" => "Mídias de Alunos",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "student-responsible",
+                        "description" => "Responsáveis de Alunos",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
             [
                 "scope"       => "student-contract",
                 "description" => "Contratos de Alunos",
@@ -54,10 +112,216 @@ public function run(): void
             ],
             [
                 "scope"       => "media",
-                "description" => "Mídias de Alunos",
+                "description" => "Mídias",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [],
+            ],
+            // Kanban
+            [
+                "scope"       => "kanban",
+                "description" => "Kanban",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [
+                    [
+                        "scope"       => "kanban-status",
+                        "description" => "Status do Kanban",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "kanban-movement",
+                        "description" => "Movimentos do Kanban",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
+            // Suporte
+            [
+                "scope"       => "support-ticket",
+                "description" => "Chamados de Suporte",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [
+                    [
+                        "scope"       => "support-status",
+                        "description" => "Status de Suporte",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "support-movement",
+                        "description" => "Movimentos de Suporte",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
+            // Notificações
+            [
+                "scope"       => "notification",
+                "description" => "Notificações",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [
+                    [
+                        "scope"       => "notification-recipient",
+                        "description" => "Destinatários de Notificações",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
+            // Produtos / Inventário
+            [
+                "scope"       => "product",
+                "description" => "Produtos",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [
+                    [
+                        "scope"       => "product-kit",
+                        "description" => "Kits de Produtos",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "product-movement",
+                        "description" => "Movimentação de Produtos",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "product-order",
+                        "description" => "Pedidos de Produtos",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [
+                            [
+                                "scope"       => "product-order-item",
+                                "description" => "Itens de Pedido de Produtos",
+                                "bits"        => Permission::ALL_PERMS,
+                                "children"    => [],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+            [
+                "scope"       => "franchisor-inventory",
+                "description" => "Estoque (Franqueadora)",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [],
+            ],
+            [
+                "scope"       => "franchisee-inventory",
+                "description" => "Estoque (Franqueado)",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [],
+            ],
+            // Fornecedores / Pagamentos
+            [
+                "scope"       => "supplier",
+                "description" => "Fornecedores",
                 "bits"        => Permission::ALL_PERMS,
                 "children"    => [],
             ],
+            [
+                "scope"       => "payment-method",
+                "description" => "Formas de Pagamento",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [],
+            ],
+            // Financeiro
+            [
+                "scope"       => "financial",
+                "description" => "Financeiro",
+                "bits"        => Permission::MENU | Permission::VIEW,
+                "children"    => [
+                    [
+                        "scope"       => "financial-account-payable",
+                        "description" => "Contas a Pagar",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "financial-account-receive",
+                        "description" => "Contas a Receber",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "financial-invoice",
+                        "description" => "Notas Fiscais",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "financial-plan-account",
+                        "description" => "Plano de Contas",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
+            // Tesouraria
+            [
+                "scope"       => "treasury",
+                "description" => "Tesouraria",
+                "bits"        => Permission::MENU | Permission::VIEW,
+                "children"    => [
+                    [
+                        "scope"       => "treasury-account",
+                        "description" => "Contas de Tesouraria",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "treasury-imports",
+                        "description" => "Importações de Tesouraria",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [
+                            [
+                                "scope"       => "treasury-import-line",
+                                "description" => "Linhas de Importação",
+                                "bits"        => Permission::ALL_PERMS,
+                                "children"    => [],
+                            ],
+                        ],
+                    ],
+                    [
+                        "scope"       => "treasury-launch",
+                        "description" => "Lançamentos de Tesouraria",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
+            // Integrações
+            [
+                "scope"       => "integrations",
+                "description" => "Integrações",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [
+                    [
+                        "scope"       => "integration-variable",
+                        "description" => "Variáveis de Integração",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
+            // Feriados
+            [
+                "scope"       => "holiday",
+                "description" => "Feriados",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [
+                    [
+                        "scope"       => "base-holiday",
+                        "description" => "Feriados Base",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                ],
+            ],
+            // TBR
             [
                 "scope"       => "tbr",
                 "description" => "TBR",
@@ -87,6 +351,24 @@ public function run(): void
                         "bits"        => Permission::ALL_PERMS,
                         "children"    => [],
                     ],
+                    [
+                        "scope"       => "franchisee-royalties-bracket",
+                        "description" => "Faixas de Royalties do Franqueado",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "franchisee-fnm-bracket",
+                        "description" => "Faixas de FNM do Franqueado",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "franchisee-maintenance-bracket",
+                        "description" => "Faixas de Manutenção do Franqueado",
+                        "bits"        => Permission::ALL_PERMS,
+                        "children"    => [],
+                    ],
                     [
                         "scope"       => "tbr-calculation",
                         "description" => "Cálculo de TBR",
@@ -107,6 +389,7 @@ public function run(): void
                     ],
                 ],
             ],
+            // Configurações
             [
                 "scope"       => "config",
                 "description" => "Configurações",
@@ -114,36 +397,49 @@ public function run(): void
                 "children"    => [
                     [
                         "scope"       => "config.user",
-                        "description" => "Configurações de Usuários",
+                        "description" => "Usuários",
+                        "bits"        => Permission::CRUD,
+                        "children"    => [],
+                    ],
+                    [
+                        "scope"       => "config.user-type",
+                        "description" => "Tipos de Usuário",
                         "bits"        => Permission::CRUD,
                         "children"    => [],
                     ],
                     [
                         "scope"       => "config.permission",
-                        "description" => "Configurações de Permissões",
+                        "description" => "Permissões",
                         "bits"        => Permission::CRUD,
                         "children"    => [],
                     ],
                     [
                         "scope"       => "config.city",
-                        "description" => "Configurações de Cidades",
+                        "description" => "Cidades",
                         "bits"        => Permission::CRUD,
                         "children"    => [],
                     ],
                     [
                         "scope"       => "config.country",
-                        "description" => "Configurações de Países",
+                        "description" => "Países",
                         "bits"        => Permission::CRUD,
                         "children"    => [],
                     ],
                     [
                         "scope"       => "config.state",
-                        "description" => "Configurações de Estados",
+                        "description" => "Estados",
                         "bits"        => Permission::CRUD,
                         "children"    => [],
                     ],
                 ],
             ],
+            // Unidade — escopos adicionais usados em subrotas de unit
+            [
+                "scope"       => "unit-user",
+                "description" => "Usuários da Unidade",
+                "bits"        => Permission::ALL_PERMS,
+                "children"    => [],
+            ],
         ];
 
         $this->createPermissionsAndChildren(permissions: $permissions);
@@ -151,9 +447,6 @@ public function run(): void
 
     /**
      * Recursively creates or updates permissions and handles nesting.
-     *
-     * @param array $permissions The array of permission data.
-     * @param Permission|null $parent The parent Permission object (for nested sets).
      */
     private function createPermissionsAndChildren(
         array $permissions,

+ 0 - 13
database/seeders/ProductSeeder.php

@@ -1,13 +0,0 @@
-<?php
-
-namespace Database\Seeders;
-
-use Illuminate\Database\Seeder;
-
-class ProductSeeder extends Seeder
-{
-    public function run(): void
-    {
-        // Data moved to DeveloperTestSeeder
-    }
-}

+ 93 - 2
database/seeders/UserTypePermissionSeeder.php

@@ -21,10 +21,99 @@ public function run(): void
                     foreach ($allPermissions as $scope => $perm) {
                         $dataToSync[] = [
                             'scope' => $scope,
-                            'bits'  => $perm->bits
+                            'bits'  => $perm->bits,
                         ];
                     }
                     break;
+
+                case UserTypeEnum::ADMIN_FRANCHISEE:
+                    $dataToSync = [
+                        // Dashboard
+                        ['scope' => 'dashboard',                        'bits' => Permission::VIEW | Permission::MENU],
+
+                        // Franqueado — visualiza o próprio, gerencia suas unidades
+                        ['scope' => 'franchisee',                       'bits' => Permission::VIEW | Permission::MENU],
+                        ['scope' => 'unit',                             'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'franchisee-unit',                  'bits' => Permission::VIEW],
+
+                        // Pacotes — visualiza os disponibilizados pela franqueadora
+                        ['scope' => 'class-package',                    'bits' => Permission::VIEW | Permission::MENU],
+                        ['scope' => 'class-package-unit',               'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'class-package-franchisee',         'bits' => Permission::VIEW],
+
+                        // Aulas
+                        ['scope' => 'class',                            'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'class-attendance',                 'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'modality',                         'bits' => Permission::VIEW],
+
+                        // Alunos
+                        ['scope' => 'student',                          'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'student-contract',                 'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'student-history',                  'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'student-media',                    'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'student-responsible',              'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'media',                            'bits' => Permission::ALL_PERMS],
+
+                        // Kanban
+                        ['scope' => 'kanban',                           'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'kanban-status',                    'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'kanban-movement',                  'bits' => Permission::ALL_PERMS],
+
+                        // Suporte
+                        ['scope' => 'support-ticket',                   'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'support-movement',                 'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'support-status',                   'bits' => Permission::VIEW],
+
+                        // Notificações
+                        ['scope' => 'notification',                     'bits' => Permission::VIEW],
+
+                        // Produtos / Estoque
+                        ['scope' => 'product',                          'bits' => Permission::VIEW],
+                        ['scope' => 'product-kit',                      'bits' => Permission::VIEW],
+                        ['scope' => 'product-order',                    'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'product-order-item',               'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'franchisee-inventory',             'bits' => Permission::ALL_PERMS],
+
+                        // Financeiro (gestão da unidade)
+                        ['scope' => 'financial',                        'bits' => Permission::VIEW | Permission::MENU],
+                        ['scope' => 'financial-account-payable',        'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'financial-account-receive',        'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'financial-invoice',                'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'financial-plan-account',           'bits' => Permission::VIEW],
+
+                        // Tesouraria
+                        ['scope' => 'treasury',                         'bits' => Permission::VIEW | Permission::MENU],
+                        ['scope' => 'treasury-account',                 'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'treasury-imports',                 'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'treasury-import-line',             'bits' => Permission::ALL_PERMS],
+                        ['scope' => 'treasury-launch',                  'bits' => Permission::ALL_PERMS],
+
+                        // Formas de pagamento e fornecedores (só visualiza)
+                        ['scope' => 'payment-method',                   'bits' => Permission::VIEW],
+                        ['scope' => 'supplier',                         'bits' => Permission::VIEW],
+
+                        // TBR — apenas visualiza o que diz respeito ao franqueado
+                        ['scope' => 'franchisee-tbr',                   'bits' => Permission::VIEW],
+                        ['scope' => 'franchisee-royalties-bracket',     'bits' => Permission::VIEW],
+                        ['scope' => 'franchisee-fnm-bracket',           'bits' => Permission::VIEW],
+                        ['scope' => 'franchisee-maintenance-bracket',   'bits' => Permission::VIEW],
+                        ['scope' => 'inhabitant-classification',        'bits' => Permission::VIEW],
+                        ['scope' => 'unit-inhabitant-classification',   'bits' => Permission::ALL_PERMS],
+
+                        // Usuários da unidade
+                        ['scope' => 'unit-user',                        'bits' => Permission::ALL_PERMS],
+
+                        // Feriados (visualiza)
+                        ['scope' => 'holiday',                          'bits' => Permission::VIEW],
+
+                        // Configurações básicas (apenas leitura de endereço)
+                        ['scope' => 'config.city',                      'bits' => Permission::VIEW],
+                        ['scope' => 'config.country',                   'bits' => Permission::VIEW],
+                        ['scope' => 'config.state',                     'bits' => Permission::VIEW],
+                        ['scope' => 'config.user',                      'bits' => Permission::VIEW | Permission::EDIT],
+                    ];
+                    break;
+
                 case UserTypeEnum::USER:
                     $dataToSync = [
                         ['scope' => 'dashboard',                        'bits' => Permission::VIEW],
@@ -43,12 +132,14 @@ public function run(): void
                         ['scope' => 'media',                            'bits' => Permission::ALL_PERMS],
                     ];
                     break;
+
                 case UserTypeEnum::GUEST:
                     $dataToSync = [
                         ['scope' => 'config.user', 'bits' => Permission::VIEW],
                     ];
                     break;
             }
+
             if (!empty($dataToSync)) {
                 $this->seedUserTypePermissions($dataToSync, $userType->value, $allPermissions);
             }
@@ -67,7 +158,7 @@ private function seedUserTypePermissions(array $permissionDataList, string $user
                         'permission_id' => $permissionModel->id,
                     ],
                     [
-                        'bits' => $data['bits']
+                        'bits' => $data['bits'],
                     ]
                 );
             }

+ 5 - 5
routes/authRoutes/base_holiday.php

@@ -4,13 +4,13 @@
 use Illuminate\Support\Facades\Route;
 
 Route::controller(BaseHolidayController::class)->prefix('base-holiday')->group(function () {
-    Route::get('/', 'index');
+    Route::get('/', 'index')->middleware('permission:base-holiday,view');
 
-    Route::post('/', 'store');
+    Route::post('/', 'store')->middleware('permission:base-holiday,add');
 
-    Route::get('/{id}', 'show');
+    Route::get('/{id}', 'show')->middleware('permission:base-holiday,view');
 
-    Route::put('/{id}', 'update');
+    Route::put('/{id}', 'update')->middleware('permission:base-holiday,edit');
 
-    Route::delete('/{id}', 'destroy');
+    Route::delete('/{id}', 'destroy')->middleware('permission:base-holiday,delete');
 });

+ 6 - 6
routes/authRoutes/class_package.php

@@ -4,10 +4,10 @@
 use App\Http\Controllers\ClassPackageController;
 
 Route::controller(ClassPackageController::class)->prefix('class-package')->group(function () {
-    Route::get('/', 'index');
-    Route::get('/by-unit', 'byUnit');
-    Route::post('/', 'store');
-    Route::get('/{id}', 'show');
-    Route::put('/{id}', 'update');
-    Route::delete('/{id}', 'destroy');
+    Route::get('/', 'index')->middleware('permission:class-package,view');
+    Route::get('/by-unit', 'byUnit')->middleware('permission:class-package,view');
+    Route::post('/', 'store')->middleware('permission:class-package,add');
+    Route::get('/{id}', 'show')->middleware('permission:class-package,view');
+    Route::put('/{id}', 'update')->middleware('permission:class-package,edit');
+    Route::delete('/{id}', 'destroy')->middleware('permission:class-package,delete');
 });

+ 7 - 7
routes/authRoutes/class_package_unit.php

@@ -4,11 +4,11 @@
 use App\Http\Controllers\ClassPackageUnitController;
 
 Route::controller(ClassPackageUnitController::class)->prefix('class-package-unit')->group(function () {
-    Route::get('/', 'index');
-    Route::get('/visible', 'byUnit');
-    Route::post('/', 'store');
-    Route::get('/{id}', 'show');
-    Route::put('/{id}', 'update');
-    Route::patch('/{id}/toggle-visibility', 'toggleVisibility');
-    Route::delete('/{id}', 'destroy');
+    Route::get('/', 'index')->middleware('permission:class-package-unit,view');
+    Route::get('/visible', 'byUnit')->middleware('permission:class-package-unit,view');
+    Route::post('/', 'store')->middleware('permission:class-package-unit,add');
+    Route::get('/{id}', 'show')->middleware('permission:class-package-unit,view');
+    Route::put('/{id}', 'update')->middleware('permission:class-package-unit,edit');
+    Route::patch('/{id}/toggle-visibility', 'toggleVisibility')->middleware('permission:class-package-unit,edit');
+    Route::delete('/{id}', 'destroy')->middleware('permission:class-package-unit,delete');
 });

+ 5 - 5
routes/authRoutes/holiday.php

@@ -4,13 +4,13 @@
 use App\Http\Controllers\HolidayController;
 
 Route::controller(HolidayController::class)->prefix('holiday')->group(function () {
-    Route::get('/', 'index');
+    Route::get('/', 'index')->middleware('permission:holiday,view');
 
-    Route::post('/', 'store');
+    Route::post('/', 'store')->middleware('permission:holiday,add');
 
-    Route::get('/{id}', 'show');
+    Route::get('/{id}', 'show')->middleware('permission:holiday,view');
 
-    Route::put('/{id}', 'update');
+    Route::put('/{id}', 'update')->middleware('permission:holiday,edit');
 
-    Route::delete('/{id}', 'destroy');
+    Route::delete('/{id}', 'destroy')->middleware('permission:holiday,delete');
 });

+ 6 - 6
routes/authRoutes/inhabitant_classification.php

@@ -4,15 +4,15 @@
 use App\Http\Controllers\InhabitantClassificationController;
 
 Route::controller(InhabitantClassificationController::class)->prefix('inhabitant-classification')->group(function () {
-    Route::get('/all/select', 'selectList');
+    Route::get('/all/select', 'selectList')->middleware('permission:inhabitant-classification,view');
 
-    Route::get('/', 'index');
+    Route::get('/', 'index')->middleware('permission:inhabitant-classification,view');
 
-    Route::post('/', 'store');
+    Route::post('/', 'store')->middleware('permission:inhabitant-classification,add');
 
-    Route::get('/{id}', 'show');
+    Route::get('/{id}', 'show')->middleware('permission:inhabitant-classification,view');
 
-    Route::put('/{id}', 'update');
+    Route::put('/{id}', 'update')->middleware('permission:inhabitant-classification,edit');
 
-    Route::delete('/{id}', 'destroy');
+    Route::delete('/{id}', 'destroy')->middleware('permission:inhabitant-classification,delete');
 });

+ 5 - 5
routes/authRoutes/media.php

@@ -4,13 +4,13 @@
 use App\Http\Controllers\MediaController;
 
 Route::controller(MediaController::class)->prefix('media')->group(function () {
-    Route::get('/', 'index');
+    Route::get('/', 'index')->middleware('permission:media,view');
 
-    Route::post('/', 'store');
+    Route::post('/', 'store')->middleware('permission:media,add');
 
-    Route::get('/{id}', 'show');
+    Route::get('/{id}', 'show')->middleware('permission:media,view');
 
-    Route::put('/{id}', 'update');
+    Route::put('/{id}', 'update')->middleware('permission:media,edit');
 
-    Route::delete('/{id}', 'destroy');
+    Route::delete('/{id}', 'destroy')->middleware('permission:media,delete');
 });

+ 4 - 0
routes/authRoutes/product.php

@@ -10,9 +10,13 @@
 
     Route::post('/', 'store')->middleware('permission:product,add');
 
+    Route::post('/import', 'import')->middleware('permission:product,add');
+
     Route::get('/{id}', 'show')->middleware('permission:product,view');
 
     Route::put('/{id}', 'update')->middleware('permission:product,edit');
 
     Route::delete('/{id}', 'destroy')->middleware('permission:product,delete');
+
+    Route::patch('/{id}/stock', 'adjustStock')->middleware('permission:product,edit');
 });

+ 8 - 8
routes/authRoutes/student.php

@@ -4,17 +4,17 @@
 use App\Http\Controllers\StudentController;
 
 Route::controller(StudentController::class)->prefix('student')->group(function () {
-    Route::get('/franchisor/summary', 'franchisorSummary');
-    Route::get('/franchisor/active', 'franchisorActive');
-    Route::get('/franchisor/{id}', 'franchisorStudentDetail');
+    Route::get('/franchisor/summary', 'franchisorSummary')->middleware('permission:student,view');
+    Route::get('/franchisor/active', 'franchisorActive')->middleware('permission:student,view');
+    Route::get('/franchisor/{id}', 'franchisorStudentDetail')->middleware('permission:student,view');
 
-    Route::get('/', 'index');
+    Route::get('/', 'index')->middleware('permission:student,view');
 
-    Route::post('/', 'store');
+    Route::post('/', 'store')->middleware('permission:student,add');
 
-    Route::get('/{id}', 'show');
+    Route::get('/{id}', 'show')->middleware('permission:student,view');
 
-    Route::put('/{id}', 'update');
+    Route::put('/{id}', 'update')->middleware('permission:student,edit');
 
-    Route::delete('/{id}', 'destroy');
+    Route::delete('/{id}', 'destroy')->middleware('permission:student,delete');
 });

+ 12 - 12
routes/authRoutes/student_contract.php

@@ -4,25 +4,25 @@
 use App\Http\Controllers\StudentContractController;
 
 Route::controller(StudentContractController::class)->prefix('student-contract')->group(function () {
-    Route::get('/franchisor/summary', 'franchisorSummary');
-    Route::get('/franchisor/frozen', 'franchisorFrozen');
-    Route::get('/franchisor/cancelled', 'franchisorCancelled');
+    Route::get('/franchisor/summary', 'franchisorSummary')->middleware('permission:student-contract,view');
+    Route::get('/franchisor/frozen', 'franchisorFrozen')->middleware('permission:student-contract,view');
+    Route::get('/franchisor/cancelled', 'franchisorCancelled')->middleware('permission:student-contract,view');
 
-    Route::get('/', 'index');
+    Route::get('/', 'index')->middleware('permission:student-contract,view');
 
-    Route::post('/', 'store');
+    Route::post('/', 'store')->middleware('permission:student-contract,add');
 
-    Route::get('/{id}', 'show');
+    Route::get('/{id}', 'show')->middleware('permission:student-contract,view');
 
-    Route::put('/{id}', 'update');
+    Route::put('/{id}', 'update')->middleware('permission:student-contract,edit');
 
-    Route::post('/{id}/file', 'attachFile');
+    Route::post('/{id}/file', 'attachFile')->middleware('permission:student-contract,edit');
 
-    Route::post('/{id}/freeze', 'freeze');
+    Route::post('/{id}/freeze', 'freeze')->middleware('permission:student-contract,edit');
 
-    Route::post('/{id}/cancel', 'cancel');
+    Route::post('/{id}/cancel', 'cancel')->middleware('permission:student-contract,edit');
 
-    Route::post('/{id}/reactivate', 'reactivate');
+    Route::post('/{id}/reactivate', 'reactivate')->middleware('permission:student-contract,edit');
 
-    Route::delete('/{id}', 'destroy');
+    Route::delete('/{id}', 'destroy')->middleware('permission:student-contract,delete');
 });

+ 4 - 4
routes/authRoutes/student_media.php

@@ -4,11 +4,11 @@
 use App\Http\Controllers\StudentMediaController;
 
 Route::controller(StudentMediaController::class)->prefix('student-media')->group(function () {
-    Route::get('/', 'index');
+    Route::get('/', 'index')->middleware('permission:student-media,view');
 
-    Route::post('/', 'store');
+    Route::post('/', 'store')->middleware('permission:student-media,add');
 
-    Route::put('/{id}', 'update');
+    Route::put('/{id}', 'update')->middleware('permission:student-media,edit');
 
-    Route::delete('/{id}', 'destroy');
+    Route::delete('/{id}', 'destroy')->middleware('permission:student-media,delete');
 });

+ 4 - 4
routes/authRoutes/student_responsible.php

@@ -4,11 +4,11 @@
 use App\Http\Controllers\StudentResponsibleController;
 
 Route::controller(StudentResponsibleController::class)->group(function () {
-    Route::get('/student/{studentId}/responsible', 'getByStudent');
+    Route::get('/student/{studentId}/responsible', 'getByStudent')->middleware('permission:student-responsible,view');
 
-    Route::post('/student-responsible', 'store');
+    Route::post('/student-responsible', 'store')->middleware('permission:student-responsible,add');
 
-    Route::put('/student-responsible/{id}', 'update');
+    Route::put('/student-responsible/{id}', 'update')->middleware('permission:student-responsible,edit');
 
-    Route::delete('/student-responsible/{id}', 'destroy');
+    Route::delete('/student-responsible/{id}', 'destroy')->middleware('permission:student-responsible,delete');
 });

+ 8 - 8
routes/authRoutes/user.php

@@ -4,17 +4,17 @@
 use App\Http\Controllers\UserController;
 
 Route::controller(UserController::class)->prefix('user')->group(function () {
+    // Rotas do próprio usuário autenticado — sem restrição de permissão específica
     Route::get('/current/auth', 'authUser');
-
     Route::put('/me', 'updateMe');
 
-    Route::get('/unit', 'indexByUnit');
-    Route::get('/all/types', 'getUserTypes');
+    Route::get('/unit', 'indexByUnit')->middleware('permission:config.user,view');
+    Route::get('/all/types', 'getUserTypes')->middleware('permission:config.user,view');
 
-    Route::get('/', 'index');
-    Route::post('/', 'store');
+    Route::get('/', 'index')->middleware('permission:config.user,view');
+    Route::post('/', 'store')->middleware('permission:config.user,add');
 
-    Route::get('/{id}', 'show');
-    Route::put('/{id}', 'update');
-    Route::delete('/{id}', 'destroy');
+    Route::get('/{id}', 'show')->middleware('permission:config.user,view');
+    Route::put('/{id}', 'update')->middleware('permission:config.user,edit');
+    Route::delete('/{id}', 'destroy')->middleware('permission:config.user,delete');
 });

+ 3 - 3
routes/authRoutes/user_type.php

@@ -4,7 +4,7 @@
 use App\Http\Controllers\UserTypeController;
 
 Route::controller(UserTypeController::class)->prefix('user-type')->group(function () {
-    Route::get('/', 'index');
-    Route::post('/', 'store');
-    Route::delete('/{id}', 'destroy');
+    Route::get('/', 'index')->middleware('permission:config.user-type,view');
+    Route::post('/', 'store')->middleware('permission:config.user-type,add');
+    Route::delete('/{id}', 'destroy')->middleware('permission:config.user-type,delete');
 });