150 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'dart:async';
 | |
| 
 | |
| import 'package:guru_app/financial/igc/igc_manager.dart';
 | |
| import 'package:guru_app/financial/product/product_model.dart';
 | |
| import 'package:guru_app/inventory/inventory_manager.dart';
 | |
| import 'manifest.dart';
 | |
| 
 | |
| /// Created by Haoyi on 2022/8/21
 | |
| 
 | |
| // typedef DetailsDistributor = Future<bool> Function(Details, TransactionMethod, String scene);
 | |
| 
 | |
| typedef DetailsDistributor = Future<List<StockItem>> Function(
 | |
|     Details, TransactionMethod, String scene);
 | |
| 
 | |
| typedef ManifestBuilder = Future<Manifest?> Function(TransactionIntent);
 | |
| 
 | |
| class ManifestManager {
 | |
|   ManifestManager._() {
 | |
|     observableDeliveredManifest = deliveredManifestStream.stream.asBroadcastStream();
 | |
|   }
 | |
| 
 | |
|   final StreamController<Manifest> deliveredManifestStream = StreamController();
 | |
| 
 | |
|   static final ManifestManager instance = ManifestManager._();
 | |
| 
 | |
|   late Stream<Manifest> observableDeliveredManifest;
 | |
| 
 | |
|   final Map<String, DetailsDistributor> distributors = {
 | |
|     DetailsReservedType.igc: _deliverIgcDetails
 | |
|   };
 | |
| 
 | |
|   final List<ManifestBuilder> builders = [];
 | |
| 
 | |
|   static Future<List<StockItem>> _deliverIgcDetails(
 | |
|       Details details, TransactionMethod method, String scene) async {
 | |
|     if (details.amount > 0) {
 | |
|       await IgcManager.instance.accumulate(details.amount, method, scene: scene);
 | |
|     }
 | |
|     return [];
 | |
|   }
 | |
| 
 | |
|   static Future<List<StockItem>> _deliverDefaultDetails(
 | |
|       Details details, TransactionMethod method, String scene) async {
 | |
|     if (details.amount > 0) {
 | |
|       return [StockItem.fromDetails(details)];
 | |
|     }
 | |
|     return [];
 | |
|   }
 | |
| 
 | |
|   // static Future<bool> _deliverDetails(
 | |
|   //     Details details, TransactionMethod method, String scene) async {
 | |
|   //   final stock = StockItem.fromDetails(details);
 | |
|   //   if (stock.amount > 0) {
 | |
|   //     await InventoryManager.instance.acquire([stock], method, scene);
 | |
|   //   }
 | |
|   //   return false;
 | |
|   // }
 | |
| 
 | |
|   void addDistributor(String type, DetailsDistributor distributor) {
 | |
|     distributors[type] = distributor;
 | |
|   }
 | |
| 
 | |
|   void addBuilder(ManifestBuilder builder) {
 | |
|     builders.add(builder);
 | |
|   }
 | |
| 
 | |
|   void addBuilders(List<ManifestBuilder> builders) {
 | |
|     this.builders.addAll(builders);
 | |
|   }
 | |
| 
 | |
|   Future _acquire(List<StockItem> items, TransactionMethod method, Manifest manifest) async {
 | |
|     if (items.isNotEmpty) {
 | |
|       String specific = "";
 | |
|       switch (method) {
 | |
|         case TransactionMethod.iap:
 | |
|           specific = manifest.contentId;
 | |
|           break;
 | |
|         case TransactionMethod.igc:
 | |
|           specific = "coin";
 | |
|           break;
 | |
|         case TransactionMethod.igb:
 | |
|           specific = manifest.barterId;
 | |
|           break;
 | |
|         default:
 | |
|           specific = manifest.scene;
 | |
|           break;
 | |
|       }
 | |
|       await InventoryManager.instance.acquire(items, method, specific, scene: manifest.scene);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future<List<StockItem>> deliverStockItems(
 | |
|       List<StockItem> items, Manifest manifest, TransactionMethod method) async {
 | |
|     final List<StockItem> unsold = [];
 | |
|     for (var item in items) {
 | |
|       if (item.sku == DetailsReservedType.igc) {
 | |
|         await distributors[DetailsReservedType.igc]
 | |
|             ?.call(Details.define(DetailsReservedType.igc, item.amount), method, manifest.scene);
 | |
|         continue;
 | |
|       }
 | |
|       unsold.add(item);
 | |
|     }
 | |
|     return unsold;
 | |
|   }
 | |
| 
 | |
|   Future<bool> deliver(Manifest manifest, TransactionMethod method) async {
 | |
|     bool result = false;
 | |
|     final List<StockItem> unsold = [];
 | |
|     for (var details in manifest.details) {
 | |
|       final items = await distributors[details.type]?.call(details, method, manifest.scene) ??
 | |
|           await _deliverDefaultDetails(details, method, manifest.scene);
 | |
|       final unsoldItems = await deliverStockItems(items, manifest, method);
 | |
|       unsold.addAll(unsoldItems);
 | |
|       result |= unsoldItems.isEmpty;
 | |
|     }
 | |
|     if (unsold.isNotEmpty) {
 | |
|       await _acquire(unsold, method, manifest);
 | |
|     }
 | |
| 
 | |
|     deliveredManifestStream.add(manifest);
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   Future<Manifest> createManifest(TransactionIntent intent) async {
 | |
|     for (var builder in builders) {
 | |
|       final manifest = await builder(intent);
 | |
|       if (manifest != null) {
 | |
|         return manifest;
 | |
|       }
 | |
|     }
 | |
|     return Manifest.empty;
 | |
|   }
 | |
| 
 | |
|   Manifest createIgcManifest(int igc, {String? category, String scene = ""}) {
 | |
|     final details = <Details>[];
 | |
|     details.add(Details.define(DetailsReservedType.igc, igc));
 | |
| 
 | |
|     final extras = <String, dynamic>{ExtraReservedField.scene: scene};
 | |
|     return Manifest(category ?? DetailsReservedType.igc, extras: extras, details: details);
 | |
|   }
 | |
| 
 | |
| // Manifest createIgbManifest(int igc, {String? category, String scene = ""}) {
 | |
| //   final details = <Details>[];
 | |
| //   details.add(Details.define(DetailsReservedType.igc, igc));
 | |
| //
 | |
| //   final extras = <String, dynamic>{ExtraReservedField.scene: scene};
 | |
| //   return Manifest(category ?? DetailsReservedType.igc, extras: extras, details: details);
 | |
| // }
 | |
| }
 |