type 'Null' is not a subtype of type 'Future<String>' error showing in unit test

27 views Asked by At

Hi Folks I am facing an issue regarding unit test in flutter. I am using flutter version 3.10.5 and Mockito plugin. I am not able to identify why this below errors showing. please help me to find out. I have provided necessary files below.

test\unit_test\data_providers\add_patients\add_patient_data_provider_test.dart 14:7 RestClientMock.get test\unit_test\data_providers\add_patients\add_patient_data_provider_test.dart 38:23 main.

type 'Null' is not a subtype of type 'Future'

add_patient_data_provider_test.dart

//@dart=3.0
//ignore_for_file: prefer-match-file-name

import 'package:mockito/mockito.dart';
import 'package:namah/repos/rest_client/rest_client.dart';
import 'package:namah/utilities/constants/api_endpoint.dart';
import 'dart:convert';
import 'package:namah/utilities/constants/api_param_constants.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:retry/retry.dart';
import 'package:namah/data_providers/patients/patient_data_provider.dart';

class RestClientMock extends Mock implements RestClient {}

void main() {
  group("add patient api calls", () {
    test("fetch patient api call positive call", () async {
      /*Given*/
      String endPoint = ApiEndPoint.athmaUserPreferenceData;
      var statusCode = 200;
      String _userPreferenceAthmaUrlCodeValue = "UAA_001";
      String responseBody = jsonEncode({
        "hospital": {"code": "123"},
      });
      Map<String, dynamic> queryParams = {
        ApiParamConstants.athmaUrlCodeKeyParam:
            _userPreferenceAthmaUrlCodeValue,
        ApiParamConstants.athmaUrlContentKeyParam:
            ApiParamConstants.vitalSaveAthmaUrlContentValue,
      };

      var mockClient = RestClientMock();
      var patientDataProvider = PatientDataProvider(
        restClient: mockClient,
      );

      when(mockClient.get(
              endpoint: endPoint,
              queryParam: queryParams,
              isAthmaTokenRequired: true))
          .thenAnswer(
        (_) => Future<http.Response>.value(
          http.Response(
            responseBody,
            statusCode,
          ),
        ),
      );

      var result = await patientDataProvider?.getUserPreference();

      verify(
        mockClient?.get(
          endpoint: endPoint,
          queryParam: queryParams,
          isAthmaTokenRequired: true,
        ),
      ).called(1);
      expect(result, isA<String>());
    });
  });
}

rest_client.dart

    import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:http/http.dart' as http;
import 'package:namah/flavor_config.dart';
import 'package:namah/utilities/storage/encrypted_sharedpref_manager.dart';
import 'package:retry/retry.dart';

import '../../utilities/constants/app_constants.dart';
import '../../utilities/helper/network_call_manager.dart';
import '../crash_analytics/app_crashlytics.dart';

class RestClient {
  http.Client? _httpClient;
  RetryOptions? _retryOption;
  AppCrashlytics? _appCrashlytics;
  EncryptedSharedPrefManager? _appStorage;

  static final RestClient _instance = RestClient._internal();
  static const int _REQUEST_TIME_OUT_DURATION_IN_SECONDS = 30;
  final String _hcciCountryCode = "1";

  RestClient._internal();

  factory RestClient({
    required http.Client httpClient,
    required RetryOptions retryOption,
    AppCrashlytics? appCrashlytics,
    EncryptedSharedPrefManager? appStorage,
  }) {
    _instance._httpClient = httpClient;
    _instance._retryOption = retryOption;
    _instance._appCrashlytics = appCrashlytics;
    _instance._appStorage = appStorage;
    return _instance;
  }

