feat: sales analytic
This commit is contained in:
@@ -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 'dto/sales_analytic_dto.dart';
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'analytic_dtos.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$SalesAnalyticDtoImpl _$$SalesAnalyticDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$SalesAnalyticDtoImpl(
|
||||
organizationId: json['organization_id'] as String?,
|
||||
outletId: json['outlet_id'] as String?,
|
||||
dateFrom: json['date_from'] == null
|
||||
? null
|
||||
: DateTime.parse(json['date_from'] as String),
|
||||
dateTo: json['date_to'] == null
|
||||
? null
|
||||
: DateTime.parse(json['date_to'] as String),
|
||||
groupBy: json['group_by'] as String?,
|
||||
summary: json['summary'] == null
|
||||
? null
|
||||
: SalesAnalyticSummaryDto.fromJson(
|
||||
json['summary'] as Map<String, dynamic>,
|
||||
),
|
||||
data: (json['data'] as List<dynamic>?)
|
||||
?.map((e) => SalesAnalyticDataDto.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SalesAnalyticDtoImplToJson(
|
||||
_$SalesAnalyticDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'organization_id': instance.organizationId,
|
||||
'outlet_id': instance.outletId,
|
||||
'date_from': instance.dateFrom?.toIso8601String(),
|
||||
'date_to': instance.dateTo?.toIso8601String(),
|
||||
'group_by': instance.groupBy,
|
||||
'summary': instance.summary,
|
||||
'data': instance.data,
|
||||
};
|
||||
|
||||
_$SalesAnalyticSummaryDtoImpl _$$SalesAnalyticSummaryDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$SalesAnalyticSummaryDtoImpl(
|
||||
totalSales: json['total_sales'] as num?,
|
||||
totalOrders: json['total_orders'] as num?,
|
||||
totalItems: json['total_items'] as num?,
|
||||
averageOrderValue: json['average_order_value'] as num?,
|
||||
totalTax: json['total_tax'] as num?,
|
||||
totalDiscount: json['total_discount'] as num?,
|
||||
netSales: json['net_sales'] as num?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SalesAnalyticSummaryDtoImplToJson(
|
||||
_$SalesAnalyticSummaryDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'total_sales': instance.totalSales,
|
||||
'total_orders': instance.totalOrders,
|
||||
'total_items': instance.totalItems,
|
||||
'average_order_value': instance.averageOrderValue,
|
||||
'total_tax': instance.totalTax,
|
||||
'total_discount': instance.totalDiscount,
|
||||
'net_sales': instance.netSales,
|
||||
};
|
||||
|
||||
_$SalesAnalyticDataDtoImpl _$$SalesAnalyticDataDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$SalesAnalyticDataDtoImpl(
|
||||
date: json['date'] == null ? null : DateTime.parse(json['date'] as String),
|
||||
sales: json['sales'] as num?,
|
||||
orders: json['orders'] as num?,
|
||||
items: json['items'] as num?,
|
||||
tax: json['tax'] as num?,
|
||||
discount: json['discount'] as num?,
|
||||
netSales: json['net_sales'] as num?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SalesAnalyticDataDtoImplToJson(
|
||||
_$SalesAnalyticDataDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'date': instance.date?.toIso8601String(),
|
||||
'sales': instance.sales,
|
||||
'orders': instance.orders,
|
||||
'items': instance.items,
|
||||
'tax': instance.tax,
|
||||
'discount': instance.discount,
|
||||
'net_sales': instance.netSales,
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
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/url/api_path.dart';
|
||||
import '../../../domain/analytic/analytic.dart';
|
||||
import '../analytic_dtos.dart';
|
||||
|
||||
@injectable
|
||||
class AnalyticRemoteDataProvider {
|
||||
final ApiClient _apiClient;
|
||||
final String _logName = "AnalyticRemoteDataProvider";
|
||||
|
||||
AnalyticRemoteDataProvider(this._apiClient);
|
||||
|
||||
Future<DC<AnalyticFailure, SalesAnalyticDto>> fetchSales({
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.get(
|
||||
ApiPath.salesAnalytic,
|
||||
params: {
|
||||
'date_from': dateFrom.toServerDate,
|
||||
'date_to': dateTo.toServerDate,
|
||||
},
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(AnalyticFailure.empty());
|
||||
}
|
||||
|
||||
final dto = SalesAnalyticDto.fromJson(response.data['data']);
|
||||
|
||||
return DC.data(dto);
|
||||
} on ApiFailure catch (e, s) {
|
||||
log('fetchSalesError', name: _logName, error: e, stackTrace: s);
|
||||
return DC.error(AnalyticFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
part of '../analytic_dtos.dart';
|
||||
|
||||
@freezed
|
||||
class SalesAnalyticDto with _$SalesAnalyticDto {
|
||||
const SalesAnalyticDto._();
|
||||
|
||||
const factory SalesAnalyticDto({
|
||||
@JsonKey(name: 'organization_id') String? organizationId,
|
||||
@JsonKey(name: 'outlet_id') String? outletId,
|
||||
@JsonKey(name: 'date_from') DateTime? dateFrom,
|
||||
@JsonKey(name: 'date_to') DateTime? dateTo,
|
||||
@JsonKey(name: 'group_by') String? groupBy,
|
||||
@JsonKey(name: 'summary') SalesAnalyticSummaryDto? summary,
|
||||
@JsonKey(name: 'data') List<SalesAnalyticDataDto>? data,
|
||||
}) = _SalesAnalyticDto;
|
||||
|
||||
factory SalesAnalyticDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$SalesAnalyticDtoFromJson(json);
|
||||
|
||||
SalesAnalytic toDomain() => SalesAnalytic(
|
||||
organizationId: organizationId ?? '',
|
||||
outletId: outletId ?? '',
|
||||
dateFrom: dateFrom ?? DateTime.fromMillisecondsSinceEpoch(0),
|
||||
dateTo: dateTo ?? DateTime.fromMillisecondsSinceEpoch(0),
|
||||
groupBy: groupBy ?? '',
|
||||
summary: summary?.toDomain() ?? SalesAnalyticSummary.empty(),
|
||||
data: data?.map((e) => e.toDomain()).toList() ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SalesAnalyticSummaryDto with _$SalesAnalyticSummaryDto {
|
||||
const SalesAnalyticSummaryDto._();
|
||||
|
||||
const factory SalesAnalyticSummaryDto({
|
||||
@JsonKey(name: 'total_sales') num? totalSales,
|
||||
@JsonKey(name: 'total_orders') num? totalOrders,
|
||||
@JsonKey(name: 'total_items') num? totalItems,
|
||||
@JsonKey(name: 'average_order_value') num? averageOrderValue,
|
||||
@JsonKey(name: 'total_tax') num? totalTax,
|
||||
@JsonKey(name: 'total_discount') num? totalDiscount,
|
||||
@JsonKey(name: 'net_sales') num? netSales,
|
||||
}) = _SalesAnalyticSummaryDto;
|
||||
|
||||
factory SalesAnalyticSummaryDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$SalesAnalyticSummaryDtoFromJson(json);
|
||||
|
||||
SalesAnalyticSummary toDomain() => SalesAnalyticSummary(
|
||||
totalSales: totalSales?.toInt() ?? 0,
|
||||
totalOrders: totalOrders?.toInt() ?? 0,
|
||||
totalItems: totalItems?.toInt() ?? 0,
|
||||
averageOrderValue: averageOrderValue?.toDouble() ?? 0,
|
||||
totalTax: totalTax?.toInt() ?? 0,
|
||||
totalDiscount: totalDiscount?.toInt() ?? 0,
|
||||
netSales: netSales?.toInt() ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SalesAnalyticDataDto with _$SalesAnalyticDataDto {
|
||||
const SalesAnalyticDataDto._();
|
||||
|
||||
const factory SalesAnalyticDataDto({
|
||||
@JsonKey(name: 'date') DateTime? date,
|
||||
@JsonKey(name: 'sales') num? sales,
|
||||
@JsonKey(name: 'orders') num? orders,
|
||||
@JsonKey(name: 'items') num? items,
|
||||
@JsonKey(name: 'tax') num? tax,
|
||||
@JsonKey(name: 'discount') num? discount,
|
||||
@JsonKey(name: 'net_sales') num? netSales,
|
||||
}) = _SalesAnalyticDataDto;
|
||||
|
||||
factory SalesAnalyticDataDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$SalesAnalyticDataDtoFromJson(json);
|
||||
|
||||
SalesAnalyticData toDomain() => SalesAnalyticData(
|
||||
date: date ?? DateTime.fromMillisecondsSinceEpoch(0),
|
||||
sales: sales?.toInt() ?? 0,
|
||||
orders: orders?.toInt() ?? 0,
|
||||
items: items?.toInt() ?? 0,
|
||||
tax: tax?.toInt() ?? 0,
|
||||
discount: discount?.toInt() ?? 0,
|
||||
netSales: netSales?.toInt() ?? 0,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/analytic/analytic.dart';
|
||||
import '../../../domain/analytic/repositories/i_analytic_repository.dart';
|
||||
import '../datasource/remote_data_provider.dart';
|
||||
|
||||
@Injectable(as: IAnalyticRepository)
|
||||
class AnalyticRepository implements IAnalyticRepository {
|
||||
final AnalyticRemoteDataProvider _dataProvider;
|
||||
final String _logName = 'AnalyticRepository';
|
||||
|
||||
AnalyticRepository(this._dataProvider);
|
||||
|
||||
@override
|
||||
Future<Either<AnalyticFailure, SalesAnalytic>> getSales({
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.fetchSales(
|
||||
dateFrom: dateFrom,
|
||||
dateTo: dateTo,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
return left(result.error!);
|
||||
}
|
||||
|
||||
final auth = result.data!.toDomain();
|
||||
|
||||
return right(auth);
|
||||
} catch (e, s) {
|
||||
log('getSalesError', name: _logName, error: e, stackTrace: s);
|
||||
return left(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user