Refactor self-serve wash flow to decouple visible question logic, improve condition evaluation, and handle nullable fields in the OpenAPI spec.
This commit is contained in:
@@ -11816,9 +11816,11 @@ components:
|
||||
type: string
|
||||
answer:
|
||||
type: boolean
|
||||
nullable: true
|
||||
answered_at:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
|
||||
SelfserveWashTaskSnapshot:
|
||||
type: object
|
||||
|
||||
@@ -167,14 +167,8 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
||||
}
|
||||
}
|
||||
|
||||
$answers = array_map(function (array $row): array {
|
||||
return [
|
||||
'question_id' => (int)$row['question_id'],
|
||||
'question' => (string)$row['question_text'],
|
||||
'answer' => (bool)$row['answer_value'],
|
||||
'answered_at' => (string)$row['answered_at'],
|
||||
];
|
||||
}, (new selfserve_wash_session_answers_o())->listBySession($sessionId));
|
||||
$answerRows = (new selfserve_wash_session_answers_o())->listBySession($sessionId);
|
||||
$answers = $this->buildSessionQuestions($session, $answerRows);
|
||||
|
||||
$tasks = array_map(function (array $row): array {
|
||||
return [
|
||||
@@ -255,15 +249,17 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
||||
$conditions = $this->loadConditions($departmentId, $laneId, $vehicleTypeId, $machineTypeId);
|
||||
$rules = $this->loadConditionRules($conditions);
|
||||
$answers = (new department_selfserve_vehicle_conditions_o())->getAnswerMapForVehicle($departmentId, $laneId, $normalizedReg);
|
||||
$conditionResults = $this->conditionEvaluator->evaluate($conditions, $rules, $answers);
|
||||
$visibilityConditionResults = $this->conditionEvaluator->evaluate($conditions, $rules, $answers);
|
||||
|
||||
$visibleQuestions = [];
|
||||
$visibleQuestionIds = [];
|
||||
foreach ($questions as $question) {
|
||||
$gateId = $this->nullableInt($question['condition_id'] ?? null);
|
||||
if ($gateId !== null && (($conditionResults[$gateId] ?? false) !== true)) {
|
||||
if ($gateId !== null && (($visibilityConditionResults[$gateId] ?? false) !== true)) {
|
||||
continue;
|
||||
}
|
||||
$questionId = (int)$question['id'];
|
||||
$visibleQuestionIds[] = $questionId;
|
||||
$visibleQuestions[] = [
|
||||
'id' => $questionId,
|
||||
'question' => (string)$question['question'],
|
||||
@@ -275,12 +271,14 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
||||
}
|
||||
|
||||
usort($visibleQuestions, static fn(array $a, array $b): int => $a['order_priority'] <=> $b['order_priority']);
|
||||
$visibleAnswers = $this->filterAnswersToVisibleQuestions($answers, $visibleQuestionIds);
|
||||
$serviceConditionResults = $this->conditionEvaluator->evaluate($conditions, $rules, $visibleAnswers);
|
||||
|
||||
$tasks = $this->loadTasks($departmentId, $laneId, $vehicleTypeId, $machineTypeId);
|
||||
$activeTasks = [];
|
||||
foreach ($tasks as $task) {
|
||||
$gateId = $this->nullableInt($task['condition_id'] ?? null);
|
||||
if (!$this->conditionEvaluator->taskGateSatisfied($gateId, $conditionResults, $answers)) {
|
||||
if (!$this->conditionEvaluator->taskGateSatisfied($gateId, $serviceConditionResults, $visibleAnswers)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -335,7 +333,7 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
||||
'vehicle_type_id' => $vehicleTypeId,
|
||||
'answers' => $answers,
|
||||
'questions' => $visibleQuestions,
|
||||
'conditions' => $conditionResults,
|
||||
'conditions' => $serviceConditionResults,
|
||||
'tasks' => $activeTasks,
|
||||
'allowed_services' => $allowedServices,
|
||||
'machine_available' => $machineAvailable,
|
||||
@@ -515,10 +513,133 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
||||
'machine_available' => (bool)$snapshot['machine_available'],
|
||||
'all_visible_questions_answered' => (bool)$snapshot['all_visible_questions_answered'],
|
||||
'visible_question_ids' => array_map(static fn(array $question): int => (int)$question['id'], $snapshot['questions']),
|
||||
'visible_questions' => array_map(static fn(array $question): array => [
|
||||
'id' => (int)$question['id'],
|
||||
'question' => (string)$question['question'],
|
||||
'order_priority' => (int)($question['order_priority'] ?? 0),
|
||||
], $snapshot['questions']),
|
||||
'task_ids' => array_map(static fn(array $task): int => (int)$task['id'], $snapshot['tasks']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int,array<string,mixed>> $answerRows
|
||||
* @return array<int,array<string,mixed>>
|
||||
*/
|
||||
protected function buildSessionQuestions(selfserve_wash_sessions_o $session, array $answerRows): array
|
||||
{
|
||||
$answersByQuestionId = [];
|
||||
foreach ($answerRows as $row) {
|
||||
$answersByQuestionId[(int)$row['question_id']] = $row;
|
||||
}
|
||||
|
||||
$metadata = $session->metadata_json->value();
|
||||
$metadata = is_array($metadata) ? $metadata : [];
|
||||
$visibleQuestions = $this->resolveVisibleQuestionsFromMetadata(
|
||||
$metadata,
|
||||
(int)$session->department_id->value(),
|
||||
(int)$session->lane_id->value(),
|
||||
$session->vehicle_type_id->value() === null ? null : (int)$session->vehicle_type_id->value(),
|
||||
);
|
||||
|
||||
if ($visibleQuestions === []) {
|
||||
return array_map(static function (array $row): array {
|
||||
return [
|
||||
'question_id' => (int)$row['question_id'],
|
||||
'question' => (string)$row['question_text'],
|
||||
'answer' => (bool)$row['answer_value'],
|
||||
'answered_at' => (string)$row['answered_at'],
|
||||
];
|
||||
}, $answerRows);
|
||||
}
|
||||
|
||||
$questions = [];
|
||||
foreach ($visibleQuestions as $visibleQuestion) {
|
||||
$questionId = (int)$visibleQuestion['id'];
|
||||
if ($questionId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$answerRow = $answersByQuestionId[$questionId] ?? null;
|
||||
$questions[] = [
|
||||
'question_id' => $questionId,
|
||||
'question' => $answerRow === null ? (string)$visibleQuestion['question'] : (string)$answerRow['question_text'],
|
||||
'answer' => $answerRow === null ? null : (bool)$answerRow['answer_value'],
|
||||
'answered_at' => $answerRow === null ? null : (string)$answerRow['answered_at'],
|
||||
];
|
||||
unset($answersByQuestionId[$questionId]);
|
||||
}
|
||||
|
||||
foreach ($answerRows as $row) {
|
||||
$questionId = (int)$row['question_id'];
|
||||
if (!array_key_exists($questionId, $answersByQuestionId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$questions[] = [
|
||||
'question_id' => $questionId,
|
||||
'question' => (string)$row['question_text'],
|
||||
'answer' => (bool)$row['answer_value'],
|
||||
'answered_at' => (string)$row['answered_at'],
|
||||
];
|
||||
unset($answersByQuestionId[$questionId]);
|
||||
}
|
||||
|
||||
return $questions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $metadata
|
||||
* @return array<int,array{id:int,question:string,order_priority:int}>
|
||||
*/
|
||||
protected function resolveVisibleQuestionsFromMetadata(array $metadata, int $departmentId, int $laneId, ?int $vehicleTypeId): array
|
||||
{
|
||||
$visibleQuestions = [];
|
||||
if (isset($metadata['visible_questions']) && is_array($metadata['visible_questions'])) {
|
||||
foreach ($metadata['visible_questions'] as $visibleQuestion) {
|
||||
if (!is_array($visibleQuestion)) {
|
||||
continue;
|
||||
}
|
||||
$questionId = (int)($visibleQuestion['id'] ?? 0);
|
||||
if ($questionId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$visibleQuestions[] = [
|
||||
'id' => $questionId,
|
||||
'question' => (string)($visibleQuestion['question'] ?? ''),
|
||||
'order_priority' => (int)($visibleQuestion['order_priority'] ?? 0),
|
||||
];
|
||||
}
|
||||
return $visibleQuestions;
|
||||
}
|
||||
|
||||
if (!isset($metadata['visible_question_ids']) || !is_array($metadata['visible_question_ids'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$questionById = [];
|
||||
foreach ($this->loadQuestions($departmentId, $laneId, $vehicleTypeId) as $question) {
|
||||
$questionById[(int)$question['id']] = [
|
||||
'question' => (string)($question['question'] ?? ''),
|
||||
'order_priority' => (int)($question['order_priority'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($metadata['visible_question_ids'] as $visibleQuestionId) {
|
||||
$questionId = (int)$visibleQuestionId;
|
||||
if ($questionId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$visibleQuestions[] = [
|
||||
'id' => $questionId,
|
||||
'question' => (string)($questionById[$questionId]['question'] ?? ''),
|
||||
'order_priority' => (int)($questionById[$questionId]['order_priority'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
return $visibleQuestions;
|
||||
}
|
||||
|
||||
protected function findVehicleByRegistration(string $reg): ?customer_vehicles_o
|
||||
{
|
||||
$vehicle = (new customer_vehicles_o())->selectByPlate($reg);
|
||||
@@ -560,6 +681,24 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
||||
return (int)$value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int,bool|null> $answers
|
||||
* @param array<int,int> $visibleQuestionIds
|
||||
* @return array<int,bool|null>
|
||||
*/
|
||||
protected function filterAnswersToVisibleQuestions(array $answers, array $visibleQuestionIds): array
|
||||
{
|
||||
$filtered = [];
|
||||
foreach ($visibleQuestionIds as $questionId) {
|
||||
$questionId = (int)$questionId;
|
||||
if ($questionId <= 0 || !array_key_exists($questionId, $answers)) {
|
||||
continue;
|
||||
}
|
||||
$filtered[$questionId] = $answers[$questionId];
|
||||
}
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
protected function normalizeJsonValue(mixed $value): mixed
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
|
||||
Reference in New Issue
Block a user