import 'dart:convert'; import 'dart:developer'; import 'package:dio/dio.dart'; import 'package:injectable/injectable.dart'; import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:yookassa_client/yookassa_client.dart'; import '../../main.dart'; import '../../packs/pack_manager.dart'; @LazySingleton() class YooMoneyHandler { final testKey = 'test_Px7SnKrsT0fO8ZKXmnzNqMknuHne7LwG-ypKhJnw9Ro'; final testShop = '382060'; final key = 'live_17KhhN5jmobRyjS2LKHPOBVs6noAtJYCg4Wyd_-3byQ'; final shop = '380354'; late final _yookassaClient = YookassaClient( Dio(), credentials: YookassaAuthCredentials( shopId: shop, secretKey: key, ), ); late final _testYookassaClient = YookassaClient( Dio(), credentials: YookassaAuthCredentials( shopId: testShop, secretKey: testKey, ), ); Map _testPayments = {}; YookassaClient get yookassaClient => _yookassaClient; final PackManager _packManager; YooMoneyHandler(this._packManager); Future createPayment({ required String productId, required String price, required String title, required UserModel user, required MnemoCardsProductType productType, }) async { if (user.id == null) { return null; } final reservedPaymentId = await isar.writeTxn( () => isar.paymentModels.put( PaymentModel.empty( date: DateTime.now(), userId: user.id!, ), ), ); final checkPaymentUrl = PurchaseCheckDeeplink( id: productId, productType: productType, token: reservedPaymentId.toString(), paymentSystem: PaymentSystem.yookassa, ).uri.toString(); final amount = Amount( value: price.replaceAll(new RegExp(r"\D"), ""), currency: 'RUB', ); final createdPaymentRequest = CreatePaymentRequest( amount: amount, receipt: YookassaReceipt( customer: YookassaCustomer( email: user.email, ), items: [ YookassaItem(description: title, quantity: '1', amount: amount), ], ), confirmation: YookassaConfirmation.redirect( returnUrl: checkPaymentUrl, ), capture: true, description: title, ); try { final payment = await yookassaClient.createPayment( paymentRequest: createdPaymentRequest, ); isar.writeTxn(() async { final paymentId = await isar.paymentModels.put( PaymentModel.yooKassa( id: reservedPaymentId, amount: payment.amount.value, currency: payment.amount.currency, date: DateTime.now(), userId: user.id!, packs: [ if (productType == MnemoCardsProductType.pack) productId, ], subscription: productType == MnemoCardsProductType.subscription, externalToken: payment.id, meta: jsonEncode(payment.toJson()), products: [ if (productType == MnemoCardsProductType.pack) MnemoCardsProductModelBase.pack( int.tryParse(productId), ) else if (productType == MnemoCardsProductType.subscription) MnemoCardsProductModelBase.subscription( int.tryParse(productId), ) ], ), ); await isar.userModels.put( user.copyWith(purchases: [...user.purchases, paymentId.toString()]), ); }); final url = payment.confirmation?.maybeMap( embedded: (_) {}, external: (_) {}, mobileApplication: (_) {}, qr: (_) {}, redirect: (redirect) => redirect.confirmationUrl, orElse: () => null, ); if (url == null) { throw Exception('Yookassa url is null'); } return YookassaPaymentDto( purchaseUrl: url, checkUrl: checkPaymentUrl, ); } on YookassaException catch (e, s) { print(e); log('YookassaException when creating Yookassa payment', error: e, stackTrace: s); } on Exception catch (e, s) { print(e); log('Error when creating Yookassa payment', error: e, stackTrace: s); } return null; } Future checkPayment(String yookassaId) async { final payment = await yookassaClient.getPaymentInfo( paymentId: yookassaId, ); return payment; } } extension YookassaPaymentStatusExt on YookassaPaymentStatus { PaymentStatus toPaymentStatus() => switch (this) { YookassaPaymentStatus.pending => PaymentStatus.created, YookassaPaymentStatus.waitingForCapture => PaymentStatus.waiting, YookassaPaymentStatus.succeeded => PaymentStatus.succeeded, YookassaPaymentStatus.canceled => PaymentStatus.canceled, }; }