feat: add payment

This commit is contained in:
2026-07-05 16:03:15 +03:30
parent c2356b3242
commit 5017e9a613
30 changed files with 470 additions and 65 deletions
@@ -1,5 +1,6 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../core/payment/payment_gateway.dart';
import '../../../../core/resources/data_state.dart';
import '../../../../core/usecase/use_case.dart';
import '../../domain/use_cases/ad_reward_usecase.dart';
@@ -17,6 +18,7 @@ class ShopBloc extends Bloc<ShopEvent, ShopBlocState> {
final SelectCardUseCase selectCardUseCase;
final PurchaseUseCase purchaseUseCase;
final AdRewardUseCase adRewardUseCase;
final PaymentGateway gateway;
ShopBloc(
this.getShopUseCase,
@@ -24,6 +26,7 @@ class ShopBloc extends Bloc<ShopEvent, ShopBlocState> {
this.selectCardUseCase,
this.purchaseUseCase,
this.adRewardUseCase,
this.gateway,
) : super(ShopBlocState.initial()) {
on<LoadShopEvent>((event, emit) => _load(emit));
@@ -33,15 +36,7 @@ class ShopBloc extends Bloc<ShopEvent, ShopBlocState> {
on<SelectCardEvent>((event, emit) =>
_action(emit, () => selectCardUseCase(event.cardId)));
on<PurchaseEvent>((event, emit) => _action(
emit,
() => purchaseUseCase(PurchaseParams(
store: 'bazaar',
kind: event.kind,
productId: event.productId,
token:
'dev-${event.kind}-${event.productId}-${DateTime.now().millisecondsSinceEpoch}',
))));
on<PurchaseEvent>((event, emit) => _action(emit, () => _purchase(event)));
on<AdRewardEvent>((event, emit) => _action(
emit,
@@ -56,6 +51,42 @@ class ShopBloc extends Bloc<ShopEvent, ShopBlocState> {
));
}
/// جریانِ خرید: ابتدا پرداختِ فروشگاهی (native) اجرا می‌شود، سپس مدرکِ خرید
/// (token/purchaseData/signature) برای اعتبارسنجی به بک‌اند فرستاده می‌شود و
/// در پایان، خرید در فروشگاه consume می‌شود.
Future<DataState<String>> _purchase(PurchaseEvent event) async {
// برای پرداختِ native به SKUِ فروشگاه نیاز است؛ اگر تنظیم نشده باشد از
// شناسه‌ی کاتالوگ استفاده می‌کنیم (حالتِ توسعه/تک‌فروشگاهی).
final sku = event.sku.isNotEmpty ? event.sku : event.productId;
final PurchaseResult result;
try {
result = await gateway.purchase(sku);
} catch (e) {
return DataError<String>('خطا در پرداخت: $e');
}
if (!result.success) {
return DataError<String>('خرید انجام نشد یا لغو شد');
}
final verify = await purchaseUseCase(PurchaseParams(
store: gateway.store,
kind: event.kind,
productId: event.productId,
token: result.token,
purchaseData: result.purchaseData,
signature: result.signature,
));
// پس از تأییدِ بک‌اند، خرید را در فروشگاه نهایی/مصرف می‌کنیم.
if (verify is DataSuccess && result.onConfirmed != null) {
try {
await result.onConfirmed!();
} catch (_) {/* consume ناموفق حیاتی نیست */}
}
return verify;
}
Future<void> _load(Emitter<ShopBlocState> emit) async {
emit(state.copyWith(loadStatus: ShopLoading()));
final res = await getShopUseCase(const NoParams());