report dashboard

This commit is contained in:
efrilm
2025-11-03 16:24:11 +07:00
parent 069c2296de
commit b4a9cf31fc
30 changed files with 5779 additions and 5 deletions
@@ -0,0 +1,8 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/analytic/analytic.dart';
part 'analytic_dtos.freezed.dart';
part 'analytic_dtos.g.dart';
part 'dtos/dashboard_dto.dart';
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,139 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'analytic_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$DashboardAnalyticDtoImpl _$$DashboardAnalyticDtoImplFromJson(
Map<String, dynamic> json,
) => _$DashboardAnalyticDtoImpl(
organizationId: json['organization_id'] as String?,
outletId: json['outlet_id'] as String?,
dateFrom: json['date_from'] as String?,
dateTo: json['date_to'] as String?,
overview: json['overview'] == null
? null
: DashboardOverviewDto.fromJson(json['overview'] as Map<String, dynamic>),
topProducts: (json['top_products'] as List<dynamic>?)
?.map((e) => DashboardTopProductDto.fromJson(e as Map<String, dynamic>))
.toList(),
paymentMethods: (json['payment_methods'] as List<dynamic>?)
?.map(
(e) => DashboardPaymentMethodDto.fromJson(e as Map<String, dynamic>),
)
.toList(),
recentSales: (json['recent_sales'] as List<dynamic>?)
?.map((e) => DashboardRecentSaleDto.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$DashboardAnalyticDtoImplToJson(
_$DashboardAnalyticDtoImpl instance,
) => <String, dynamic>{
'organization_id': instance.organizationId,
'outlet_id': instance.outletId,
'date_from': instance.dateFrom,
'date_to': instance.dateTo,
'overview': instance.overview,
'top_products': instance.topProducts,
'payment_methods': instance.paymentMethods,
'recent_sales': instance.recentSales,
};
_$DashboardOverviewDtoImpl _$$DashboardOverviewDtoImplFromJson(
Map<String, dynamic> json,
) => _$DashboardOverviewDtoImpl(
totalSales: (json['total_sales'] as num?)?.toInt(),
totalOrders: (json['total_orders'] as num?)?.toInt(),
averageOrderValue: (json['average_order_value'] as num?)?.toDouble(),
totalCustomers: (json['total_customers'] as num?)?.toInt(),
voidedOrders: (json['voided_orders'] as num?)?.toInt(),
refundedOrders: (json['refunded_orders'] as num?)?.toInt(),
);
Map<String, dynamic> _$$DashboardOverviewDtoImplToJson(
_$DashboardOverviewDtoImpl instance,
) => <String, dynamic>{
'total_sales': instance.totalSales,
'total_orders': instance.totalOrders,
'average_order_value': instance.averageOrderValue,
'total_customers': instance.totalCustomers,
'voided_orders': instance.voidedOrders,
'refunded_orders': instance.refundedOrders,
};
_$DashboardTopProductDtoImpl _$$DashboardTopProductDtoImplFromJson(
Map<String, dynamic> json,
) => _$DashboardTopProductDtoImpl(
productId: json['product_id'] as String?,
productName: json['product_name'] as String?,
categoryId: json['category_id'] as String?,
categoryName: json['category_name'] as String?,
quantitySold: (json['quantity_sold'] as num?)?.toInt(),
revenue: (json['revenue'] as num?)?.toInt(),
averagePrice: (json['average_price'] as num?)?.toDouble(),
orderCount: (json['order_count'] as num?)?.toInt(),
);
Map<String, dynamic> _$$DashboardTopProductDtoImplToJson(
_$DashboardTopProductDtoImpl instance,
) => <String, dynamic>{
'product_id': instance.productId,
'product_name': instance.productName,
'category_id': instance.categoryId,
'category_name': instance.categoryName,
'quantity_sold': instance.quantitySold,
'revenue': instance.revenue,
'average_price': instance.averagePrice,
'order_count': instance.orderCount,
};
_$DashboardPaymentMethodDtoImpl _$$DashboardPaymentMethodDtoImplFromJson(
Map<String, dynamic> json,
) => _$DashboardPaymentMethodDtoImpl(
paymentMethodId: json['payment_method_id'] as String?,
paymentMethodName: json['payment_method_name'] as String?,
paymentMethodType: json['payment_method_type'] as String?,
totalAmount: (json['total_amount'] as num?)?.toInt(),
orderCount: (json['order_count'] as num?)?.toInt(),
paymentCount: (json['payment_count'] as num?)?.toInt(),
percentage: (json['percentage'] as num?)?.toDouble(),
);
Map<String, dynamic> _$$DashboardPaymentMethodDtoImplToJson(
_$DashboardPaymentMethodDtoImpl instance,
) => <String, dynamic>{
'payment_method_id': instance.paymentMethodId,
'payment_method_name': instance.paymentMethodName,
'payment_method_type': instance.paymentMethodType,
'total_amount': instance.totalAmount,
'order_count': instance.orderCount,
'payment_count': instance.paymentCount,
'percentage': instance.percentage,
};
_$DashboardRecentSaleDtoImpl _$$DashboardRecentSaleDtoImplFromJson(
Map<String, dynamic> json,
) => _$DashboardRecentSaleDtoImpl(
date: json['date'] as String?,
sales: (json['sales'] as num?)?.toInt(),
orders: (json['orders'] as num?)?.toInt(),
items: (json['items'] as num?)?.toInt(),
tax: (json['tax'] as num?)?.toInt(),
discount: (json['discount'] as num?)?.toInt(),
netSales: (json['net_sales'] as num?)?.toInt(),
);
Map<String, dynamic> _$$DashboardRecentSaleDtoImplToJson(
_$DashboardRecentSaleDtoImpl instance,
) => <String, dynamic>{
'date': instance.date,
'sales': instance.sales,
'orders': instance.orders,
'items': instance.items,
'tax': instance.tax,
'discount': instance.discount,
'net_sales': instance.netSales,
};
@@ -0,0 +1,50 @@
import 'dart:developer';
import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';
import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/extension/extension.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/analytic/analytic.dart';
import '../analytic_dtos.dart';
@injectable
class AnalyticRemoteDataProvider {
final ApiClient _apiClient;
final _logName = 'AnalyticRemoteDataProvider';
AnalyticRemoteDataProvider(this._apiClient);
Future<DC<AnalyticFailure, DashboardAnalyticDto>> fetchDashboard({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
try {
final response = await _apiClient.get(
ApiPath.analyticDashboard,
params: {
'date_from': dateFrom.toServerDate(),
'date_to': dateTo.toServerDate(),
},
headers: getAuthorizationHeader(),
);
if (response.data['success'] == false) {
return DC.error(AnalyticFailure.unexpectedError());
}
final dashboard = DashboardAnalyticDto.fromJson(
response.data['data'] as Map<String, dynamic>,
);
return DC.data(dashboard);
} on ApiFailure catch (e, s) {
log('fetchDashboard', name: _logName, error: e, stackTrace: s);
return DC.error(AnalyticFailure.serverError(e));
}
}
}
@@ -0,0 +1,149 @@
part of '../analytic_dtos.dart';
@freezed
class DashboardAnalyticDto with _$DashboardAnalyticDto {
const DashboardAnalyticDto._();
const factory DashboardAnalyticDto({
@JsonKey(name: "organization_id") String? organizationId,
@JsonKey(name: "outlet_id") String? outletId,
@JsonKey(name: "date_from") String? dateFrom,
@JsonKey(name: "date_to") String? dateTo,
@JsonKey(name: "overview") DashboardOverviewDto? overview,
@JsonKey(name: "top_products") List<DashboardTopProductDto>? topProducts,
@JsonKey(name: "payment_methods")
List<DashboardPaymentMethodDto>? paymentMethods,
@JsonKey(name: "recent_sales") List<DashboardRecentSaleDto>? recentSales,
}) = _DashboardAnalyticDto;
factory DashboardAnalyticDto.fromJson(Map<String, dynamic> json) =>
_$DashboardAnalyticDtoFromJson(json);
// Optional mapping ke domain
DashboardAnalytic toDomain() => DashboardAnalytic(
organizationId: organizationId ?? '',
outletId: outletId ?? '',
dateFrom: dateFrom ?? '',
dateTo: dateTo ?? '',
overview: overview?.toDomain() ?? DashboardOverview.empty(),
topProducts: topProducts?.map((e) => e.toDomain()).toList() ?? [],
paymentMethods: paymentMethods?.map((e) => e.toDomain()).toList() ?? [],
recentSales: recentSales?.map((e) => e.toDomain()).toList() ?? [],
);
}
@freezed
class DashboardOverviewDto with _$DashboardOverviewDto {
const DashboardOverviewDto._();
const factory DashboardOverviewDto({
@JsonKey(name: "total_sales") int? totalSales,
@JsonKey(name: "total_orders") int? totalOrders,
@JsonKey(name: "average_order_value") double? averageOrderValue,
@JsonKey(name: "total_customers") int? totalCustomers,
@JsonKey(name: "voided_orders") int? voidedOrders,
@JsonKey(name: "refunded_orders") int? refundedOrders,
}) = _DashboardOverviewDto;
factory DashboardOverviewDto.fromJson(Map<String, dynamic> json) =>
_$DashboardOverviewDtoFromJson(json);
// Optional mapping ke domain
DashboardOverview toDomain() => DashboardOverview(
totalSales: totalSales ?? 0,
totalOrders: totalOrders ?? 0,
averageOrderValue: averageOrderValue ?? 0.0,
totalCustomers: totalCustomers ?? 0,
voidedOrders: voidedOrders ?? 0,
refundedOrders: refundedOrders ?? 0,
);
}
@freezed
class DashboardTopProductDto with _$DashboardTopProductDto {
const DashboardTopProductDto._();
const factory DashboardTopProductDto({
@JsonKey(name: "product_id") String? productId,
@JsonKey(name: "product_name") String? productName,
@JsonKey(name: "category_id") String? categoryId,
@JsonKey(name: "category_name") String? categoryName,
@JsonKey(name: "quantity_sold") int? quantitySold,
@JsonKey(name: "revenue") int? revenue,
@JsonKey(name: "average_price") double? averagePrice,
@JsonKey(name: "order_count") int? orderCount,
}) = _DashboardTopProductDto;
factory DashboardTopProductDto.fromJson(Map<String, dynamic> json) =>
_$DashboardTopProductDtoFromJson(json);
// Optional mapping ke domain
DashboardTopProduct toDomain() => DashboardTopProduct(
productId: productId ?? '',
productName: productName ?? '',
categoryId: categoryId ?? '',
categoryName: categoryName ?? '',
quantitySold: quantitySold ?? 0,
revenue: revenue ?? 0,
averagePrice: averagePrice ?? 0.0,
orderCount: orderCount ?? 0,
);
}
@freezed
class DashboardPaymentMethodDto with _$DashboardPaymentMethodDto {
const DashboardPaymentMethodDto._();
const factory DashboardPaymentMethodDto({
@JsonKey(name: "payment_method_id") String? paymentMethodId,
@JsonKey(name: "payment_method_name") String? paymentMethodName,
@JsonKey(name: "payment_method_type") String? paymentMethodType,
@JsonKey(name: "total_amount") int? totalAmount,
@JsonKey(name: "order_count") int? orderCount,
@JsonKey(name: "payment_count") int? paymentCount,
@JsonKey(name: "percentage") double? percentage,
}) = _DashboardPaymentMethodDto;
factory DashboardPaymentMethodDto.fromJson(Map<String, dynamic> json) =>
_$DashboardPaymentMethodDtoFromJson(json);
// Optional mapping ke domain
DashboardPaymentMethod toDomain() => DashboardPaymentMethod(
paymentMethodId: paymentMethodId ?? '',
paymentMethodName: paymentMethodName ?? '',
paymentMethodType: paymentMethodType ?? '',
totalAmount: totalAmount ?? 0,
orderCount: orderCount ?? 0,
paymentCount: paymentCount ?? 0,
percentage: percentage ?? 0.0,
);
}
@freezed
class DashboardRecentSaleDto with _$DashboardRecentSaleDto {
const DashboardRecentSaleDto._();
const factory DashboardRecentSaleDto({
@JsonKey(name: "date") String? date,
@JsonKey(name: "sales") int? sales,
@JsonKey(name: "orders") int? orders,
@JsonKey(name: "items") int? items,
@JsonKey(name: "tax") int? tax,
@JsonKey(name: "discount") int? discount,
@JsonKey(name: "net_sales") int? netSales,
}) = _DashboardRecentSaleDto;
factory DashboardRecentSaleDto.fromJson(Map<String, dynamic> json) =>
_$DashboardRecentSaleDtoFromJson(json);
// Optional mapping ke domain
DashboardRecentSale toDomain() => DashboardRecentSale(
date: date ?? '',
sales: sales ?? 0,
orders: orders ?? 0,
items: items ?? 0,
tax: tax ?? 0,
discount: discount ?? 0,
netSales: netSales ?? 0,
);
}
@@ -0,0 +1,40 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/analytic/analytic.dart';
import '../datasources/remote_data_provider.dart';
@Injectable(as: IAnalyticRepository)
class AnalyticRepository implements IAnalyticRepository {
final AnalyticRemoteDataProvider _dataProvider;
final _logName = 'AnalyticRepository';
AnalyticRepository(this._dataProvider);
@override
Future<Either<AnalyticFailure, DashboardAnalytic>> getDashboard({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
try {
final result = await _dataProvider.fetchDashboard(
dateFrom: dateFrom,
dateTo: dateTo,
);
if (result.hasError) {
return left(result.error!);
}
final dashboard = result.data!.toDomain();
return right(dashboard);
} catch (e) {
log('getDashboardError', name: _logName, error: e);
return left(const AnalyticFailure.unexpectedError());
}
}
}