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
|
type: string
|
||||||
answer:
|
answer:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
nullable: true
|
||||||
answered_at:
|
answered_at:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
|
nullable: true
|
||||||
|
|
||||||
SelfserveWashTaskSnapshot:
|
SelfserveWashTaskSnapshot:
|
||||||
type: object
|
type: object
|
||||||
|
|||||||
@@ -167,14 +167,8 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$answers = array_map(function (array $row): array {
|
$answerRows = (new selfserve_wash_session_answers_o())->listBySession($sessionId);
|
||||||
return [
|
$answers = $this->buildSessionQuestions($session, $answerRows);
|
||||||
'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));
|
|
||||||
|
|
||||||
$tasks = array_map(function (array $row): array {
|
$tasks = array_map(function (array $row): array {
|
||||||
return [
|
return [
|
||||||
@@ -255,15 +249,17 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
|||||||
$conditions = $this->loadConditions($departmentId, $laneId, $vehicleTypeId, $machineTypeId);
|
$conditions = $this->loadConditions($departmentId, $laneId, $vehicleTypeId, $machineTypeId);
|
||||||
$rules = $this->loadConditionRules($conditions);
|
$rules = $this->loadConditionRules($conditions);
|
||||||
$answers = (new department_selfserve_vehicle_conditions_o())->getAnswerMapForVehicle($departmentId, $laneId, $normalizedReg);
|
$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 = [];
|
$visibleQuestions = [];
|
||||||
|
$visibleQuestionIds = [];
|
||||||
foreach ($questions as $question) {
|
foreach ($questions as $question) {
|
||||||
$gateId = $this->nullableInt($question['condition_id'] ?? null);
|
$gateId = $this->nullableInt($question['condition_id'] ?? null);
|
||||||
if ($gateId !== null && (($conditionResults[$gateId] ?? false) !== true)) {
|
if ($gateId !== null && (($visibilityConditionResults[$gateId] ?? false) !== true)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$questionId = (int)$question['id'];
|
$questionId = (int)$question['id'];
|
||||||
|
$visibleQuestionIds[] = $questionId;
|
||||||
$visibleQuestions[] = [
|
$visibleQuestions[] = [
|
||||||
'id' => $questionId,
|
'id' => $questionId,
|
||||||
'question' => (string)$question['question'],
|
'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']);
|
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);
|
$tasks = $this->loadTasks($departmentId, $laneId, $vehicleTypeId, $machineTypeId);
|
||||||
$activeTasks = [];
|
$activeTasks = [];
|
||||||
foreach ($tasks as $task) {
|
foreach ($tasks as $task) {
|
||||||
$gateId = $this->nullableInt($task['condition_id'] ?? null);
|
$gateId = $this->nullableInt($task['condition_id'] ?? null);
|
||||||
if (!$this->conditionEvaluator->taskGateSatisfied($gateId, $conditionResults, $answers)) {
|
if (!$this->conditionEvaluator->taskGateSatisfied($gateId, $serviceConditionResults, $visibleAnswers)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +333,7 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
|||||||
'vehicle_type_id' => $vehicleTypeId,
|
'vehicle_type_id' => $vehicleTypeId,
|
||||||
'answers' => $answers,
|
'answers' => $answers,
|
||||||
'questions' => $visibleQuestions,
|
'questions' => $visibleQuestions,
|
||||||
'conditions' => $conditionResults,
|
'conditions' => $serviceConditionResults,
|
||||||
'tasks' => $activeTasks,
|
'tasks' => $activeTasks,
|
||||||
'allowed_services' => $allowedServices,
|
'allowed_services' => $allowedServices,
|
||||||
'machine_available' => $machineAvailable,
|
'machine_available' => $machineAvailable,
|
||||||
@@ -515,10 +513,133 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
|||||||
'machine_available' => (bool)$snapshot['machine_available'],
|
'machine_available' => (bool)$snapshot['machine_available'],
|
||||||
'all_visible_questions_answered' => (bool)$snapshot['all_visible_questions_answered'],
|
'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_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']),
|
'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
|
protected function findVehicleByRegistration(string $reg): ?customer_vehicles_o
|
||||||
{
|
{
|
||||||
$vehicle = (new customer_vehicles_o())->selectByPlate($reg);
|
$vehicle = (new customer_vehicles_o())->selectByPlate($reg);
|
||||||
@@ -560,6 +681,24 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
|
|||||||
return (int)$value;
|
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
|
protected function normalizeJsonValue(mixed $value): mixed
|
||||||
{
|
{
|
||||||
if ($value === null || $value === '') {
|
if ($value === null || $value === '') {
|
||||||
|
|||||||
Reference in New Issue
Block a user