gross_amount; $items = $this->buildOrderItems($schedule, $grossAmount); $customer = $this->buildCustomer($schedule, $options); $split = $this->buildSplit($payment, $options); $pixOptions = config('services.pagarme.pix_disable_split') ? [] : ['split' => $split]; $orderOptions = array_merge(['split' => $split], $pixOptions); if ($paymentMethod === 'credit_card') { $creditCard = new OrderCreditCardData( cardId: $cardId, installments: 1, statementDescriptor: Str::limit((string) config('app.name', 'SOFTPAR'), 13, ''), operationType: 'auth_and_capture', ); return $this->createOrderWithCreditCard( payment: $payment, items: $items, customer: $customer, creditCard: $creditCard, options: $orderOptions, ); } $pixData = new OrderPixData( expiresIn: 1800, additionalInformation: [ new OrderPixAdditionalInformationData( name: 'Agendamento', value: (string) $schedule->id, ), ], ); return $this->createOrderWithPix( payment: $payment, items: $items, customer: $customer, pix: $pixData, options: $pixOptions, ); } public function createOrderWithCreditCard( Payment $payment, array $items, CustomerRequestData $customer, OrderCreditCardData $creditCard, array $options = [] ): array { return $this->createOrder( payment: $payment, items: $items, customer: $customer, paymentMethod: OrderRequestData::creditCardPaymentMethod( creditCard: $creditCard, split: is_array($options['split'] ?? null) ? $options['split'] : null, ), options: $options, ); } public function createOrderWithPix( Payment $payment, array $items, CustomerRequestData $customer, OrderPixData $pix, array $options = [] ): array { return $this->createOrder( payment: $payment, items: $items, customer: $customer, paymentMethod: OrderRequestData::pixPaymentMethod( pix: $pix, split: is_array($options['split'] ?? null) ? $options['split'] : null, ), options: $options, ); } public function createOrder( Payment $payment, array $items, CustomerRequestData $customer, OrderPaymentData $paymentMethod, array $options = [] ): array { $metadata = array_merge([ 'payment_id' => (string) $payment->id, 'schedule_id' => (string) $payment->schedule_id, 'client_id' => (string) $payment->client_id, 'provider_id' => (string) $payment->provider_id, ], $options['metadata'] ?? []); $requestData = new OrderRequestData( code: $this->ensurePaymentCode($payment), items: $items, payments: [$paymentMethod], metadata: $metadata, customer: $customer, customerId: $options['customer_id'] ?? null, closed: $options['closed'] ?? true, channel: $options['channel'] ?? null, ); $order = OrderResponseData::fromArray($this->pagarmeRequest( method: 'POST', path: '/orders', payload: $requestData, idempotencyKey: $this->idempotencyKey($payment), errorMessage: 'Erro ao criar pedido de pagamento no Pagar.me.', )); $order->requireId(); return $order->toArray(); } // public function applyGatewayResponseToPayment(Payment $payment, array $orderResponse): Payment { $order = OrderResponseData::fromArray($orderResponse); $newStatus = $order->paymentStatus(); $failureCode = null; $failureMessage = null; if ($newStatus === PaymentStatusEnum::FAILED) { $failureCode = $order->failureCode(); $failureMessage = $order->failureMessage(); } $payment->forceFill([ 'gateway_provider' => 'pagarme', 'gateway_entity_reference' => $order->gatewayEntityReference(), 'gateway_entity_label' => $order->gatewayEntityLabel(), 'gateway_operation_reference' => $order->gatewayOperationReference(), 'gateway_operation_label' => $order->gatewayOperationLabel(), 'status' => $newStatus, 'paid_at' => $order->paidAt(), 'authorized_at' => $order->authorizedAt(), 'gateway_payload' => $orderResponse, 'failure_code' => $failureCode, 'failure_message' => $failureMessage, ])->save(); $splitStatus = match ($newStatus) { PaymentStatusEnum::PAID => PaymentSplitStatusEnum::TRANSFERRED, PaymentStatusEnum::FAILED => PaymentSplitStatusEnum::FAILED, PaymentStatusEnum::CANCELLED => PaymentSplitStatusEnum::CANCELLED, PaymentStatusEnum::AUTHORIZED => PaymentSplitStatusEnum::PROCESSING, default => PaymentSplitStatusEnum::PENDING, }; PaymentSplit::query() ->where('payment_id', $payment->id) ->update(['status' => $splitStatus]); return $payment->fresh(); } // public function ensureCustomerPhone(Schedule $schedule, array $options): void { $phone = $this->buildPhonePayload($schedule->client?->user?->phone) ?: $this->buildPhonePayload($options['phone'] ?? null); if (! $phone) { throw new \InvalidArgumentException( 'Voce precisa cadastrar um numero de celular valido no seu perfil para concluir o pagamento.' ); } } // private function buildOrderItems(Schedule $schedule, float $grossAmount): array { $description = $schedule->customSchedule?->serviceType?->description ?? "Servico {$schedule->id}"; return [new OrderItemData( code: "schedule-{$schedule->id}", amount: OrderRequestData::amountInCents($grossAmount), quantity: 1, description: $description, )]; } private function buildCustomer(Schedule $schedule, array $options = []): CustomerRequestData { $client = $schedule->client; $user = $client->user()->first(['id', 'name', 'email', 'phone']); $address = Address::with(['city.state', 'state'])->find($schedule->address_id); foreach ([ 'nome' => $user?->name, 'email' => $user?->email, 'documento' => $client->document, ] as $field => $value) { if ($value === null || $value === '') { throw new \InvalidArgumentException("Cliente precisa ter {$field} para criar pedido no Pagar.me."); } } if (! $address) { throw new \InvalidArgumentException('Endereco do agendamento nao encontrado para criar pedido no Pagar.me.'); } $document = $this->digits($client->document); $phone = $this->buildPhonePayload($user->phone) ?: $this->buildPhonePayload($options['phone'] ?? null); $state = $address->state?->code ?? $address->city?->state?->code; $city = $address->city?->name; $zipCode = $this->digits($address->zip_code); $line1 = implode(', ', array_filter([ $address->number ?: 'S/N', $address->address, $address->district, ])); foreach ([ 'documento' => $document, 'estado' => $state, 'cidade' => $city, 'cep' => $zipCode, 'endereco' => $line1, 'telefone' => $phone, ] as $field => $value) { if ($value === null || $value === '' || $value === []) { throw new \InvalidArgumentException("Cliente precisa ter {$field} valido para criar pedido no Pagar.me."); } } $customerAddress = new CustomerAddressRequestData( line1: $line1, line2: $address->complement ?: $address->instructions, zipCode: $zipCode, city: $city, state: $state, country: 'BR', ); $customerPhones = null; if ($phone) { $customerPhones = new CustomerPhonesRequestData( mobilePhone: new CustomerPhoneData( countryCode: $phone['country_code'], areaCode: $phone['area_code'], number: $phone['number'], ), ); } return new CustomerRequestData( name: $user->name, email: $user->email, document: $document, type: strlen($document) === 14 ? 'company' : 'individual', documentType: strlen($document) === 14 ? 'CNPJ' : 'CPF', code: "client-{$client->id}", address: $customerAddress, phones: $customerPhones, ); } private function buildPhonePayload(?string $phone): ?array { $digits = $this->digits($phone); if (strlen($digits) < 10) { return null; } if (str_starts_with($digits, '55')) { $digits = substr($digits, 2); } return [ 'country_code' => '55', 'area_code' => substr($digits, 0, 2), 'number' => substr($digits, 2), ]; } private function buildSplit(Payment $payment, array $options): array { $transfers = PaymentSplit::query() ->where('payment_id', $payment->id) ->get(); $split = OrderRequestData::splitFromTransfers($transfers); $platformFee = (float) ($payment->platform_fee_amount ?? 0); if ($platformFee > 0) { $platformRecipientId = config('services.pagarme.platform_recipient_id'); $split[] = new OrderSplitData( amount: OrderRequestData::amountInCents($platformFee), recipientId: $platformRecipientId, type: 'flat', options: new OrderSplitOptionsData( chargeProcessingFee: true, chargeRemainderFee: true, liable: true, ), ); } return $split; } private function digits(?string $value): string { return preg_replace('/\D+/', '', (string) $value) ?? ''; } // private function idempotencyKey(Payment $payment): string { return "payment-{$payment->id}-schedule-{$payment->schedule_id}"; } private function ensurePaymentCode(Payment $payment): string { if (! empty($payment->gateway_code)) { return $payment->gateway_code; } $code = 'payment-'.(string) Str::uuid(); $payment->forceFill(['gateway_code' => $code])->save(); return $code; } }