tuna_sdk 0.1.4 copy "tuna_sdk: ^0.1.4" to clipboard
tuna_sdk: ^0.1.4 copied to clipboard

Tuna Gateway SDK.

example/lib/main.dart

// ignore_for_file: avoid_print
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:tuna_sdk/tuna_sdk.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:dio/dio.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tuna SDK Test App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Tuna SDK Test App'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final Dio _dio = Dio();

  late final ThreeDS _threeDS;
  late final Tuna _tuna;
  bool _showThreeDS = false;
  bool _dataLoaded = false;
  String _infoText = "Starting app";

  // //-------------// Edit this data //-------------//
  final String _env = "prod";
  final CustomerData _customer = CustomerData("4321", "john.doe@tuna.uy");
  final String _partnerUniqueId = _generateRandomString(10);
  final CardData _cardData = CardData(
      cardNumber: "4456530000001096",
      cardHolderName: "John Doe",
      expirationMonth: 1,
      expirationYear: 2027,
      cvv: "123");

  //Sensitive data
  final String _appToken = "";
  final String _account = "";
  //Sensitive data

  // //-------------// Edit this data //-------------//

  static String _generateRandomString(int i) =>
      String.fromCharCodes(List.generate(
          i,
          (_) =>
              'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
                  .codeUnitAt(Random().nextInt(62))));

  void callDialog(String message) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('3DS result'),
          content: Text(message),
          actions: <Widget>[
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: const Text('Close'),
            ),
          ],
        );
      },
    );
  }

  Future<void> startPaymentTransaction() async {
    _tuna = await Tuna.create(_appToken, _account, _customer, _partnerUniqueId,
        env: _env, is3dsTest: true);

    setState(() {
      _infoText = "Tuna object created";
    });

    var generateResponse = await _tuna.tokenizer.generate(_cardData);

    setState(() {
      _infoText = "Card token generated. \n SessionID: ${_tuna.sessionID}";
    });

    _threeDS = ThreeDS(
      (message) async {
        if (message == "Data collection ready") {
          setState(() {
            _infoText = "3DS data collection done. Calling /Init";
          });
          final initResponse = await callInit(generateResponse, _cardData);

          setState(() {
            _infoText = "/Init call ended. 3DS challenge loading";
          });

          final paymentMethod = initResponse["methods"][0];
          final threeDSInfo =
              ThreeDSInfo.fromJson(paymentMethod["threeDSInfo"]);

          setState(() {
            _showThreeDS = true;
          });

          _threeDS.loadChallengeFrame(threeDSInfo);

          _tuna.doStatusLongPolling((statusPollResult) {
            if (statusPollResult.code == 1) {
              if (statusPollResult.paymentMethodConfirmed) {
                if (statusPollResult.paymentApproved ?? false) {
                  setState(() {
                    _showThreeDS = false;
                    _infoText = "3DS payment ended";
                  });
                  callDialog("Payment approved!");
                } else {
                  callDialog("Payment refused");
                }
              } else {
                // callDialog("Error");
              }
            } else {
              // callDialog("Error");
            }
          }, paymentMethod["methodId"], initResponse["paymentKey"]);
        } else if (message == "Challenge done") {
          setState(() {
            _showThreeDS = false;
            _infoText = """
The challenge is done and the Webview is closed now.
This does not mean that the purchase was approved,
it only means that the challenge was completed.
To know if the payment was approved,
check the payment status.
""";
          });
        }
      },
    );

    final authenticationInfo = generateResponse.authenticationInformation!;
    final accessToken = authenticationInfo.accessToken!;
    final deviceDataCollectionUrl = authenticationInfo.deviceDataCollectionUrl!;

    _threeDS.loadDataCollectionFrame(accessToken, deviceDataCollectionUrl);
    setState(() {
      _infoText =
          "3DS device data collection is running. \n Take a look at console output. \n The webview is invisible this moment";
    });
  }

  Future<dynamic> callInit(
      GenerateResponse generateResponse, CardData cardData) async {
    try {
      Response response = await _dio.post(
        'https://engine.tunagateway.com/api/Payment/Init',
        options: Options(
          headers: {
            'accept': 'application/json',
            'x-tuna-account': _account,
            'x-tuna-apptoken': _appToken,
            'Content-Type': 'application/json',
            'Idempotency-Key': 'YzHfUsJHm73412df',
          },
        ),
        data: {
          "PartnerUniqueID": _partnerUniqueId,
          "TokenSession": _tuna.sessionID,
          "Customer": {
            "Email": _customer.email,
            "ID": _customer.id,
            "Document": "160.756.340-10",
            "DocumentType": "CPF"
          },
          "FrontData": {
            "SessionID": "3ca3cc8ff8eac0093a4097de219f2a8c",
            "Origin": "WEBSITE",
            "IpAddress": "172.18.0.1",
            "CookiesAccepted": true
          },
          "PaymentItems": {
            "Items": [
              {
                "Amount": 10,
                "ProductDescription": "Sample Product",
                "ItemQuantity": 1,
                "CategoryName": "simple",
                "AntiFraud": {"Ean": "24-WB04"}
              }
            ]
          },
          "PaymentData": {
            "Countrycode": "BR",
            "DeliveryAddress": {
              "Street": "Sample Street",
              "Number": "288",
              "City": "Salvador",
              "State": "BA",
              "Country": "BR",
              "PostalCode": "41341-545",
              "Phone": "(71)999999929"
            },
            "SalesChannel": "ECOMMERCE",
            "Amount": 10,
            "PaymentMethods": [
              {
                "PaymentMethodType": "7",
                "Amount": 10,
                "Installments": 1,
                "cardInfo": {
                  "CardNumber": cardData.cardNumber,
                  "CardHolderName": cardData.cardHolderName,
                  "BrandName": generateResponse.brand,
                  "ExpirationMonth": cardData.expirationMonth,
                  "ExpirationYear": cardData.expirationYear,
                  "Token": generateResponse.token,
                  "TokenProvider": "Tuna",
                  "TokenSingleUse": cardData.singleUse,
                  "SaveCard": !(cardData.singleUse ?? true),
                  "BillingInfo": {
                    "Document": "160.756.340-10",
                    "DocumentType": "CPF",
                    "Address": {}
                  }
                },
                "AuthenticationInformation": {
                  "Code": _tuna.sessionID,
                  "ReferenceId":
                      generateResponse.authenticationInformation!.referenceId!,
                  "TransactionId":
                      generateResponse.authenticationInformation!.transactionId!
                }
              }
            ]
          }
        },
      );

      return response.data;
    } catch (error, stacktrace) {
      print('Error: $error, Stacktrace: $stacktrace');
    }
  }

  @override
  void initState() {
    super.initState();
    startPaymentTransaction().then((_) => setState(() => _dataLoaded = true));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Wrap(
            spacing: 5.0,
            runSpacing: 5.0,
            direction: Axis.vertical,
            children: [
              Visibility(
                  visible: !_showThreeDS,
                  child: Center(
                    child: Text(_infoText),
                  )),
              _dataLoaded
                  ? SizedBox(
                      width: MediaQuery.of(context).size.width,
                      height: MediaQuery.of(context).size.height,
                      child: SizedBox.expand(
                          child: Visibility(
                              visible: _showThreeDS,
                              child: WebViewWidget(
                                  controller: _threeDS.webViewController))))
                  : Container(),
            ],
          ),
        ));
  }
}