  Future<dynamic> get({
    required String endpoint,
    Map<String, dynamic>? queryParam,
    bool isAthmaTokenRequired = false,
  }) async {
    try {
      var baseUrl = await getBaseUrl();
      var endPoint = await _getEndPoint(endpoint);
      var headers = await _getHeaderConfig(isAthmaTokenRequired);
      http.Response? response = await _retryOption?.retry(
        () => _httpClient
            ?.get(
              _getUri(
                queryParam,
                endPoint,
                baseUrl,
              ),
              headers: headers,
            )
            .timeout(Duration(seconds: _REQUEST_TIME_OUT_DURATION_IN_SECONDS)),
        retryIf: (e) => e is SocketException || e is TimeoutException,
      );
      if (response?.statusCode.isSuccessRequest != ResponseHandler.SUCCESSFUL) {
        _logApiException(error: response?.body, stackTrace: StackTrace.current);
      }
      return response;
    } on Exception catch (e, stack) {
      log("RestClient - Exception : ${e.toString()}");
      _logApiException(error: e.toString(), stackTrace: stack);
      rethrow;
    }
  }

  Future<dynamic> post({
    required String endpoint,
    dynamic body,
    Map<String, dynamic>? queryParam,
    bool isAthmaTokenRequired = false,
    bool isFileUploadRequest = false,
  }) async {
    try {
      var baseUrl = await getBaseUrl();
      var endPoint = await _getEndPoint(endpoint);
      var headers = await _getHeaderConfig(
        isAthmaTokenRequired,
        isFileUploadRequest: isFileUploadRequest,
      );
      http.Response? response = await _httpClient
          ?.post(
            _getUri(queryParam, endPoint, baseUrl),
            headers: headers,
            body: (body != null) ? jsonEncode(body) : '',
          )
          .timeout(Duration(seconds: _REQUEST_TIME_OUT_DURATION_IN_SECONDS));
      if (response?.statusCode.isSuccessRequest != ResponseHandler.SUCCESSFUL) {
        _logApiException(error: response?.body, stackTrace: StackTrace.current);
      }
      return response;
    } on Exception catch (e, stack) {
      log("RestClient - Exception : ${e.toString()}");
      _logApiException(error: e.toString(), stackTrace: stack);
      rethrow;
    }
  }

  Future<dynamic> put({
    required String endpoint,
    dynamic body,
    Map<String, String>? queryParam,
    bool isAthmaTokenRequired = false,
  }) async {
    try {
      var baseUrl = await getBaseUrl();
      var endPoint = await _getEndPoint(endpoint);
      var headers = await _getHeaderConfig(isAthmaTokenRequired);
      http.Response? response = await _httpClient
          ?.put(
            _getUri(queryParam, endPoint, baseUrl),
            headers: headers,
            body: (body != null) ? jsonEncode(body) : '',
          )
          .timeout(Duration(seconds: _REQUEST_TIME_OUT_DURATION_IN_SECONDS));
      if (response?.statusCode.isSuccessRequest != ResponseHandler.SUCCESSFUL) {
        _logApiException(error: response?.body, stackTrace: StackTrace.current);
      }
      return response;
    } on Exception catch (e, stack) {
      log("RestClient - Exception : ${e.toString()}");
      _logApiException(error: e.toString(), stackTrace: stack);
      rethrow;
    }
  }

  Future<dynamic> delete({
    required String endpoint,
    Map<String, String>? queryParam,
    bool isAthmaTokenRequired = false,
  }) async {
    try {
      var baseUrl = await getBaseUrl();
      var endPoint = await _getEndPoint(endpoint);
      var headers = await _getHeaderConfig(isAthmaTokenRequired);
      http.Response? response = await _retryOption?.retry(
        () => _httpClient
            ?.delete(_getUri(queryParam, endPoint, baseUrl), headers: headers)
            .timeout(Duration(seconds: _REQUEST_TIME_OUT_DURATION_IN_SECONDS)),
        retryIf: (e) => e is SocketException || e is TimeoutException,
      );
      if (response?.statusCode.isSuccessRequest != ResponseHandler.SUCCESSFUL) {
        _logApiException(error: response?.body, stackTrace: StackTrace.current);
      }
      return response;
    } on Exception catch (e, stack) {
      log("RestClient - Exception : ${e.toString()}");
      _logApiException(error: e.toString(), stackTrace: stack);
      rethrow;
    }
  }

