stone_smart_flutter 1.4.0 copy "stone_smart_flutter: ^1.4.0" to clipboard
stone_smart_flutter: ^1.4.0 copied to clipboard

PlatformAndroid

Plugin Flutter para integrar sua aplicação com o SDK Android da Stone para meios de pagamento.

Stone Smart Flutter

Stone

Sobre   |   Tecnologias   |   Configuração   |   Autores   |  


Buy Me A Book

Github Badge

Plugin não oficial!!! #

🎯 Sobre #

Projeto destinado a facilitar a integração com o SDK da Stone Smart no Flutter. Funciona somente com máquinas smarts.

Máquinas compatíveis:

  • Positivo L300
  • Positivo L400
  • Ingenico APOS A8
  • Sunmi P2
  • Gertec GPOS700X

🚀 Tecnologias #

As seguintes ferramentas foram usadas na construção do projeto:

🏁 Configuração #

# Pubspec.yaml #

Para usar este plugin, adicione stone_smart_flutter como dependência ao seu arquivo pubspec.yaml.

dependencies:
  stone_smart_flutter: any

This will get you the latest version.

# Build.gradle #

Em seu build.gradle a nivel do app, a propriedade minSdkVersion precisa ser level 23. Recurso este exigido pela versão 4.9.5 do SDK Stone.

