Procházet zdrojové kódy

Merge branch 'development' of gogs.softpar.inf.br:Softpar/sfp_api_laravel_diarista into development

Gustavo Zanatta před 1 týdnem
rodič
revize
aa5ba542f1

+ 0 - 1
app/Http/Controllers/ClientCalendarController.php

@@ -18,7 +18,6 @@ class ClientCalendarController extends Controller
             return $this->successResponse(payload: $dados);
         } catch (\Exception $e) {
             Log::error('Error fetching client calendar: '.$e->getMessage());
-
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }

+ 10 - 3
app/Http/Controllers/DashboardController.php

@@ -5,6 +5,8 @@ namespace App\Http\Controllers;
 use App\Http\Resources\DashboardClienteResource;
 use App\Http\Resources\DashboardPrestadorResource;
 use App\Services\DashboardService;
+use Illuminate\Auth\Access\AuthorizationException;
+use Illuminate\Database\Eloquent\ModelNotFoundException;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Support\Facades\Log;
 
@@ -20,9 +22,12 @@ class DashboardController extends Controller
             return $this->successResponse(
                 payload: new DashboardClienteResource($dados),
             );
+        } catch (AuthorizationException $e) {
+            return $this->errorResponse(message: $e->getMessage(), code: 403);
+        } catch (ModelNotFoundException) {
+            return $this->errorResponse(message: 'Cliente não encontrado.', code: 404);
         } catch (\Exception $e) {
             Log::error('Erro ao obter dados do dashboard do cliente: '.$e->getMessage());
-
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }
@@ -35,7 +40,6 @@ class DashboardController extends Controller
             return $this->successResponse(payload: $dados);
         } catch (\Exception $e) {
             Log::error('Erro ao obter detalhes do schedule do cliente: '.$e->getMessage());
-
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }
@@ -48,9 +52,12 @@ class DashboardController extends Controller
             return $this->successResponse(
                 payload: new DashboardPrestadorResource($dados),
             );
+        } catch (AuthorizationException $e) {
+            return $this->errorResponse(message: $e->getMessage(), code: 403);
+        } catch (ModelNotFoundException) {
+            return $this->errorResponse(message: 'Prestador não encontrado.', code: 404);
         } catch (\Exception $e) {
             Log::error('Erro ao obter dados do dashboard do prestador: '.$e->getMessage());
-
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }

+ 0 - 1
app/Http/Controllers/ProviderCalendarController.php

@@ -18,7 +18,6 @@ class ProviderCalendarController extends Controller
             return $this->successResponse(payload: $dados);
         } catch (\Exception $e) {
             Log::error('Error fetching provider calendar: '.$e->getMessage());
-
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }

+ 7 - 0
app/Http/Controllers/ProviderWithdrawalController.php

@@ -54,6 +54,13 @@ class ProviderWithdrawalController extends Controller
         return $this->successResponse(payload: ProviderWithdrawalResource::collection($items));
     }
 
+    public function all(): JsonResponse
+    {
+        $items = $this->service->getAllWithdrawals();
+
+        return $this->successResponse(payload: ProviderWithdrawalResource::collection($items));
+    }
+
     public function store(Request $request): JsonResponse
     {
         $provider = $this->resolveProvider();

+ 0 - 1
app/Http/Controllers/SearchController.php

@@ -19,7 +19,6 @@ class SearchController extends Controller
             return $this->successResponse(payload: $dados);
         } catch (\Exception $e) {
             Log::error('Erro ao buscar prestadores: '.$e->getMessage());
-
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }

+ 2 - 0
app/Http/Resources/PaymentResource.php

@@ -21,6 +21,8 @@ class PaymentResource extends JsonResource
             'schedule_id'                 => $this->schedule_id,
             'client_id'                   => $this->client_id,
             'provider_id'                 => $this->provider_id,
+            'client_name'                 => $this->client?->user?->name,
+            'provider_name'               => $this->provider?->user?->name,
             'client_payment_method_id'    => $this->client_payment_method_id,
             'gateway_provider'            => $this->gateway_provider,
             'gateway_entity_reference'    => $this->gateway_entity_reference,

