storeRevocations method

Future<void> Function(DVPurchaseChange change) storeRevocations(
  1. FutureOr<void> reverse(
    1. DVContext context,
    2. DVPurchaseChange change
    )
)

A DVPurchases(onChange: ...) handler that runs reverse when a store takes a purchase back.

Only for a revocation -- a refund, a chargeback -- and never for a subscription that lapsed, which revokes the same entitlements and moves no money. reverse runs as its own transaction. A failure is logged rather than thrown, because the store's notification has already been applied and must still be acknowledged; a reversal whose compensation failed is DV-COMMERCE-004.

Implementation

Future<void> Function(DVPurchaseChange change) storeRevocations(
  FutureOr<void> Function(DVContext context, DVPurchaseChange change) reverse,
) =>
    (DVPurchaseChange change) async {
      if (change.revokedAt == null || change.revoked.isEmpty) return;
      final Map<String, Object?> context = <String, Object?>{
        'store': change.store.name,
        'transaction': change.originalTransactionId,
      };
      try {
        await DVTransactionRunner().call<void>(
          (DVContext unit) => reverse(unit, change),
          isolated: true,
        );
      } on DVCompensationException catch (failure) {
        _incomplete(
            'the reversal of ${change.store.name} purchase '
            '${change.originalTransactionId}',
            failure,
            context);
      } on Object catch (error, stackTrace) {
        _log.log(
          'The reversal of ${change.store.name} purchase '
          '${change.originalTransactionId} failed and was rolled back: '
          '$error',
          level: DVLogLevel.error,
          error: error,
          stackTrace: stackTrace,
          context: context,
        );
      }
    };