  Future<String> getBaseUrl() async {
    var baseUrl = FlavorConfig.flavorValues.apiUrlPrefix;
    // if (FlavorConfig.appFlavor == Flavor.namahUat ||
    //     FlavorConfig.appFlavor == Flavor.namahProd) {
    //   String country = "0";
    //   try {
    //     country =
    //         await _appStorage?.retrieveEncryptedData(kSelectedCountry) ?? "";
    //   } catch (e) {
    //     log(e.toString());
    //   }
    //   if (country == _hcciCountryCode) {
    //     baseUrl = FlavorConfig.appFlavor == Flavor.namahUat
    //         ? NAMAH_HCCI_UAT_BASEURL
    //         : NAMAH_HCCI_PROD_BASEURL;
    //   }
    // }
    return baseUrl;
  }

  Future<Map<String, String>> _getHeaderConfig(
    bool isAthmaTokenRequired, {
    bool isFileUploadRequest = false,
  }) async {
    Map<String, String> headers = {};
    headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Connection': 'Keep-Alive',
      'Keep-Alive': 'timeout=10, max=1000',
    };

    String? token = await EncryptedSharedPrefManager.getInstance()
        ?.retrieveEncryptedData(kIdToken);
    if (token != null && token.isNotEmpty) {
      headers.putIfAbsent("Authorization", () => 'Bearer $token');
    }

    if (isAthmaTokenRequired) {
      var athma_token = await EncryptedSharedPrefManager.getInstance()
          ?.retrieveEncryptedData(kAthmaToken);
      headers.putIfAbsent(
        "athmaToken",
        () => athma_token ?? "",
      );
    }
    if (isFileUploadRequest) {
      Map<String, String> headers = {};
      String? token = await EncryptedSharedPrefManager.getInstance()
          ?.retrieveEncryptedData(kIdToken);
      if (token != null && token.isNotEmpty) {
        headers.putIfAbsent("Authorization", () => 'Bearer $token');
        headers.putIfAbsent("cache-control", () => 'no-cache');
        headers.putIfAbsent("Content-Type", () => 'multipart/form-data');
      }
      return headers;
    }
    return headers;
  }

  Uri _getUri(
    Map<String, dynamic>? queryParam,
    String endpoint,
    String baseUrl,
  ) {
    Uri uri = Uri.https(
      baseUrl,
      endpoint,
      queryParam,
    );
    log('uri ' + uri.toString());
    return uri;
  }

  void _logApiException({String? error, StackTrace? stackTrace}) {
    _appCrashlytics?.recordNonFatalError(
      errorMsg: error ?? "",
      stack: stackTrace,
    );
  }

  Future<String> _getEndPoint(String endpoint) async {
    var sub_url = endpoint;
    if (FlavorConfig.appFlavor == Flavor.namahProd) {
      String country =
          await _appStorage?.retrieveEncryptedData(kSelectedCountry) ?? "";
      if (country == _hcciCountryCode) {
        sub_url = endpoint.replaceAll("/aadi/", "/");
      }
    }
    return sub_url;
  }

}

patient_data_provider.dart

// ignore_for_file: avoid-nested-conditional-expressions

import 'dart:convert';

import 'package:http/http.dart';
import 'package:namah/models/patient_model.dart';
import 'package:namah/models/sync_chat_message_model.dart';
import 'package:namah/models/tasks/task_model.dart';
import 'package:namah/utilities/constants/api_param_constants.dart';
import 'package:namah/utilities/constants/app_task_constants.dart';
import 'package:namah/utilities/helper/network_call_manager.dart';

import '../../models/chat_message_model.dart';
import '../../models/fetch_patient_list_request_model.dart';
import '../../models/patient_chat_messages_request_model.dart';
import '../../models/vulnerability_criteria_update_model.dart';
import '../../repos/rest_client/rest_client.dart';
import '../../utilities/constants/api_endpoint.dart';
import '../../utilities/constants/app_constants.dart';
import '../../utilities/constants/app_handover_constants.dart';
import '../../utilities/constants/app_size_constants.dart';