...
defaultConfig {
        applicationId "com.example.stone_example"
        minSdkVersion 22
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
...

# Implementação #

Para começar é necessário criar uma classe que implemente ´StoneHandler´, sendo que essa é a responsável por monitorar e retornar os dados da Stone.

Criando classe StoneController #

import 'dart:convert';

import 'package:stone_smart_flutter/stone_smart_flutter.dart';

import '../../../sqflite/data/helper/debug_log.dart';
import '../entities/stone_transaction.dart';

class StoneHandler extends IStoneHandler {
  final Function(StoneTransaction?)? onTransaction;
  final Function(String)? onMessageMonitor;

  StoneHandler({
    this.onTransaction,
    this.onMessageMonitor,
  });

  @override
  Future<void> onError(String message) async {
    DebugLog.payment('onError_STONE: $message');
    final stoneTransaction = _getStoneTransaction(message);
    if (onTransaction != null) {
      onTransaction!(stoneTransaction);
    }
  }

  @override
  Future<void> onMessage(String message) async {
    DebugLog.payment('onMessage_STONE: $message');
    if (onMessageMonitor != null) {
      onMessageMonitor!(message);
    }
  }

  @override
  Future<void> onFinishedResponse(String message) async {
    DebugLog.payment('onFinishedResponse_STONE: $message');
    final stoneTransaction = _getStoneTransaction(message);
    if (onTransaction != null) {
      onTransaction!(stoneTransaction);
    }
  }

  @override
  Future<void> onChanged(String message) async {
    DebugLog.payment('onChanged_STONE: $message');
    final stoneTransaction = _getStoneTransaction(message);
    if (onTransaction != null) {
      onTransaction!(stoneTransaction);
    }
  }

  @override
  Future<void> onAuthProgress(String message) async {
    DebugLog.payment('onAuthProgress_STONE: $message');
    final stoneTransaction = _getStoneTransaction(message);
    if (stoneTransaction?.method != 'active') {
      if (onTransaction != null) {
        onTransaction!(stoneTransaction);
      }
    }
  }

  @override
  Future<void> onTransactionSuccess() async {
    DebugLog.payment('onTransactionSuccess_STONE');
  }

  @override
  Future<void> onLoading(bool show) async {}

  StoneTransaction? _getStoneTransaction(String message) {
    try {
      if (message.contains('{')) {
        final map = json.decode(message);
        final stoneTransaction = StoneTransaction.fromMap(map);
        return stoneTransaction;
      }
    } catch (e) {
      DebugLog.payment('***Erro_getStoneTransaction: $e');
      return null;
    }
    return null;
  }
}
Classe StoneTransaction

Essa classe é responsável por decodificar o retorno da STONE.

// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';

import 'package:acc_checkout/app/core/domain/entities/i_transaction_response.dart';

class StoneTransaction extends ITransactionResponse {
  final String? actionCode;
  final String? aid;
  final String? amount;
  final String? arcq;
  final String? cardBrand;
  final int? cardBrandId;
  final String? cardHolderNumber;
  final String? cardSequenceNumber;
  final String? date;
  final String? entryMode;
  final int? idFromBase;
  final int? isBuildResponse;
  final String? manufacture;
  final int? result;
  final String? saleAffiliationKey;
  final String? serialNumber;
  final String? time;
  final String? transactionReference;
  final String? typeOfTransactionEnum;
  final String? errorMessage;
  final String? method;
  final String? transactionStatus;
  final String? messageFromAuthorize;
  final String? message;
  final String? authorizationCode;
  final String? externalId;
  final String? transactionKey;
  final String? initiatorTransactionKey;

  final String? actionResultMessage;
  final bool isPrinterRequest;
  final List<String>? options;

  List<String> get getOptions => options ?? [];

  bool get isApproved =>
      transactionStatus?.toUpperCase() == 'APPROVED' &&
      method?.toLowerCase() == 'transaction';

  StoneTransaction({
    required this.actionCode,
    required this.aid,
    required this.amount,
    required this.arcq,
    required this.cardBrand,
    required this.cardBrandId,
    required this.cardHolderNumber,
    required this.cardSequenceNumber,
    required this.date,
    required this.entryMode,
    required this.idFromBase,
    required this.isBuildResponse,
    required this.manufacture,
    required this.result,
    required this.saleAffiliationKey,
    required this.serialNumber,
    required this.time,
    required this.transactionReference,
    required this.typeOfTransactionEnum,
    required this.errorMessage,
    required this.method,
    required this.transactionStatus,
    required this.messageFromAuthorize,
    required this.message,
    required this.actionResultMessage,
    required this.authorizationCode,
    required this.transactionKey,
    required this.externalId,
    required this.initiatorTransactionKey,
    this.isPrinterRequest = false,
    this.options,
  });

  StoneTransaction copyWith({
    String? actionCode,
    String? aid,
    String? amount,
    String? arcq,
    String? cardBrand,
    int? cardBrandId,
    String? cardHolderNumber,
    String? cardSequenceNumber,
    String? date,
    String? entryMode,
    int? idFromBase,
    int? isBuildResponse,
    String? manufacture,
    int? result,
    String? saleAffiliationKey,
    String? serialNumber,
    String? time,
    String? transactionReference,
    String? typeOfTransactionEnum,
    String? errorMessage,
    String? method,
    String? transactionStatus,
    String? messageFromAuthorize,
    String? message,
    String? actionResultMessage,
    String? authorizationCode,
    String? transactionKey,
    String? externalId,
    String? initiatorTransactionKey,
    bool? isPrinterRequest,
    List<String>? options,
  }) {
    return StoneTransaction(
      actionCode: actionCode ?? this.actionCode,
      aid: aid ?? this.aid,
      amount: amount ?? this.amount,
      arcq: arcq ?? this.arcq,
      cardBrand: cardBrand ?? this.cardBrand,
      cardBrandId: cardBrandId ?? this.cardBrandId,
      cardHolderNumber: cardHolderNumber ?? this.cardHolderNumber,
      cardSequenceNumber: cardSequenceNumber ?? this.cardSequenceNumber,
      date: date ?? this.date,
      entryMode: entryMode ?? this.entryMode,
      idFromBase: idFromBase ?? this.idFromBase,
      isBuildResponse: isBuildResponse ?? this.isBuildResponse,
      manufacture: manufacture ?? this.manufacture,
      result: result ?? this.result,
      saleAffiliationKey: saleAffiliationKey ?? this.saleAffiliationKey,
      serialNumber: serialNumber ?? this.serialNumber,
      time: time ?? this.time,
      transactionReference: transactionReference ?? this.transactionReference,
      typeOfTransactionEnum:
          typeOfTransactionEnum ?? this.typeOfTransactionEnum,
      errorMessage: errorMessage ?? this.errorMessage,
      method: method ?? this.method,
      transactionStatus: transactionStatus ?? this.transactionStatus,
      messageFromAuthorize: messageFromAuthorize ?? this.messageFromAuthorize,
      message: message ?? this.message,
      actionResultMessage: actionResultMessage ?? this.actionResultMessage,
      authorizationCode: authorizationCode ?? this.authorizationCode,
      transactionKey: transactionKey ?? this.transactionKey,
      externalId: externalId ?? this.externalId,
      initiatorTransactionKey:
          initiatorTransactionKey ?? this.initiatorTransactionKey,
      isPrinterRequest: isPrinterRequest ?? this.isPrinterRequest,
      options: options ?? this.options,
    );
  }

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'actionCode': actionCode,
      'aid': aid,
      'amount': amount,
      'arcq': arcq,
      'cardBrand': cardBrand,
      'cardBrandId': cardBrandId,
      'cardHolderNumber': cardHolderNumber,
      'cardSequenceNumber': cardSequenceNumber,
      'date': date,
      'entryMode': entryMode,
      'idFromBase': idFromBase,
      'isBuildResponse': isBuildResponse,
      'manufacture': manufacture,
      'result': result,
      'saleAffiliationKey': saleAffiliationKey,
      'serialNumber': serialNumber,
      'time': time,
      'transactionReference': transactionReference,
      'typeOfTransactionEnum': typeOfTransactionEnum,
      'errorMessage': errorMessage,
      'method': method,
      'transactionStatus': transactionStatus,
      'messageFromAuthorize': messageFromAuthorize,
      'message': message,
      'actionResultMessage': actionResultMessage ?? '',
      'authorizationCode': authorizationCode ?? '',
      'externalId': externalId,
      'transactionKey': transactionKey,
      'initiatorTransactionKey': initiatorTransactionKey,
      'isPrinterRequest': isPrinterRequest,
      'options': options,
    };
  }

  factory StoneTransaction.fromMap(Map<String, dynamic> map) {
    return StoneTransaction(
      actionCode: map['actionCode']?.toString(),
      aid: map['aid']?.toString(),
      amount: map['amount']?.toString(),
      arcq: map['arcq']?.toString(),
      cardBrand: map['cardBrand']?.toString(),
      cardBrandId: map['cardBrandId'] != null
          ? int.tryParse(map['cardBrandId'].toString())
          : null,
      cardHolderNumber: map['cardHolderNumber']?.toString(),
      cardSequenceNumber: map['cardSequenceNumber']?.toString(),
      date: map['date']?.toString(),
      entryMode: map['entryMode']?.toString(),
      idFromBase: map['idFromBase'] != null
          ? int.tryParse(map['idFromBase'].toString())
          : null,
      isBuildResponse: map['isBuildResponse'] != null
          ? int.tryParse(map['isBuildResponse'].toString())
          : null,
      manufacture: map['manufacture']?.toString(),
      result:
          map['result'] != null ? int.tryParse(map['result'].toString()) : null,
      saleAffiliationKey: map['saleAffiliationKey']?.toString(),
      serialNumber: map['serialNumber']?.toString(),
      time: map['time']?.toString(),
      transactionReference: map['transactionReference']?.toString(),
      typeOfTransactionEnum: map['typeOfTransactionEnum']?.toString(),
      errorMessage: map['errorMessage']?.toString(),
      method: map['method']?.toString(),
      transactionStatus: map['transactionStatus']?.toString(),
      messageFromAuthorize: map['messageFromAuthorize']?.toString(),
      message: map['message']?.toString(),
      actionResultMessage: map['actionResultMessage'] != null
          ? map['actionResultMessage']!.toString()
          : '',
      authorizationCode: map['authorizationCode'] != null
          ? map['authorizationCode']!.toString()
          : '',
      externalId: map['externalId']?.toString(),
      transactionKey: map['transactionKey']?.toString(),
      initiatorTransactionKey: map['initiatorTransactionKey']?.toString(),
      isPrinterRequest: map['isPrinterRequest'] != null
          ? map['isPrinterRequest'] as bool
          : false,
      options:
          map['options'] != null ? List<String>.from(map['options']) : null,
    );
  }

  factory StoneTransaction.buildErrorResponse({
    required int result,
    required String errorMessage,
    required String method,
  }) {
    return StoneTransaction(
      actionCode: '',
      aid: '',
      amount: '',
      arcq: '',
      cardBrand: '',
      cardBrandId: 0,
      cardHolderNumber: '',
      cardSequenceNumber: '',
      date: '',
      entryMode: '',
      idFromBase: 0,
      isBuildResponse: 0,
      manufacture: '',
      result: result,
      saleAffiliationKey: '',
      serialNumber: '',
      time: '',
      transactionReference: '',
      typeOfTransactionEnum: '',
      errorMessage: errorMessage,
      method: method,
      transactionStatus: '',
      messageFromAuthorize: '',
      message: errorMessage,
      actionResultMessage: null,
      authorizationCode: '',
      transactionKey: '',
      externalId: '',
      initiatorTransactionKey: '',
      isPrinterRequest: false,
      options: null,
    );
  }

  String toJson() => json.encode(toMap());

  factory StoneTransaction.fromJson(String source) =>
      StoneTransaction.fromMap(json.decode(source) as Map<String, dynamic>);

  @override
  // TODO: implement props
  List<Object?> get props => throw UnimplementedError();
}

