Skip to main content

Request-Flow

App\Services\Grenke\RequestFlowService

Der Orchestrator-Service. Verkettet bis zu 8 Actions zu einem Geschäfts-Workflow:

Create  →  optional Patch  →  Poll bis ReadyToSign  →  E-Signature ODER Paper-Contract  →  optional Vertrag holen

Endpunkt

POST /api/v1/grenke/grenke/request-flow

Eine Validation-Klasse: App\Http\Requests\GrenkeRequestFlowRequest (die größte FormRequest-Klasse im Projekt).

Flow-Diagramm

Zwei Modi

ModusTriggerZweck
e_signaturecancel_e_signature: falseStandard-Flow mit Online-Unterschrift
cancel_e_signaturecancel_e_signature: trueE-Signature wird abgebrochen, Wechsel zu Papiervertrag

Vollständiges Request-Beispiel

curl -X POST https://api.bluesafety.dev/api/v1/grenke/grenke/request-flow \
-H 'Authorization: Bearer 1|...' \
-H 'Content-Type: application/json' \
-d '{
"request_payload": {
"FinancingAmount": 33877.56,
"Period": 84,
"PaymentFrequency": "Monthly",
"PaymentMethod": "DirectDebit",
"Currency": "EUR",
"ResidualValue": 0,
"ProductType": "ClassicLease",
"HasRepurchase": true,
"Lessee": {
"CompanyName": "Dr. Bettina Brem & Katrin Schimmelpfennig",
"ExternalId": "K562983",
"Email": "info@example.com",
"LegalFormId": 0,
"Addresses": [
{ "Line1": "Truderinger Str. 330", "PostCode": "81825", "City": "München", "Country": "DE", "Type": "main" }
],
"Telephones": [
{ "Number": "+49 89 890566800", "Type": "Phone" },
{ "Number": "+49 89 890566808", "Type": "Fax" }
]
},
"FinancingObjects": [
{ "Quantity": 2, "ObjectTypeId": 13, "Name": "Human Medical Equipment",
"Manufacturer": "BLUE SAFETY", "Details": "SAFEWATER 4.2", "NetPricePerObject": 16938.78 }
]
},
"e_signature_payload": {
"SignerName": "Bettina Brem",
"SignerEmail": "bettina.brem@example.com"
},
"patch_request_payload": { "PaymentMethod": "Invoice" },
"cancel_e_signature": false,
"fetch_contract_document_base64": true,
"fetch_contract_document_download_link": false,
"max_attempts": 10,
"sleep_milliseconds": 1000
}'

Response-Shape (Modus e_signature)

{
"success": true,
"data": {
"success": true,
"mode": "e_signature",
"financingId": "F-1234567",
"request": { ... RequestResponseData::toArray() ... },
"patchedRequest": null,
"patchedLessee": null,
"readyRequest": { ... RequestResponseData::toArray() ... },
"configuration": { ... ESignatureConfigurationData::toArray() ... },
"eSignature": { ... },
"contractDocumentBase64": { "Content": "JVBERi0..." },
"contractDocumentDownloadLink": null
}
}

Programmatisch nutzen

Der Service ist auch direkt aus eigenen Services / Jobs heraus aufrufbar:

use App\Services\Grenke\RequestFlowService;

$result = $this->grenkeRequestFlowService->execute(
requestPayload: RequestPayloadData::fromArray($payload),
eSignaturePayload: ESignaturePayloadData::fromArray([
'SignerName' => 'Bettina Brem',
'SignerEmail' => 'bettina.brem@example.com',
]),
fetchContractDocumentBase64: true,
maxAttempts: 15,
sleepMilliseconds: 1500,
);

Polling — maxAttempts & sleepMilliseconds

Wenn der State nach dem Create nicht direkt ReadyToSign ist, pollt WaitForGrenkeReadyToSignAction bis zu maxAttempts Mal mit sleepMilliseconds Pause dazwischen.

ParameterDefaultEmpfehlung Production
max_attempts101520
sleep_milliseconds100015002000

Achtung: in einem HTTP-Request kann der Endpoint also bis zu max_attempts × sleep blockieren. Konfiguriere die PHP max_execution_time und Web-Server-Timeouts entsprechend (oder packe den Flow in einen Job).

State-Branching während des Pollings

Wenn der State während des Pollings auf …

  • ReadyToSign → return → Flow geht weiter zu E-Signature
  • MissingInfo → triggert MissingInfo-Mailflow → Exception
  • Cancelled / Declined → Exception (abortsProcess())
  • RunningContract / ContractPrinted → Exception (Flow ist schon vorbei)

Error-Handling im Controller

try {
$result = $this->grenkeRequestFlowService->execute(/* ... */);
return response()->json(['success' => true, 'data' => $result]);
} catch (Throwable $e) {
\Log::error('GrenkeRequestFlowController store failed', ['message' => $e->getMessage()]);
return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
}