tuna_sdk 0.1.1 copy "tuna_sdk: ^0.1.1" to clipboard
tuna_sdk: ^0.1.1 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 = "xxx";
  final String _account = "xxx";
  //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);

    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"]);
        }
      },
    );

    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(),
            ],
          ),
        ));
  }
}