Métodos da ´StoneHandler´

onAbortedSuccessfully

Acionado quando uma transação de abort é concluída com sucesso.

onAuthProgress

Acionado quando uma transação está em progresso. Retorno do status do Pinpad também é mapeado aqui.

onError

Acionado quando uma transação retorna um estado de ´Erro´, devolvendo como parâmetro um objeto em formato ´String´ com a mensagem e o método.

onMessage

Método responsável por devolver para o usuário uma mensagem retornada da Stone.

onFinishedResponse

Método responsável por devolver uma response da transação.

onTransactionSuccess

Método acionado quando a transação foi concluída com sucesso.

Iniciar transação

Para iniciar a transação é necessário primeiro chamar a função de ativação do PinPad, passando como parâmetro o código de ativação daquele POS (código este informado na sua conta PagBank).

StoneSmart.instance().payment.activePinpad(stoneCode: '12345');

Logo após ativação, o SDK da Stone fornece algumas opções de transação como:

  • Crédito = StoneSmart.instance().payment.creditPayment(12.50)

  • Crédito Parcelado = StoneSmart.instance().payment.creditPaymentParc(value: controller.amount, installment: 2)

  • Débito = StoneSmart.instance().payment.debitPayment(12.50)

  • PIX = StoneSmart.instance().payment.pixPayment.(amount: 1250, qrCodeAuthorization: '', qrCodeProviderid: '')

  • Voucher (alimentação) = StoneSmart.instance().payment.voucherPayment(12.50)

  • Estorno = StoneSmart.instance().payment.cancelTransaction(amount: controller.saleValue, transactionType: PaymentTypeTransaction.CREDIT)

  • Abortar transação = StoneSmart.instance().payment.abortTransaction()

