startPayment method

Future<RpayMap> startPayment(
  1. RpayMap options
)

Starts the payment flow

Implementation

Future<RpayMap> startPayment(RpayMap options) async {
  // Completer to return future response
  RpayCompleter completer = RpayCompleter();

  /// Main return object
  RpayMap returnMap = <dynamic, dynamic>{};

  /// Data object
  RpayMap dataMap = <dynamic, dynamic>{};

  ///Ensure Razorpay SDK is loaded before proceeding
  bool isRazorpayLoaded = web.window.has('Razorpay');

  /// Optionally we can use this double conversion method also:
  /// bool isRazorpayLoaded = web.window.hasProperty('Razorpay'.toJS).toDart;

  if (isRazorpayLoaded == false) {
    completer.completeError("Razorpay SDK not loaded");
    return completer.future;
  }

  ///The dart function which will be called when payment is successful
  void handlerFn(jsinterop.JSObject jsResponse) {
    debugPrint('handlerFn called');

    ///Retriving Dart object from JS object
    Object? responseDartObject = jsResponse.dartify();

    ///If not null then parse it back as dart map
    if (responseDartObject != null) {
      Map response = Map.from(responseDartObject as LinkedHashMap);
      returnMap['type'] = ResponseCodes.CODE_PAYMENT_SUCCESS;
      dataMap['razorpay_payment_id'] = response['razorpay_payment_id'];
      dataMap['razorpay_order_id'] = response['razorpay_order_id'];
      dataMap['razorpay_signature'] = response['razorpay_signature'];
      returnMap['data'] = dataMap;
      completer.complete(returnMap);
    } else {
      debugPrint('response is not Map');
    }
  }

  ///The dart function which will be called when dialogue is closed by clicking close button
  void dismissFn() {
    debugPrint('dismissFn called');
    if (!completer.isCompleted) {
      returnMap['type'] = ResponseCodes.CODE_PAYMENT_ERROR;
      dataMap['code'] = ResponseCodes.PAYMENT_CANCELLED;
      dataMap['message'] = 'Payment processing cancelled by user';
      returnMap['data'] = dataMap;
      completer.complete(returnMap);
    }
  }

  /// Dart function to handle payment failure
  void onFailedFn(jsinterop.JSObject jsResponse) {
    debugPrint('onFailedFn called');
    Object? dartObject = jsResponse.dartify();
    if (dartObject != null) {
      Map response = Map.from(dartObject as LinkedHashMap);
      returnMap['type'] = ResponseCodes.CODE_PAYMENT_ERROR;
      dataMap['code'] = ResponseCodes.BASE_REQUEST_ERROR;
      dataMap['message'] = response['error']['description'];
      var metadataMap = <dynamic, dynamic>{};
      metadataMap['payment_id'] = response['error']['metadata']['payment_id'];
      dataMap['metadata'] = metadataMap;
      dataMap['source'] = response['error']['source'];
      dataMap['step'] = response['error']['step'];
      returnMap['data'] = dataMap;
      completer.complete(returnMap);
    } else {
      debugPrint('onFailedFn response is not Map');
    }
  }

  /// Converting dart map to js object
  /// [NOTE] handler functions should not be added before jsify,
  /// if we pass them like options['handler'] = handlerFn, then it will be
  /// a dart function and not a js function so in release mode the success, or failiure, or dismiss
  /// handlers will not be executed.
  /// Also if we call .toJS before jsify(), it's not running so we have to
  /// put all the handlers to the newly created [jsmapFromDart]
  jsinterop.JSAny? jsmapFromDart = options.jsify();

  /// Now manually insert the function handlers as JS object
  if (jsmapFromDart != null) {
    // Now manually insert the function handlers into the JS object
    (jsmapFromDart as jsinterop.JSObject).setProperty('handler'.toJS, handlerFn.toJS);
    (jsmapFromDart).setProperty('modal.ondismiss'.toJS, dismissFn.toJS);
    (jsmapFromDart).setProperty('payment.failed'.toJS, onFailedFn.toJS);
  }

  /// Retrieving the Object named [Razorpay] from the .js file we received from checkout API
  jsinterop.JSAny? razorpay = web.window.callMethod('Razorpay'.toJS, jsmapFromDart);

  if (razorpay is jsinterop.JSObject) {
    ///Assigning the onFailedFn to the payment.failed event
    razorpay.callMethod('on'.toJS, 'payment.failed'.toJS, onFailedFn.toJS);

    ///If no errors captured, then execute the ['open'] method
    razorpay.callMethod('open'.toJS);
  }
  return completer.future;
}