+ 2 - 0
app/Http/Resources/PaymentSplitResource.php

@@ -14,6 +14,8 @@ class PaymentSplitResource extends JsonResource
             'id'                                => $this->id,
             'payment_id'                        => $this->payment_id,
             'provider_id'                       => $this->provider_id,
+            'provider_name'                     => $this->provider?->user?->name,
+            'provider_withdrawal_id'            => $this->provider_withdrawal_id,
             'gateway_provider'                  => $this->gateway_provider,
             'gateway_transfer_target_reference' => $this->gateway_transfer_target_reference,
             'gateway_transfer_target_label'     => $this->gateway_transfer_target_label,

+ 2 - 0
app/Http/Resources/ProviderWithdrawalResource.php

@@ -13,6 +13,7 @@ class ProviderWithdrawalResource extends JsonResource
         return [
             'id'                 => $this->id,
             'provider_id'        => $this->provider_id,
+            'provider_name'      => $this->provider?->user?->name,
             'recipient_id'       => $this->recipient_id,
             'transfer_id'        => $this->transfer_id,
             'gross_amount'       => $this->gross_amount,
@@ -23,6 +24,7 @@ class ProviderWithdrawalResource extends JsonResource
             'bank_account'       => $this->bank_account,
             'completed_at'       => $this->completed_at?->toISOString(),
             'failed_at'          => $this->failed_at?->toISOString(),
+            'payment_split_ids'  => $this->whenLoaded('paymentSplits', fn () => $this->paymentSplits->pluck('id')->values()),
             'created_at'         => $this->created_at?->toISOString(),
         ];
     }

+ 11 - 3
app/Services/DashboardService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\Enums\UserTypeEnum;
 use App\Models\Address;
 use App\Models\Client;
 use App\Models\ClientFavoriteProvider;
@@ -15,6 +16,7 @@ use App\Models\Speciality;
 use App\Models\Notification;
 use App\Rules\ScheduleBusinessRules;
 use App\Services\DistanceService;