class PatientDataProvider {
  final RestClient? restClient;
  String _sizeParam0 = '0';
  String _sizeParam20 = '20';
  String _userPreferenceAthmaUrlCodeValue = "UAA_001";
  String _patientAndEncounterAthmaUrlCodeValue = "ADT_001";
  String _updateAthmaUrlCodeValue = "ADT_003";
  String _HTTP_PARAM = "httpMethod";

  PatientDataProvider({required this.restClient});

  Future<String> getUserPreference() async {
    Map<String, dynamic> queryParams = {
      ApiParamConstants.athmaUrlCodeKeyParam: _userPreferenceAthmaUrlCodeValue,
      ApiParamConstants.athmaUrlContentKeyParam:
          ApiParamConstants.vitalSaveAthmaUrlContentValue,
    };

    Response response = await restClient?.get(
      endpoint: ApiEndPoint.athmaUserPreferenceData,
      queryParam: queryParams,
      isAthmaTokenRequired: true,
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      return jsonDecode(response.body)['hospital'] != null
          ? (jsonDecode(response.body)['hospital']['code'].toString().isNotEmpty
              ? jsonDecode(response.body)['hospital']['code']
              : "")
          : "";
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<List<PatientModel>> fetchPatientsBySearchWithWard(
    String searchString,
    String loginId,
  ) async {
    Map<String, dynamic> queryParams = {
      ApiParamConstants.loginParam: loginId,
      ApiParamConstants.queryParam: _addPatientsWithWard(
        await getUserPreference(),
        searchString,
      ),
      ApiParamConstants.sizeParam: ApiParamConstants.sizeParam50,
      ApiParamConstants.pageParam: _sizeParam0,
    };

    Response response = await restClient?.get(
      endpoint: ApiEndPoint.addSelectedPatientsWithWard,
      queryParam: queryParams,
    );
    List<PatientModel> patientsList = [];
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      patientsList = (jsonDecode(response.body) as List)
          .map((i) => PatientModel.fromJson(i))
          .toList();
      return patientsList;
    } else if (response.statusCode == kErrorState) {
      throw FormatException();
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<Map?> searchToReceivePatient(String mrn) async {
    Map<String, String> queryParams = {
      ApiParamConstants.athmaUrlCodeKeyParam:
          _patientAndEncounterAthmaUrlCodeValue,
      ApiParamConstants.athmaUrlContentKeyParam:
          _receiveBillClearedPatientQuery(mrn),
    };
    Response response = await restClient?.get(
      endpoint: ApiEndPoint.athmaEndPoint,
      queryParam: queryParams,
      isAthmaTokenRequired: true,
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      return response.body.isEmpty
          ? null
          : response.body == "[]"
              ? null
              : json.decode(response.body)[0];
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<bool> receivePatientToWard(Map body) async {
    Map<String, String> queryParams = {
      ApiParamConstants.athmaUrlCodeKeyParam: _updateAthmaUrlCodeValue,
      ApiParamConstants.athmaUrlContentKeyParam:
          ApiParamConstants.vitalSaveAthmaUrlContentValue,
      _HTTP_PARAM: kHttpMethodPut,
    };
    Response response = await restClient?.put(
      endpoint: ApiEndPoint.saveEndPoint,
      body: body,
      queryParam: queryParams,
      isAthmaTokenRequired: true,
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      return true;
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<List<PatientModel>> fetchMyPatients(
    FetchPatientListRequestModel fetchPatientListRequestModel,
  ) async {
    Response response = await restClient?.post(
      endpoint: ApiEndPoint.fetchMyPatientsList,
      body: fetchPatientListRequestModel,
    );
    List<PatientModel> patientsList = [];
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      patientsList = (jsonDecode(response.body) as List)
          .map((i) => PatientModel.fromJson(i))
          .toList();
      return patientsList;
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<PatientModel?> updateAddSelectedPatients(
    String mrn,
    String login,
  ) async {
    Response response = await restClient?.get(
      endpoint: ApiEndPoint.updateSelectedPatients,
      queryParam: {
        ApiParamConstants.loginParam: login,
        ApiParamConstants.mrnParam: mrn,
      },
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      return response.body.isEmpty
          ? null
          : PatientModel.fromJson(json.decode(response.body));
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<List<PatientModel>?> updateAddSelectedPatientsToShiftIncharge(
    List<String> mrn,
    Map<String, dynamic> shiftInchargeInfo,
    Map<String, dynamic> staffNurseInfo,
  ) async {
    Map<String, dynamic> body = {
      ApiParamConstants.mrnListParam: mrn,
      ApiParamConstants.shiftInchargeParam: shiftInchargeInfo,
      ApiParamConstants.attendingNurseParam: staffNurseInfo,
    };
    Response response = await restClient?.post(
      endpoint: ApiEndPoint.addSelectedPatientsToShiftIncharge,
      body: body,
      queryParam: {
        "assignEveryOne": [staffNurseInfo.isEmpty ? "false" : "true"],
      },
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      return response.body.isEmpty
          ? []
          : jsonDecode(response.body)
              .map<PatientModel>((json) => PatientModel.fromJson(json))
              .toList();
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<SyncChatMessageModel> fetchNewlyAddedPatientsChat(
    PatientChatMessagesRequestModel chatMessagesRequestModel,
  ) async {
    Response response = await restClient?.get(
      endpoint: ApiEndPoint.fetchNewlyAddedPatientMessages +
          "${chatMessagesRequestModel.loginId}" +
          ApiParamConstants.slashParam +
          "${chatMessagesRequestModel.mrn}",
      queryParam: {
        ApiParamConstants.pageParam: chatMessagesRequestModel.page,
        ApiParamConstants.sizeParam: ApiParamConstants.sizeParam1000,
        ApiParamConstants.loadCompleteHistoryParam:
            chatMessagesRequestModel.loadCompleteHistory,
      },
    );
    SyncChatMessageModel syncChatMessage = SyncChatMessageModel();
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      syncChatMessage.chatMessages = (jsonDecode(response.body) as List)
          .map((i) => ChatMessageModel.fromJson(i))
          .toList();
      syncChatMessage.xTotalCount =
          int.parse(response.headers['x-total-count'] ?? "0");

      return syncChatMessage;
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<ChatHistoryModel?> fetchOfflineChatHistory(
    FetchPatientListRequestModel offlineChatRequestModel,
    int page,
  ) async {
    Response response = await restClient?.post(
      endpoint: ApiEndPoint.fetchOfflineChatMessages,
      queryParam: {
        ApiParamConstants.pageParam: page.toString(),
        ApiParamConstants.sizeParam: ApiParamConstants.sizeParam1000,
      },
      body: offlineChatRequestModel,
    );
    List<ChatMessageModel> chatMessages = [];
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      chatMessages = (jsonDecode(response.body) as List)
          .map((i) => ChatMessageModel.fromJson(i))
          .toList();
      return ChatHistoryModel(
        chatModel: chatMessages,
        isPaginationAvailable:
            int.parse(response.headers['x-total-count'] ?? "0") > 0
                ? true
                : false,
      );
    } else if (response.statusCode.status == ResponseHandler.NODATA) {
      return null;
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<List<TaskModel>> checkTakeOverRequests(String loginId) async {
    Response response = await restClient?.get(
      endpoint: ApiEndPoint.checkTakeOverRequests,
      queryParam: {
        ApiParamConstants.pageParam: "${AppSizeConstants.length0}",
        ApiParamConstants.queryParam: _checkTakeoverRequestQuery(loginId),
        ApiParamConstants.sizeParam: ApiParamConstants.sizeParam100,
        ApiParamConstants.sortParamText: ApiParamConstants.sortIdDescParam,
      },
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      List<TaskModel> taskDetailsList = [];
      if (response.body.isEmpty) {
        return taskDetailsList;
      } else {
        taskDetailsList = jsonDecode(response.body)
            .map<TaskModel>((json) => TaskModel.fromJson(json))
            .toList();
        return taskDetailsList;
      }
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<PatientModel?> searchPatientByMRN(String mrn, String lognId) async {
    Response response = await restClient?.get(
      endpoint: ApiEndPoint.addSelectedPatientsWithWard,
      queryParam: {
        ApiParamConstants.pageParam: "${AppSizeConstants.length0}",
        ApiParamConstants.loginParam: lognId,
        ApiParamConstants.queryParam: _searchPatientByMRNQuery(mrn),
        ApiParamConstants.sizeParam: _sizeParam20,
      },
    );
    return response.statusCode.status == ResponseHandler.SUCCESSFUL
        ? response.body.isEmpty
            ? null
            : (jsonDecode(response.body) as List)
                .map((i) => PatientModel.fromJson(i))
                .toList()
                .first
        : null;
  }

  Future<List<TaskModel>> fetchTakeoverAssignedTasks(String ids) async {
    Response response = await restClient?.get(
      endpoint: ApiEndPoint.taskListEndPoint,
      queryParam: {
        ApiParamConstants.queryParam:
            _fetchTakeoverAssignedTasksRequestQuery(ids),
        ApiParamConstants.sizeParam: ApiParamConstants.sizeParam100,
        ApiParamConstants.sortParamText: ApiParamConstants.sortIdDescParam,
      },
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      List<TaskModel> taskDetailsList = [];
      taskDetailsList = jsonDecode(response.body)
          .map<TaskModel>((json) => TaskModel.fromJson(json))
          .toList();
      return taskDetailsList;
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<TaskModel?> handoverAcceptOrRejection(TaskModel? taskModel) async {
    Response response = await restClient?.post(
      endpoint: ApiEndPoint.handoverAcceptOrRejectionRequest,
      body: taskModel,
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      return response.body.isEmpty
          ? null
          : TaskModel.fromJson(json.decode(response.body));
    } else {
      throw ApiException(response.errorBody);
    }
  }

  Future<PatientModel?> updateVulnerabilityCriteriaList(
    VulnerabilityCriteriaUpdateModel model,
  ) async {
    Response response = await restClient?.post(
      endpoint: ApiEndPoint.updateVulnerabilityCriteria,
      body: model,
    );
    if (response.statusCode.status == ResponseHandler.SUCCESSFUL) {
      return response.body.isEmpty
          ? null
          : PatientModel.fromJson(json.decode(response.body));
    } else {
      throw ApiException(response.errorBody);
    }
  }

  /* ---------fetch Takeover requests Query Value----------*/
  String _checkTakeoverRequestQuery(String loginId) {
    return "active:true AND (taskStatus:INITIATED) AND (assignee.login:$loginId) AND taskDefinition.code:\"" +
        kHandoverDefinitionCode +
        "\"";
  }

  /* ---------fetch Takeover Tasks requests Query Value----------*/
  String _fetchTakeoverAssignedTasksRequestQuery(String ids) {
    return "active:true AND ($ids) AND  taskDefinition.code:\"" +
        kTaskDefinitionCode +
        "\"";
  }

  /*---------Add Patients using Ward (AthmaUrlQuery)----------*/

  String _addPatientsWithWard(
    String unitCode,
    String searchString,
  ) {
    return "(name:*$searchString* OR mrn:*$searchString* OR location:*$searchString*) AND unitCode:$unitCode AND active:true";
  }

  String _searchPatientByMRNQuery(String mrn) {
    return "(mrn:*$mrn*) AND active:true";
  }

  String _receiveBillClearedPatientQuery(String mrn) {
    return "?query=patientDetails.mrn:$mrn AND status:BILLING_CLEARED";
  }
}
0

There are 0 answers