**Obs: Por padrão o SDK da Stone SEMPRE imprime a via do consumidor.

Modelo de resposta #

Método onAuthProgress, onChanged e onError

Estes métodos iram retornar um objeto em formato de string com a seguinte estrutura:

{
  "method": "transaction",
  "message": "Transação aprovada",
  "errorMessage": "",
  "result": 0,
}

O campo errorMessage só é preenchido caso venha algum erro; Métodos mapeados para o campo method: abort, transaction, active, printer, reversal;

Método onFinishedResponse

Este método irá retornar um objeto em formato de String com a seguinte estrutura:

{
"method": "transaction",
"idFromBase": 0,
"amount": 1250,
"cardHolderNumber": "",
"cardBrand": "",
"date": "",
"time": "",
"aid": "",
"arcq": "",
"transactionReference": "",
"saleAffiliationKey": "",
"entryMode": "",
"typeOfTransactionEnum": "",
"serialNumber": "",
"manufacture": "",
"actionCode": "",
"transactionStatus": "",
"messageFromAuthorize": "",
"errorMessage": "",
"result": 0,
}

Observações:

Para a transação com PIX é necessário fornecer nos parâmetros o qrCodeAuthroization e o qrCodeProviderid fornecidos pela Stone.

No método onChanged, pode vir um retorno com o campo "method" preenchido como "QRCode" e no campo message virá a imagem em formato Bitmap, convertida em String, ficando a cargo do desenvolvedor mostrar o QRCode gerado para o usuário final.

Cancelamento

Para cancelar uma transação é necessário chamar o método cancelTransaction passando o ID da transação. Caso você não tenha a informação do ID da transação, é necessário chamar o método getAllTransactions para trazer todas transações em forma de lista, e você conseguir pegar as informações de valor, id e status.

DICA #

Mapeem o retorno sempre pela função onFinishedresponse, todos os retornos do SDK estão concentrados nela. Para você saber do que trata o retorno, verifique o campo method quem junto na response. Esse campo é responsável por lhe indicar do que se trata, se é transaction, printer, etc.

Os possíveis retornos para o campo method são:

void onFinishedResponseMonitor(StoneTransaction? stoneTransaction) {
    switch (stoneTransaction?.method) {
      case 'active':
        //Retorno se o terminal foi ativado ou não
        break;
      case 'transaction':
        //Retorno completo de uma transação
        break;
      case 'abort':
        break;
      case 'abortPix':
        break;
      case 'cancel':
        break;
      case 'printer':
        break;
      case 'QRCode':
        //O QRCode vem aqui e deve ser exibido ao cliente
        break;
      case 'PaymentOptions':
        //Abrir modal para escolher forma de pagamento (alimentacao ou refeicao)
        //Chamar método  _stoneSmart.payment.setPaymentOption(option: <opcao_escolhida>);
        break;
      case 'reversal':
        break;
      default:
    }
  }

📝 Autores #

Este projeto foi desenvolvido por: Jhonathan Queiroz


Voltar para o topo

6
likes
150
points
199
downloads

Publisher

unverified uploader

Weekly Downloads

Plugin Flutter para integrar sua aplicação com o SDK Android da Stone para meios de pagamento.

Repository (GitHub)

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter, interface_stone_smart_flutter

More

Packages that depend on stone_smart_flutter