+use Illuminate\Auth\Access\AuthorizationException;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Storage;
@@ -29,6 +31,10 @@ class DashboardService
     {
         $user = Auth::user();
 
+        if ($user->type !== UserTypeEnum::CLIENT) {
+            throw new AuthorizationException('Apenas clientes podem acessar este recurso.');
+        }
+
         $cliente = Client::with('profileMedia')->where('user_id', $user->id)->first();
 
         $headerBar = [
@@ -351,8 +357,6 @@ class DashboardService
 
         $hasPaymentMethods = ClientPaymentMethod::where('client_id', $cliente->id)->exists();
 
-
-
         return [
             'headerBar'           => $headerBar,
             'summaryInfos'        => $summaryInfos,
@@ -363,7 +367,7 @@ class DashboardService
             'providersClose'      => $providersClose,
             'todaySchedules'      => $todaySchedules,
             'schedulesProposals'  => $schedulesProposals,
-            'notifications' => $notifications,
+            'notifications'       => $notifications,
             'has_payment_methods' => $hasPaymentMethods,
         ];
     }
@@ -419,6 +423,10 @@ class DashboardService
     {
         $user = Auth::user();
 
+        if ($user->type !== UserTypeEnum::PROVIDER) {
+            throw new AuthorizationException('Apenas prestadores podem acessar este recurso.');
+        }
+
         $provider = Provider::with('profileMedia')->where('user_id', $user->id)->first();
 
         $headerBar = [

+ 94 - 0
app/Services/Pagarme/PagarmeTransferService.php

@@ -3,7 +3,10 @@
 namespace App\Services\Pagarme;
 
 use App\Data\Pagarme\Request\PagarmeTransferRequestData;
+use App\Models\Provider;
+use App\Models\ProviderWithdrawal;
 use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
+use Carbon\Carbon;
 
 class PagarmeTransferService
 {
@@ -11,6 +14,14 @@ class PagarmeTransferService
 
     public function createTransfer(int $amountInCents, string $recipientId, string $idempotencyKey): array
     {
+        if ($this->shouldMockTransferRequest()) {
+            return $this->mockTransferResponse(
+                amountInCents: $amountInCents,
+                recipientId: $recipientId,
+                idempotencyKey: $idempotencyKey,
+            );
+        }
+
         return $this->pagarmeRequest(
             method: 'POST',
             path: '/transfers',
@@ -25,6 +36,10 @@ class PagarmeTransferService
 
     public function getTransfer(string $transferId): array
     {
+        if ($this->shouldMockTransferRequest()) {
+            return $this->mockTransferLookupResponse($transferId);
+        }
+
         return $this->pagarmeRequest(
             method: 'GET',
             path: "/transfers/{$transferId}",
@@ -33,4 +48,83 @@ class PagarmeTransferService
             errorMessage: 'Erro ao consultar transferencia no Pagar.me.',
         );
     }
+
+    //
+
+    private function shouldMockTransferRequest(): bool
+    {
+        return app()->environment('local', 'development');
+    }
+
+    private function mockTransferResponse(int $amountInCents, string $recipientId, string $idempotencyKey): array
+    {
+        $provider = Provider::query()
+            ->where('recipient_id', $recipientId)
+            ->first();
+
+        $createdAt = Carbon::now();
+
+        return [
+            'id'                     => $this->mockTransferId($idempotencyKey),
+            'amount'                 => $amountInCents,
+            'type'                   => 'credito_em_conta',
+            'status'                 => 'pending_transfer',
+            'fee'                    => 0,
+            'funding_date'           => null,
+            'funding_estimated_date' => $createdAt->copy()->addWeekday()->toISOString(),
+            'transaction_id'         => null,
+            'bank_account'           => $provider?->recipient_default_bank_account,
+            'date_created'           => $createdAt->toISOString(),
+            'created_at'             => $createdAt->toISOString(),
+
+            'metadata' => [
+                'mocked'          => true,
+                'environment'     => app()->environment(),
+                'recipient_id'    => $recipientId,
+                'idempotency_key' => $idempotencyKey,
+                'provider_id'     => $provider?->id,
+            ],
+
+            'bank_response' => null,
+        ];
+    }
+
+    private function mockTransferLookupResponse(string $transferId): array
+    {
+        $withdrawal = ProviderWithdrawal::query()
+            ->where('transfer_id', $transferId)
+            ->first();
+
+        if ($withdrawal?->gateway_payload) {
+            return $withdrawal->gateway_payload;
+        }
+
+        $createdAt = Carbon::now();
+
+        return [
+            'id'                     => $transferId,
+            'amount'                 => $withdrawal ? (int) round((float) $withdrawal->gross_amount * 100) : 0,
+            'type'                   => $withdrawal?->type ?? 'credito_em_conta',
+            'status'                 => $withdrawal?->status?->value ?? 'pending_transfer',
+            'fee'                    => $withdrawal ? (int) round((float) $withdrawal->gateway_fee_amount * 100) : 0,
+            'funding_date'           => $withdrawal?->completed_at?->toISOString(),
+            'funding_estimated_date' => $createdAt->copy()->addWeekday()->toISOString(),
+            'transaction_id'         => null,
+            'bank_account'           => $withdrawal?->bank_account,
+            'date_created'           => $withdrawal?->created_at?->toISOString() ?? $createdAt->toISOString(),
+            'created_at'             => $withdrawal?->created_at?->toISOString() ?? $createdAt->toISOString(),
+
+            'metadata' => $withdrawal?->metadata ?? [
+                'mocked'      => true,
+                'environment' => app()->environment(),
+            ],
+
+            'bank_response' => $withdrawal?->bank_response,
+        ];
+    }
+
+    private function mockTransferId(string $idempotencyKey): string
+    {
+        return (string) abs(crc32($idempotencyKey));
+    }
 }

+ 4 - 1
app/Services/PaymentService.php

@@ -24,13 +24,16 @@ class PaymentService
     public function getAll(): Collection
     {
         return Payment::query()
+            ->with(['client.user', 'provider.user'])
             ->orderBy('created_at', 'desc')
             ->get();
     }
 
     public function findById(int $id): ?Payment
     {
-        return Payment::find($id);
+        return Payment::query()
+            ->with(['client.user', 'provider.user'])
+            ->find($id);
     }
 
     public function create(array $data): Payment

+ 4 - 1
app/Services/PaymentSplitService.php

@@ -10,13 +10,16 @@ class PaymentSplitService
     public function getAll(): Collection
     {
         return PaymentSplit::query()
+            ->with(['payment.schedule.client.user', 'provider.user', 'providerWithdrawal'])
             ->orderBy('created_at', 'desc')
             ->get();
     }
 
     public function findById(int $id): ?PaymentSplit
     {
-        return PaymentSplit::find($id);
+        return PaymentSplit::query()
+            ->with(['payment.schedule.client.user', 'provider.user', 'providerWithdrawal'])
+            ->find($id);
     }
 
     public function create(array $data): PaymentSplit

+ 8 - 0
app/Services/ProviderWithdrawalService.php

@@ -154,6 +154,14 @@ class ProviderWithdrawalService
             ->get();
     }
 
+    public function getAllWithdrawals(): Collection
+    {
+        return ProviderWithdrawal::query()
+            ->with(['provider.user', 'paymentSplits'])
+            ->orderBy('created_at', 'desc')
+            ->get();
+    }
+
     public function getWithdrawal(int $id, Provider $provider): ProviderWithdrawal
     {
         return ProviderWithdrawal::query()

+ 13 - 0
database/seeders/PermissionSeeder.php

@@ -35,6 +35,19 @@ class PermissionSeeder extends Seeder
                 'bits'        => 511,
                 'children'    => [],
             ],
+            [
+                'scope'       => 'payment',
+                'description' => 'Pagamentos',
+                'bits'        => 257,
+                'children'    => [
+                    [
+                        'scope'       => 'payment-split',
+                        'description' => 'Splits de Pagamento',
+                        'bits'        => 1,
+                        'children'    => [],
+                    ],
+                ],
+            ],
             [
                 'scope'       => 'config',
                 'description' => 'Configurações',

+ 2 - 0
database/seeders/UserTypePermissionSeeder.php

@@ -29,6 +29,8 @@ class UserTypePermissionSeeder extends Seeder
                 case UserTypeEnum::USER:
                     $userPermissions = [
                         ['scope' => 'dashboard', 'bits' => 1],
+                        ['scope' => 'payment', 'bits' => 257],
+                        ['scope' => 'payment-split', 'bits' => 1],
                         ['scope' => 'config.user', 'bits' => 5],
                         ['scope' => 'config.address', 'bits' => 271],
                         ['scope' => 'config.city', 'bits' => 1],

+ 1 - 0
routes/authRoutes/provider.php

@@ -8,6 +8,7 @@ Route::get('/provider/pending',            [ProviderController::class, 'pending'
 Route::patch('/provider/{id}/approve',            [ProviderController::class, 'approve'])->middleware('permission:config.provider,edit');
 Route::patch('/provider/{id}/reject',             [ProviderController::class, 'reject'])->middleware('permission:config.provider,edit');
 Route::get('/provider/payment-splits',            [ProviderWithdrawalController::class, 'splits'])->middleware('permission:config.provider,view');
+Route::get('/provider-withdrawals',               [ProviderWithdrawalController::class, 'all'])->middleware('permission:payment,view');
 Route::get('/provider/withdrawals/balance',       [ProviderWithdrawalController::class, 'balance'])->middleware('permission:config.provider,view');
 Route::get('/provider/withdrawals',               [ProviderWithdrawalController::class, 'index'])->middleware('permission:config.provider,view');
 Route::post('/provider/withdrawals',              [ProviderWithdrawalController::class, 'store'])->middleware('permission:config.provider,edit');