@@ -23,7 +23,8 @@ public class ReportingRequestHandler : IRequestHandler<Queries.GetComparisonDate
2323IRequestHandler < GetTopOperatorDataQuery , Result < List < TopBottomOperatorDataModel > > > ,
2424IRequestHandler < GetBottomOperatorDataQuery , Result < List < TopBottomOperatorDataModel > > > ,
2525IRequestHandler < GetLastSettlementQuery , Result < LastSettlementModel > > ,
26- IRequestHandler < GetMerchantTransactionSummaryQuery , Result < List < MerchantTransactionSummaryModel > > > {
26+ IRequestHandler < GetMerchantTransactionSummaryQuery , Result < List < MerchantTransactionSummaryModel > > > ,
27+ IRequestHandler < GetProductPerformanceQuery , Result < List < ProductPerformanceModel > > > {
2728
2829 private readonly IApiClient ApiClient ;
2930 public ReportingRequestHandler ( IApiClient apiClient )
@@ -166,4 +167,73 @@ public async Task<Result<List<MerchantTransactionSummaryModel>>> Handle(GetMerch
166167
167168 return Result . Success ( summary ) ;
168169 }
170+
171+ public async Task < Result < List < ProductPerformanceModel > > > Handle ( GetProductPerformanceQuery request ,
172+ CancellationToken cancellationToken ) {
173+ // TODO: Replace with actual API call when endpoint is available
174+ // For now, return mock data for testing
175+ var contracts = await this . ApiClient . GetContracts ( request . AccessToken , Guid . Empty , request . EstateId , cancellationToken ) ;
176+
177+ if ( ! contracts . IsSuccess ) {
178+ return Result . Failure < List < ProductPerformanceModel > > ( contracts . Message ) ;
179+ }
180+
181+ var products = new List < ProductPerformanceModel > ( ) ;
182+
183+ // Calculate days in the date range to vary data based on period
184+ var daysInRange = ( request . EndDate - request . StartDate ) . Days + 1 ;
185+
186+ // Use date range as seed for consistent but varying data
187+ var seed = request . StartDate . GetHashCode ( ) ^ request . EndDate . GetHashCode ( ) ;
188+ var random = new Random ( seed ) ;
189+
190+ // Collect all unique products from all contracts
191+ var productNames = contracts . Data
192+ . SelectMany ( c => c . Products ?? new List < ContractProductModel > ( ) )
193+ . Select ( p => p . ProductName )
194+ . Distinct ( )
195+ . ToList ( ) ;
196+
197+ decimal totalValue = 0 ;
198+
199+ // Generate mock transaction data for each product
200+ // Scale transaction counts based on the date range length
201+ var countMultiplier = Math . Max ( 1 , daysInRange / 30.0 ) ; // Scale based on 30-day baseline
202+
203+ foreach ( var productName in productNames ) {
204+ if ( string . IsNullOrEmpty ( productName ) ) continue ;
205+
206+ var baseTransactionCount = random . Next ( 50 , 500 ) ;
207+ var transactionCount = ( int ) ( baseTransactionCount * countMultiplier ) ;
208+ var transactionValue = Math . Round ( ( decimal ) ( random . NextDouble ( ) * 30000 + 5000 ) * ( decimal ) countMultiplier , 2 ) ;
209+ totalValue += transactionValue ;
210+
211+ products . Add ( new ProductPerformanceModel {
212+ ProductName = productName ,
213+ TransactionCount = transactionCount ,
214+ TransactionValue = transactionValue ,
215+ PercentageContribution = 0 // Will be calculated after total is known
216+ } ) ;
217+ }
218+
219+ // Calculate percentage contributions (ensure they sum to 100%)
220+ if ( totalValue > 0 ) {
221+ decimal percentageSum = 0 ;
222+ for ( int i = 0 ; i < products . Count ; i ++ ) {
223+ if ( i == products . Count - 1 ) {
224+ // Last item gets the remainder to ensure exact 100% (protected against negative values)
225+ products [ i ] . PercentageContribution = Math . Max ( 0 , Math . Round ( 100 - percentageSum , 2 ) ) ;
226+ } else {
227+ var percentage = Math . Round ( ( products [ i ] . TransactionValue / totalValue ) * 100 , 2 ) ;
228+ products [ i ] . PercentageContribution = percentage ;
229+ percentageSum += percentage ;
230+ }
231+ }
232+ }
233+
234+ // Sort by transaction value descending
235+ products = products . OrderByDescending ( p => p . TransactionValue ) . ToList ( ) ;
236+
237+ return Result . Success ( products ) ;
238+ }
169239}
0 commit comments