Skip to main content

Grenke Controllers

app/Http/Controllers/Grenke/

Drei Controller bedienen die /api/v1/grenke-Routen. Sie bleiben dünn — nur Validation, DTO-Hydration, Action-Aufruf und Response.

ControllerDateiRouten
RequestControllerGrenke/RequestControllergesamtes Request-API (Step-by-Step)
RequestFlowControllerGrenke/RequestFlowControllerOrchestrator (One-Shot Flow)
CalculateControllerGrenke/CalculateControllerLease-Berechnungen

RequestController

Bedient den vollständigen Lifecycle eines Grenke-Requests.

Methoden

MethodeRouteAction(s)
createPOST /api/v1/grenkeCreateGrenkeRequestAction
showGET /api/v1/grenke/{financingId}GetGrenkeRequestAction
patchRequestPATCH /api/v1/grenke/{financingId}PatchGrenkeRequestAction
patchLesseePATCH /api/v1/grenke/{financingId}/lesseePatchGrenkeLesseeAction
waitForReadyToSignGET /api/v1/grenke/{financingId}/wait-ready-to-signWaitForGrenkeReadyToSignAction
getESignatureConfigurationGET /api/v1/grenke/{financingId}/e-signature/configurationGet+GetESignatureConfigurationAction
startESignaturePOST /api/v1/grenke/{financingId}/e-signatureGet+StartGrenkeESignatureAction
cancelESignaturePUT /api/v1/grenke/{financingId}/cancel-e-signatureCancelGrenkeESignatureAction
switchToPaperContractPUT /api/v1/grenke/{financingId}/switch-to-paper-contractSwitchGrenkeToPaperContractAction
getContractDocumentBase64GET /api/v1/grenke/{financingId}/contractdocument/base64Get+GetGrenkeContractDocumentAction
getContractDocumentDownloadLinkPOST /api/v1/grenke/{financingId}/contractdocument/linkGet+PostGrenkeContractDocumentAction

Beispiel — create

public function create(CreateGrenkeRequestRequest $request): JsonResponse
{
try {
$dto = RequestPayloadData::fromArray($request->validated());
$result = $this->createGrenkeRequestAction->execute($dto);

return response()->json([
'success' => true,
'data' => $result->toArray(),
'meta' => $this->grenkeRequestStateService->buildStateMeta($result),
]);
} catch (Throwable $e) {
return $this->errorResponse($e);
}
}

Beispiel — waitForReadyToSign (mit Mail-Context)

public function waitForReadyToSign(Request $request, string $financingId): JsonResponse
{
try {
$result = $this->waitForGrenkeReadyToSignAction->execute(
financingId: $financingId,
maxAttempts: (int) $request->input('max_attempts', 10),
sleepMilliseconds: (int) $request->input('sleep_milliseconds', 1000),
mailContext: [
'technician_appointment_date' => $request->input('technician_appointment_date'),
'technician_appointment_time' => $request->input('technician_appointment_time'),
],
);
return response()->json([
'success' => true,
'data' => $result->toArray(),
'meta' => $this->grenkeRequestStateService->buildStateMeta($result),
]);
} catch (Throwable $e) {
return $this->errorResponse($e);
}
}

mailContext wird bei Status MissingInfo an den MissingInfoMailFlowService gereicht — siehe Mailflow.

Beispiel — getContractDocumentBase64 mit optionalem Speichern

$savedFile = null;
if ($request->boolean('store_pdf', false)) {
$base64 = $this->grenkePdfService->extractBase64FromResponse($result);
$savedFile = $this->grenkePdfService->saveBase64Pdf(
base64Content: $base64,
directory: 'grenke/contracts',
filename: $financingId . '.pdf',
);
}

errorResponse(Throwable $e)

Zentralisiert. Loggt den Fehler und liefert einheitlichen 500-Body:

{ "success": false, "message": "<exception message>" }

RequestFlowController

Wraps den RequestFlowService für One-Shot-Aufrufe — der gesamte Flow (Create → optional Patch → polling → e-signature oder cancel/paper) in einem einzigen Endpoint.

Routen

RouteMethodeZweck
POST /api/v1/grenke/grenke/request-flowstorekompletter Flow
GET /api/v1/grenke/grenke/request-flowindexHealth-Check
GET /api/v1/grenke/grenke/request-flow/test-flow/{financingId}testFlownur Vertrag-PDF in Storage ablegen

Request-Body (gekürzt)

{
"request_payload": { "FinancingAmount": 33877.56, "Period": 84, "Lessee": { ... }, "FinancingObjects": [ ... ] },
"e_signature_payload": { "SignerName": "Bettina Brem", "SignerEmail": "..." },
"patch_request_payload": { "PaymentMethod": "Invoice" },
"patch_lessee_payload": { "CompanyName": "..." },
"cancel_e_signature": false,
"fetch_contract_document_base64": true,
"fetch_contract_document_download_link": false,
"max_attempts": 10,
"sleep_milliseconds": 1000
}

Vollständiges Beispiel + Erklärung in Request-Flow.


CalculateController

app/Http/Controllers/Grenke/CalculateController.php

Zwei Hilfs-Endpunkte für Lease-Berechnung:

MethodeRouteZweck
storePOST /api/v1/grenke/calculatecalls Grenke POST /calculate mit validiertem Body
purchaseGET /api/v1/grenke/calculate/{monthlyInstalment?}/{period?}inverse Berechnung: aus Monatsrate + Laufzeit → Kaufsumme

purchase — wie funktioniert das?

Grenke\Helper::getFactor($period) liefert pro Laufzeit (48/60/72/84 Monate) einen Faktor. Aus monatlicher Rate und Laufzeit ergibt sich der Finanzierungsbetrag:

$financingAmount = ($monthlyInstalment * 100) / Helper::getFactor($period);
// e.g. (299 * 100) / 1.47 = 20340.14 für 84 Monate

Default-Werte: monthlyInstalment = 299, period = 84.

GET /api/v1/grenke/calculate/299/84
{ "data": 20340.14, "monthlyInstalment": 299, "period": 84 }