From d58198e7f017a14cefcd067acebe9fc9152037f5 Mon Sep 17 00:00:00 2001 From: efrilm Date: Mon, 18 Aug 2025 02:13:11 +0700 Subject: [PATCH] feat: product analytic repo --- .../product_analytic_loader_bloc.dart | 49 ++ .../product_analytic_loader_bloc.freezed.dart | 385 +++++++++++ .../product_analytic_loader_event.dart | 6 + .../product_analytic_loader_state.dart | 15 + lib/common/url/api_path.dart | 1 + lib/domain/analytic/analytic.dart | 1 + lib/domain/analytic/analytic.freezed.dart | 546 +++++++++++++++ .../entities/product_analytic_entity.dart | 45 ++ .../repositories/i_analytic_repository.dart | 5 + .../analytic/analytic_dtos.dart | 1 + .../analytic/analytic_dtos.freezed.dart | 627 ++++++++++++++++++ .../analytic/analytic_dtos.g.dart | 48 ++ .../datasource/remote_data_provider.dart | 28 + .../analytic/dto/product_analytic_dto.dart | 55 ++ .../repositories/analytic_repository.dart | 27 + lib/injection.config.dart | 5 + lib/presentation/router/app_router.gr.dart | 2 +- 17 files changed, 1845 insertions(+), 1 deletion(-) create mode 100644 lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart create mode 100644 lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.freezed.dart create mode 100644 lib/application/analytic/product_analytic_loader/product_analytic_loader_event.dart create mode 100644 lib/application/analytic/product_analytic_loader/product_analytic_loader_state.dart create mode 100644 lib/domain/analytic/entities/product_analytic_entity.dart create mode 100644 lib/infrastructure/analytic/dto/product_analytic_dto.dart diff --git a/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart b/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart new file mode 100644 index 0000000..877407c --- /dev/null +++ b/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart @@ -0,0 +1,49 @@ +import 'package:dartz/dartz.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:injectable/injectable.dart'; + +import '../../../domain/analytic/analytic.dart'; +import '../../../domain/analytic/repositories/i_analytic_repository.dart'; + +part 'product_analytic_loader_event.dart'; +part 'product_analytic_loader_state.dart'; +part 'product_analytic_loader_bloc.freezed.dart'; + +@injectable +class ProductAnalyticLoaderBloc + extends Bloc { + final IAnalyticRepository _repository; + ProductAnalyticLoaderBloc(this._repository) + : super(ProductAnalyticLoaderState.initial()) { + on(_onProductAnalyticLoaderEvent); + } + + Future _onProductAnalyticLoaderEvent( + ProductAnalyticLoaderEvent event, + Emitter emit, + ) { + return event.map( + fetched: (e) async { + emit( + state.copyWith( + isFetching: true, + failureOptionProductAnalytic: none(), + ), + ); + + final result = await _repository.getProduct( + dateFrom: DateTime.now().subtract(const Duration(days: 30)), + dateTo: DateTime.now(), + ); + + var data = result.fold( + (f) => state.copyWith(failureOptionProductAnalytic: optionOf(f)), + (productAnalytic) => state.copyWith(productAnalytic: productAnalytic), + ); + + emit(data.copyWith(isFetching: false)); + }, + ); + } +} diff --git a/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.freezed.dart b/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.freezed.dart new file mode 100644 index 0000000..d35c1aa --- /dev/null +++ b/lib/application/analytic/product_analytic_loader/product_analytic_loader_bloc.freezed.dart @@ -0,0 +1,385 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'product_analytic_loader_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); + +/// @nodoc +mixin _$ProductAnalyticLoaderEvent { + @optionalTypeArgs + TResult when({ + required TResult Function() fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? fetched, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Fetched value) fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Fetched value)? fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Fetched value)? fetched, + required TResult orElse(), + }) => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProductAnalyticLoaderEventCopyWith<$Res> { + factory $ProductAnalyticLoaderEventCopyWith( + ProductAnalyticLoaderEvent value, + $Res Function(ProductAnalyticLoaderEvent) then, + ) = + _$ProductAnalyticLoaderEventCopyWithImpl< + $Res, + ProductAnalyticLoaderEvent + >; +} + +/// @nodoc +class _$ProductAnalyticLoaderEventCopyWithImpl< + $Res, + $Val extends ProductAnalyticLoaderEvent +> + implements $ProductAnalyticLoaderEventCopyWith<$Res> { + _$ProductAnalyticLoaderEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ProductAnalyticLoaderEvent + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$FetchedImplCopyWith<$Res> { + factory _$$FetchedImplCopyWith( + _$FetchedImpl value, + $Res Function(_$FetchedImpl) then, + ) = __$$FetchedImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$FetchedImplCopyWithImpl<$Res> + extends _$ProductAnalyticLoaderEventCopyWithImpl<$Res, _$FetchedImpl> + implements _$$FetchedImplCopyWith<$Res> { + __$$FetchedImplCopyWithImpl( + _$FetchedImpl _value, + $Res Function(_$FetchedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ProductAnalyticLoaderEvent + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$FetchedImpl implements _Fetched { + const _$FetchedImpl(); + + @override + String toString() { + return 'ProductAnalyticLoaderEvent.fetched()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$FetchedImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({required TResult Function() fetched}) { + return fetched(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({TResult? Function()? fetched}) { + return fetched?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? fetched, + required TResult orElse(), + }) { + if (fetched != null) { + return fetched(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Fetched value) fetched, + }) { + return fetched(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Fetched value)? fetched, + }) { + return fetched?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Fetched value)? fetched, + required TResult orElse(), + }) { + if (fetched != null) { + return fetched(this); + } + return orElse(); + } +} + +abstract class _Fetched implements ProductAnalyticLoaderEvent { + const factory _Fetched() = _$FetchedImpl; +} + +/// @nodoc +mixin _$ProductAnalyticLoaderState { + ProductAnalytic get productAnalytic => throw _privateConstructorUsedError; + dynamic get failureOptionProductAnalytic => + throw _privateConstructorUsedError; + bool get isFetching => throw _privateConstructorUsedError; + + /// Create a copy of ProductAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ProductAnalyticLoaderStateCopyWith + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProductAnalyticLoaderStateCopyWith<$Res> { + factory $ProductAnalyticLoaderStateCopyWith( + ProductAnalyticLoaderState value, + $Res Function(ProductAnalyticLoaderState) then, + ) = + _$ProductAnalyticLoaderStateCopyWithImpl< + $Res, + ProductAnalyticLoaderState + >; + @useResult + $Res call({ + ProductAnalytic productAnalytic, + dynamic failureOptionProductAnalytic, + bool isFetching, + }); +} + +/// @nodoc +class _$ProductAnalyticLoaderStateCopyWithImpl< + $Res, + $Val extends ProductAnalyticLoaderState +> + implements $ProductAnalyticLoaderStateCopyWith<$Res> { + _$ProductAnalyticLoaderStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ProductAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? productAnalytic = freezed, + Object? failureOptionProductAnalytic = freezed, + Object? isFetching = null, + }) { + return _then( + _value.copyWith( + productAnalytic: freezed == productAnalytic + ? _value.productAnalytic + : productAnalytic // ignore: cast_nullable_to_non_nullable + as ProductAnalytic, + failureOptionProductAnalytic: + freezed == failureOptionProductAnalytic + ? _value.failureOptionProductAnalytic + : failureOptionProductAnalytic // ignore: cast_nullable_to_non_nullable + as dynamic, + isFetching: null == isFetching + ? _value.isFetching + : isFetching // ignore: cast_nullable_to_non_nullable + as bool, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ProductAnalyticLoaderStateImplCopyWith<$Res> + implements $ProductAnalyticLoaderStateCopyWith<$Res> { + factory _$$ProductAnalyticLoaderStateImplCopyWith( + _$ProductAnalyticLoaderStateImpl value, + $Res Function(_$ProductAnalyticLoaderStateImpl) then, + ) = __$$ProductAnalyticLoaderStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + ProductAnalytic productAnalytic, + dynamic failureOptionProductAnalytic, + bool isFetching, + }); +} + +/// @nodoc +class __$$ProductAnalyticLoaderStateImplCopyWithImpl<$Res> + extends + _$ProductAnalyticLoaderStateCopyWithImpl< + $Res, + _$ProductAnalyticLoaderStateImpl + > + implements _$$ProductAnalyticLoaderStateImplCopyWith<$Res> { + __$$ProductAnalyticLoaderStateImplCopyWithImpl( + _$ProductAnalyticLoaderStateImpl _value, + $Res Function(_$ProductAnalyticLoaderStateImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ProductAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? productAnalytic = freezed, + Object? failureOptionProductAnalytic = freezed, + Object? isFetching = null, + }) { + return _then( + _$ProductAnalyticLoaderStateImpl( + productAnalytic: freezed == productAnalytic + ? _value.productAnalytic + : productAnalytic // ignore: cast_nullable_to_non_nullable + as ProductAnalytic, + failureOptionProductAnalytic: freezed == failureOptionProductAnalytic + ? _value.failureOptionProductAnalytic! + : failureOptionProductAnalytic, + isFetching: null == isFetching + ? _value.isFetching + : isFetching // ignore: cast_nullable_to_non_nullable + as bool, + ), + ); + } +} + +/// @nodoc + +class _$ProductAnalyticLoaderStateImpl implements _ProductAnalyticLoaderState { + const _$ProductAnalyticLoaderStateImpl({ + required this.productAnalytic, + required this.failureOptionProductAnalytic, + this.isFetching = false, + }); + + @override + final ProductAnalytic productAnalytic; + @override + final dynamic failureOptionProductAnalytic; + @override + @JsonKey() + final bool isFetching; + + @override + String toString() { + return 'ProductAnalyticLoaderState(productAnalytic: $productAnalytic, failureOptionProductAnalytic: $failureOptionProductAnalytic, isFetching: $isFetching)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProductAnalyticLoaderStateImpl && + const DeepCollectionEquality().equals( + other.productAnalytic, + productAnalytic, + ) && + const DeepCollectionEquality().equals( + other.failureOptionProductAnalytic, + failureOptionProductAnalytic, + ) && + (identical(other.isFetching, isFetching) || + other.isFetching == isFetching)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(productAnalytic), + const DeepCollectionEquality().hash(failureOptionProductAnalytic), + isFetching, + ); + + /// Create a copy of ProductAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProductAnalyticLoaderStateImplCopyWith<_$ProductAnalyticLoaderStateImpl> + get copyWith => + __$$ProductAnalyticLoaderStateImplCopyWithImpl< + _$ProductAnalyticLoaderStateImpl + >(this, _$identity); +} + +abstract class _ProductAnalyticLoaderState + implements ProductAnalyticLoaderState { + const factory _ProductAnalyticLoaderState({ + required final ProductAnalytic productAnalytic, + required final dynamic failureOptionProductAnalytic, + final bool isFetching, + }) = _$ProductAnalyticLoaderStateImpl; + + @override + ProductAnalytic get productAnalytic; + @override + dynamic get failureOptionProductAnalytic; + @override + bool get isFetching; + + /// Create a copy of ProductAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProductAnalyticLoaderStateImplCopyWith<_$ProductAnalyticLoaderStateImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/application/analytic/product_analytic_loader/product_analytic_loader_event.dart b/lib/application/analytic/product_analytic_loader/product_analytic_loader_event.dart new file mode 100644 index 0000000..58e9c7f --- /dev/null +++ b/lib/application/analytic/product_analytic_loader/product_analytic_loader_event.dart @@ -0,0 +1,6 @@ +part of 'product_analytic_loader_bloc.dart'; + +@freezed +class ProductAnalyticLoaderEvent with _$ProductAnalyticLoaderEvent { + const factory ProductAnalyticLoaderEvent.fetched() = _Fetched; +} diff --git a/lib/application/analytic/product_analytic_loader/product_analytic_loader_state.dart b/lib/application/analytic/product_analytic_loader/product_analytic_loader_state.dart new file mode 100644 index 0000000..23dfa16 --- /dev/null +++ b/lib/application/analytic/product_analytic_loader/product_analytic_loader_state.dart @@ -0,0 +1,15 @@ +part of 'product_analytic_loader_bloc.dart'; + +@freezed +class ProductAnalyticLoaderState with _$ProductAnalyticLoaderState { + const factory ProductAnalyticLoaderState({ + required ProductAnalytic productAnalytic, + required Option failureOptionProductAnalytic, + @Default(false) bool isFetching, + }) = _ProductAnalyticLoaderState; + + factory ProductAnalyticLoaderState.initial() => ProductAnalyticLoaderState( + productAnalytic: ProductAnalytic.empty(), + failureOptionProductAnalytic: none(), + ); +} diff --git a/lib/common/url/api_path.dart b/lib/common/url/api_path.dart index 9a84378..4f8bee7 100644 --- a/lib/common/url/api_path.dart +++ b/lib/common/url/api_path.dart @@ -8,6 +8,7 @@ class ApiPath { static const String profitLossAnalytic = '/api/v1/analytics/profit-loss'; static const String categoryAnalytic = '/api/v1/analytics/categories'; static const String dashboardAnalytic = '/api/v1/analytics/dashboard'; + static const String productAnalytic = '/api/v1/analytics/products'; // Inventory static const String inventoryReportDetail = diff --git a/lib/domain/analytic/analytic.dart b/lib/domain/analytic/analytic.dart index 7759997..99ab431 100644 --- a/lib/domain/analytic/analytic.dart +++ b/lib/domain/analytic/analytic.dart @@ -9,4 +9,5 @@ part 'entities/profit_loss_analytic_entity.dart'; part 'entities/category_analytic_entity.dart'; part 'entities/inventory_analytic_entity.dart'; part 'entities/dashboard_analytic_entity.dart'; +part 'entities/product_analytic_entity.dart'; part 'failures/analytic_failure.dart'; diff --git a/lib/domain/analytic/analytic.freezed.dart b/lib/domain/analytic/analytic.freezed.dart index 52f35a3..879b068 100644 --- a/lib/domain/analytic/analytic.freezed.dart +++ b/lib/domain/analytic/analytic.freezed.dart @@ -5723,6 +5723,552 @@ abstract class _DashboardRecentSale implements DashboardRecentSale { throw _privateConstructorUsedError; } +/// @nodoc +mixin _$ProductAnalytic { + String get organizationId => throw _privateConstructorUsedError; + String get outletId => throw _privateConstructorUsedError; + String get dateFrom => throw _privateConstructorUsedError; + String get dateTo => throw _privateConstructorUsedError; + List get data => throw _privateConstructorUsedError; + + /// Create a copy of ProductAnalytic + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ProductAnalyticCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProductAnalyticCopyWith<$Res> { + factory $ProductAnalyticCopyWith( + ProductAnalytic value, + $Res Function(ProductAnalytic) then, + ) = _$ProductAnalyticCopyWithImpl<$Res, ProductAnalytic>; + @useResult + $Res call({ + String organizationId, + String outletId, + String dateFrom, + String dateTo, + List data, + }); +} + +/// @nodoc +class _$ProductAnalyticCopyWithImpl<$Res, $Val extends ProductAnalytic> + implements $ProductAnalyticCopyWith<$Res> { + _$ProductAnalyticCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ProductAnalytic + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? organizationId = null, + Object? outletId = null, + Object? dateFrom = null, + Object? dateTo = null, + Object? data = null, + }) { + return _then( + _value.copyWith( + organizationId: null == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String, + outletId: null == outletId + ? _value.outletId + : outletId // ignore: cast_nullable_to_non_nullable + as String, + dateFrom: null == dateFrom + ? _value.dateFrom + : dateFrom // ignore: cast_nullable_to_non_nullable + as String, + dateTo: null == dateTo + ? _value.dateTo + : dateTo // ignore: cast_nullable_to_non_nullable + as String, + data: null == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as List, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ProductAnalyticImplCopyWith<$Res> + implements $ProductAnalyticCopyWith<$Res> { + factory _$$ProductAnalyticImplCopyWith( + _$ProductAnalyticImpl value, + $Res Function(_$ProductAnalyticImpl) then, + ) = __$$ProductAnalyticImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + String organizationId, + String outletId, + String dateFrom, + String dateTo, + List data, + }); +} + +/// @nodoc +class __$$ProductAnalyticImplCopyWithImpl<$Res> + extends _$ProductAnalyticCopyWithImpl<$Res, _$ProductAnalyticImpl> + implements _$$ProductAnalyticImplCopyWith<$Res> { + __$$ProductAnalyticImplCopyWithImpl( + _$ProductAnalyticImpl _value, + $Res Function(_$ProductAnalyticImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ProductAnalytic + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? organizationId = null, + Object? outletId = null, + Object? dateFrom = null, + Object? dateTo = null, + Object? data = null, + }) { + return _then( + _$ProductAnalyticImpl( + organizationId: null == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String, + outletId: null == outletId + ? _value.outletId + : outletId // ignore: cast_nullable_to_non_nullable + as String, + dateFrom: null == dateFrom + ? _value.dateFrom + : dateFrom // ignore: cast_nullable_to_non_nullable + as String, + dateTo: null == dateTo + ? _value.dateTo + : dateTo // ignore: cast_nullable_to_non_nullable + as String, + data: null == data + ? _value._data + : data // ignore: cast_nullable_to_non_nullable + as List, + ), + ); + } +} + +/// @nodoc + +class _$ProductAnalyticImpl implements _ProductAnalytic { + const _$ProductAnalyticImpl({ + required this.organizationId, + required this.outletId, + required this.dateFrom, + required this.dateTo, + required final List data, + }) : _data = data; + + @override + final String organizationId; + @override + final String outletId; + @override + final String dateFrom; + @override + final String dateTo; + final List _data; + @override + List get data { + if (_data is EqualUnmodifiableListView) return _data; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_data); + } + + @override + String toString() { + return 'ProductAnalytic(organizationId: $organizationId, outletId: $outletId, dateFrom: $dateFrom, dateTo: $dateTo, data: $data)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProductAnalyticImpl && + (identical(other.organizationId, organizationId) || + other.organizationId == organizationId) && + (identical(other.outletId, outletId) || + other.outletId == outletId) && + (identical(other.dateFrom, dateFrom) || + other.dateFrom == dateFrom) && + (identical(other.dateTo, dateTo) || other.dateTo == dateTo) && + const DeepCollectionEquality().equals(other._data, _data)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + organizationId, + outletId, + dateFrom, + dateTo, + const DeepCollectionEquality().hash(_data), + ); + + /// Create a copy of ProductAnalytic + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProductAnalyticImplCopyWith<_$ProductAnalyticImpl> get copyWith => + __$$ProductAnalyticImplCopyWithImpl<_$ProductAnalyticImpl>( + this, + _$identity, + ); +} + +abstract class _ProductAnalytic implements ProductAnalytic { + const factory _ProductAnalytic({ + required final String organizationId, + required final String outletId, + required final String dateFrom, + required final String dateTo, + required final List data, + }) = _$ProductAnalyticImpl; + + @override + String get organizationId; + @override + String get outletId; + @override + String get dateFrom; + @override + String get dateTo; + @override + List get data; + + /// Create a copy of ProductAnalytic + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProductAnalyticImplCopyWith<_$ProductAnalyticImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$ProductAnalyticData { + String get productId => throw _privateConstructorUsedError; + String get productName => throw _privateConstructorUsedError; + String get categoryId => throw _privateConstructorUsedError; + String get categoryName => throw _privateConstructorUsedError; + int get quantitySold => throw _privateConstructorUsedError; + double get revenue => throw _privateConstructorUsedError; + double get averagePrice => throw _privateConstructorUsedError; + int get orderCount => throw _privateConstructorUsedError; + + /// Create a copy of ProductAnalyticData + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ProductAnalyticDataCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProductAnalyticDataCopyWith<$Res> { + factory $ProductAnalyticDataCopyWith( + ProductAnalyticData value, + $Res Function(ProductAnalyticData) then, + ) = _$ProductAnalyticDataCopyWithImpl<$Res, ProductAnalyticData>; + @useResult + $Res call({ + String productId, + String productName, + String categoryId, + String categoryName, + int quantitySold, + double revenue, + double averagePrice, + int orderCount, + }); +} + +/// @nodoc +class _$ProductAnalyticDataCopyWithImpl<$Res, $Val extends ProductAnalyticData> + implements $ProductAnalyticDataCopyWith<$Res> { + _$ProductAnalyticDataCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ProductAnalyticData + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? productId = null, + Object? productName = null, + Object? categoryId = null, + Object? categoryName = null, + Object? quantitySold = null, + Object? revenue = null, + Object? averagePrice = null, + Object? orderCount = null, + }) { + return _then( + _value.copyWith( + productId: null == productId + ? _value.productId + : productId // ignore: cast_nullable_to_non_nullable + as String, + productName: null == productName + ? _value.productName + : productName // ignore: cast_nullable_to_non_nullable + as String, + categoryId: null == categoryId + ? _value.categoryId + : categoryId // ignore: cast_nullable_to_non_nullable + as String, + categoryName: null == categoryName + ? _value.categoryName + : categoryName // ignore: cast_nullable_to_non_nullable + as String, + quantitySold: null == quantitySold + ? _value.quantitySold + : quantitySold // ignore: cast_nullable_to_non_nullable + as int, + revenue: null == revenue + ? _value.revenue + : revenue // ignore: cast_nullable_to_non_nullable + as double, + averagePrice: null == averagePrice + ? _value.averagePrice + : averagePrice // ignore: cast_nullable_to_non_nullable + as double, + orderCount: null == orderCount + ? _value.orderCount + : orderCount // ignore: cast_nullable_to_non_nullable + as int, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ProductAnalyticDataImplCopyWith<$Res> + implements $ProductAnalyticDataCopyWith<$Res> { + factory _$$ProductAnalyticDataImplCopyWith( + _$ProductAnalyticDataImpl value, + $Res Function(_$ProductAnalyticDataImpl) then, + ) = __$$ProductAnalyticDataImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + String productId, + String productName, + String categoryId, + String categoryName, + int quantitySold, + double revenue, + double averagePrice, + int orderCount, + }); +} + +/// @nodoc +class __$$ProductAnalyticDataImplCopyWithImpl<$Res> + extends _$ProductAnalyticDataCopyWithImpl<$Res, _$ProductAnalyticDataImpl> + implements _$$ProductAnalyticDataImplCopyWith<$Res> { + __$$ProductAnalyticDataImplCopyWithImpl( + _$ProductAnalyticDataImpl _value, + $Res Function(_$ProductAnalyticDataImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ProductAnalyticData + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? productId = null, + Object? productName = null, + Object? categoryId = null, + Object? categoryName = null, + Object? quantitySold = null, + Object? revenue = null, + Object? averagePrice = null, + Object? orderCount = null, + }) { + return _then( + _$ProductAnalyticDataImpl( + productId: null == productId + ? _value.productId + : productId // ignore: cast_nullable_to_non_nullable + as String, + productName: null == productName + ? _value.productName + : productName // ignore: cast_nullable_to_non_nullable + as String, + categoryId: null == categoryId + ? _value.categoryId + : categoryId // ignore: cast_nullable_to_non_nullable + as String, + categoryName: null == categoryName + ? _value.categoryName + : categoryName // ignore: cast_nullable_to_non_nullable + as String, + quantitySold: null == quantitySold + ? _value.quantitySold + : quantitySold // ignore: cast_nullable_to_non_nullable + as int, + revenue: null == revenue + ? _value.revenue + : revenue // ignore: cast_nullable_to_non_nullable + as double, + averagePrice: null == averagePrice + ? _value.averagePrice + : averagePrice // ignore: cast_nullable_to_non_nullable + as double, + orderCount: null == orderCount + ? _value.orderCount + : orderCount // ignore: cast_nullable_to_non_nullable + as int, + ), + ); + } +} + +/// @nodoc + +class _$ProductAnalyticDataImpl implements _ProductAnalyticData { + const _$ProductAnalyticDataImpl({ + required this.productId, + required this.productName, + required this.categoryId, + required this.categoryName, + required this.quantitySold, + required this.revenue, + required this.averagePrice, + required this.orderCount, + }); + + @override + final String productId; + @override + final String productName; + @override + final String categoryId; + @override + final String categoryName; + @override + final int quantitySold; + @override + final double revenue; + @override + final double averagePrice; + @override + final int orderCount; + + @override + String toString() { + return 'ProductAnalyticData(productId: $productId, productName: $productName, categoryId: $categoryId, categoryName: $categoryName, quantitySold: $quantitySold, revenue: $revenue, averagePrice: $averagePrice, orderCount: $orderCount)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProductAnalyticDataImpl && + (identical(other.productId, productId) || + other.productId == productId) && + (identical(other.productName, productName) || + other.productName == productName) && + (identical(other.categoryId, categoryId) || + other.categoryId == categoryId) && + (identical(other.categoryName, categoryName) || + other.categoryName == categoryName) && + (identical(other.quantitySold, quantitySold) || + other.quantitySold == quantitySold) && + (identical(other.revenue, revenue) || other.revenue == revenue) && + (identical(other.averagePrice, averagePrice) || + other.averagePrice == averagePrice) && + (identical(other.orderCount, orderCount) || + other.orderCount == orderCount)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + productId, + productName, + categoryId, + categoryName, + quantitySold, + revenue, + averagePrice, + orderCount, + ); + + /// Create a copy of ProductAnalyticData + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProductAnalyticDataImplCopyWith<_$ProductAnalyticDataImpl> get copyWith => + __$$ProductAnalyticDataImplCopyWithImpl<_$ProductAnalyticDataImpl>( + this, + _$identity, + ); +} + +abstract class _ProductAnalyticData implements ProductAnalyticData { + const factory _ProductAnalyticData({ + required final String productId, + required final String productName, + required final String categoryId, + required final String categoryName, + required final int quantitySold, + required final double revenue, + required final double averagePrice, + required final int orderCount, + }) = _$ProductAnalyticDataImpl; + + @override + String get productId; + @override + String get productName; + @override + String get categoryId; + @override + String get categoryName; + @override + int get quantitySold; + @override + double get revenue; + @override + double get averagePrice; + @override + int get orderCount; + + /// Create a copy of ProductAnalyticData + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProductAnalyticDataImplCopyWith<_$ProductAnalyticDataImpl> get copyWith => + throw _privateConstructorUsedError; +} + /// @nodoc mixin _$AnalyticFailure { @optionalTypeArgs diff --git a/lib/domain/analytic/entities/product_analytic_entity.dart b/lib/domain/analytic/entities/product_analytic_entity.dart new file mode 100644 index 0000000..1b57062 --- /dev/null +++ b/lib/domain/analytic/entities/product_analytic_entity.dart @@ -0,0 +1,45 @@ +part of '../analytic.dart'; + +@freezed +class ProductAnalytic with _$ProductAnalytic { + const factory ProductAnalytic({ + required String organizationId, + required String outletId, + required String dateFrom, + required String dateTo, + required List data, + }) = _ProductAnalytic; + + factory ProductAnalytic.empty() => const ProductAnalytic( + organizationId: '', + outletId: '', + dateFrom: '', + dateTo: '', + data: [], + ); +} + +@freezed +class ProductAnalyticData with _$ProductAnalyticData { + const factory ProductAnalyticData({ + required String productId, + required String productName, + required String categoryId, + required String categoryName, + required int quantitySold, + required double revenue, + required double averagePrice, + required int orderCount, + }) = _ProductAnalyticData; + + factory ProductAnalyticData.empty() => const ProductAnalyticData( + productId: '', + productName: '', + categoryId: '', + categoryName: '', + quantitySold: 0, + revenue: 0.0, + averagePrice: 0.0, + orderCount: 0, + ); +} diff --git a/lib/domain/analytic/repositories/i_analytic_repository.dart b/lib/domain/analytic/repositories/i_analytic_repository.dart index 50a1a90..a2a0c99 100644 --- a/lib/domain/analytic/repositories/i_analytic_repository.dart +++ b/lib/domain/analytic/repositories/i_analytic_repository.dart @@ -27,4 +27,9 @@ abstract class IAnalyticRepository { required DateTime dateFrom, required DateTime dateTo, }); + + Future> getProduct({ + required DateTime dateFrom, + required DateTime dateTo, + }); } diff --git a/lib/infrastructure/analytic/analytic_dtos.dart b/lib/infrastructure/analytic/analytic_dtos.dart index a604c55..f5ae672 100644 --- a/lib/infrastructure/analytic/analytic_dtos.dart +++ b/lib/infrastructure/analytic/analytic_dtos.dart @@ -10,3 +10,4 @@ part 'dto/profit_loss_analytic_dto.dart'; part 'dto/category_analytic_dto.dart'; part 'dto/inventory_analytic_dto.dart'; part 'dto/dashboard_analytic_dto.dart'; +part 'dto/product_analytic_dto.dart'; diff --git a/lib/infrastructure/analytic/analytic_dtos.freezed.dart b/lib/infrastructure/analytic/analytic_dtos.freezed.dart index 2f5bbd5..3385538 100644 --- a/lib/infrastructure/analytic/analytic_dtos.freezed.dart +++ b/lib/infrastructure/analytic/analytic_dtos.freezed.dart @@ -6653,3 +6653,630 @@ abstract class _DashboardRecentSaleDto extends DashboardRecentSaleDto { _$$DashboardRecentSaleDtoImplCopyWith<_$DashboardRecentSaleDtoImpl> get copyWith => throw _privateConstructorUsedError; } + +ProductAnalyticDto _$ProductAnalyticDtoFromJson(Map json) { + return _ProductAnalyticDto.fromJson(json); +} + +/// @nodoc +mixin _$ProductAnalyticDto { + @JsonKey(name: 'organization_id') + String get organizationId => throw _privateConstructorUsedError; + @JsonKey(name: 'outlet_id') + String get outletId => throw _privateConstructorUsedError; + @JsonKey(name: 'date_from') + String get dateFrom => throw _privateConstructorUsedError; + @JsonKey(name: 'date_to') + String get dateTo => throw _privateConstructorUsedError; + List get data => throw _privateConstructorUsedError; + + /// Serializes this ProductAnalyticDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ProductAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ProductAnalyticDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProductAnalyticDtoCopyWith<$Res> { + factory $ProductAnalyticDtoCopyWith( + ProductAnalyticDto value, + $Res Function(ProductAnalyticDto) then, + ) = _$ProductAnalyticDtoCopyWithImpl<$Res, ProductAnalyticDto>; + @useResult + $Res call({ + @JsonKey(name: 'organization_id') String organizationId, + @JsonKey(name: 'outlet_id') String outletId, + @JsonKey(name: 'date_from') String dateFrom, + @JsonKey(name: 'date_to') String dateTo, + List data, + }); +} + +/// @nodoc +class _$ProductAnalyticDtoCopyWithImpl<$Res, $Val extends ProductAnalyticDto> + implements $ProductAnalyticDtoCopyWith<$Res> { + _$ProductAnalyticDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ProductAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? organizationId = null, + Object? outletId = null, + Object? dateFrom = null, + Object? dateTo = null, + Object? data = null, + }) { + return _then( + _value.copyWith( + organizationId: null == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String, + outletId: null == outletId + ? _value.outletId + : outletId // ignore: cast_nullable_to_non_nullable + as String, + dateFrom: null == dateFrom + ? _value.dateFrom + : dateFrom // ignore: cast_nullable_to_non_nullable + as String, + dateTo: null == dateTo + ? _value.dateTo + : dateTo // ignore: cast_nullable_to_non_nullable + as String, + data: null == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as List, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ProductAnalyticDtoImplCopyWith<$Res> + implements $ProductAnalyticDtoCopyWith<$Res> { + factory _$$ProductAnalyticDtoImplCopyWith( + _$ProductAnalyticDtoImpl value, + $Res Function(_$ProductAnalyticDtoImpl) then, + ) = __$$ProductAnalyticDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @JsonKey(name: 'organization_id') String organizationId, + @JsonKey(name: 'outlet_id') String outletId, + @JsonKey(name: 'date_from') String dateFrom, + @JsonKey(name: 'date_to') String dateTo, + List data, + }); +} + +/// @nodoc +class __$$ProductAnalyticDtoImplCopyWithImpl<$Res> + extends _$ProductAnalyticDtoCopyWithImpl<$Res, _$ProductAnalyticDtoImpl> + implements _$$ProductAnalyticDtoImplCopyWith<$Res> { + __$$ProductAnalyticDtoImplCopyWithImpl( + _$ProductAnalyticDtoImpl _value, + $Res Function(_$ProductAnalyticDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ProductAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? organizationId = null, + Object? outletId = null, + Object? dateFrom = null, + Object? dateTo = null, + Object? data = null, + }) { + return _then( + _$ProductAnalyticDtoImpl( + organizationId: null == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String, + outletId: null == outletId + ? _value.outletId + : outletId // ignore: cast_nullable_to_non_nullable + as String, + dateFrom: null == dateFrom + ? _value.dateFrom + : dateFrom // ignore: cast_nullable_to_non_nullable + as String, + dateTo: null == dateTo + ? _value.dateTo + : dateTo // ignore: cast_nullable_to_non_nullable + as String, + data: null == data + ? _value._data + : data // ignore: cast_nullable_to_non_nullable + as List, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$ProductAnalyticDtoImpl extends _ProductAnalyticDto { + const _$ProductAnalyticDtoImpl({ + @JsonKey(name: 'organization_id') required this.organizationId, + @JsonKey(name: 'outlet_id') required this.outletId, + @JsonKey(name: 'date_from') required this.dateFrom, + @JsonKey(name: 'date_to') required this.dateTo, + required final List data, + }) : _data = data, + super._(); + + factory _$ProductAnalyticDtoImpl.fromJson(Map json) => + _$$ProductAnalyticDtoImplFromJson(json); + + @override + @JsonKey(name: 'organization_id') + final String organizationId; + @override + @JsonKey(name: 'outlet_id') + final String outletId; + @override + @JsonKey(name: 'date_from') + final String dateFrom; + @override + @JsonKey(name: 'date_to') + final String dateTo; + final List _data; + @override + List get data { + if (_data is EqualUnmodifiableListView) return _data; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_data); + } + + @override + String toString() { + return 'ProductAnalyticDto(organizationId: $organizationId, outletId: $outletId, dateFrom: $dateFrom, dateTo: $dateTo, data: $data)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProductAnalyticDtoImpl && + (identical(other.organizationId, organizationId) || + other.organizationId == organizationId) && + (identical(other.outletId, outletId) || + other.outletId == outletId) && + (identical(other.dateFrom, dateFrom) || + other.dateFrom == dateFrom) && + (identical(other.dateTo, dateTo) || other.dateTo == dateTo) && + const DeepCollectionEquality().equals(other._data, _data)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + organizationId, + outletId, + dateFrom, + dateTo, + const DeepCollectionEquality().hash(_data), + ); + + /// Create a copy of ProductAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProductAnalyticDtoImplCopyWith<_$ProductAnalyticDtoImpl> get copyWith => + __$$ProductAnalyticDtoImplCopyWithImpl<_$ProductAnalyticDtoImpl>( + this, + _$identity, + ); + + @override + Map toJson() { + return _$$ProductAnalyticDtoImplToJson(this); + } +} + +abstract class _ProductAnalyticDto extends ProductAnalyticDto { + const factory _ProductAnalyticDto({ + @JsonKey(name: 'organization_id') required final String organizationId, + @JsonKey(name: 'outlet_id') required final String outletId, + @JsonKey(name: 'date_from') required final String dateFrom, + @JsonKey(name: 'date_to') required final String dateTo, + required final List data, + }) = _$ProductAnalyticDtoImpl; + const _ProductAnalyticDto._() : super._(); + + factory _ProductAnalyticDto.fromJson(Map json) = + _$ProductAnalyticDtoImpl.fromJson; + + @override + @JsonKey(name: 'organization_id') + String get organizationId; + @override + @JsonKey(name: 'outlet_id') + String get outletId; + @override + @JsonKey(name: 'date_from') + String get dateFrom; + @override + @JsonKey(name: 'date_to') + String get dateTo; + @override + List get data; + + /// Create a copy of ProductAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProductAnalyticDtoImplCopyWith<_$ProductAnalyticDtoImpl> get copyWith => + throw _privateConstructorUsedError; +} + +ProductAnalyticDataDto _$ProductAnalyticDataDtoFromJson( + Map json, +) { + return _ProductAnalyticDataDto.fromJson(json); +} + +/// @nodoc +mixin _$ProductAnalyticDataDto { + @JsonKey(name: 'product_id') + String get productId => throw _privateConstructorUsedError; + @JsonKey(name: 'product_name') + String get productName => throw _privateConstructorUsedError; + @JsonKey(name: 'category_id') + String get categoryId => throw _privateConstructorUsedError; + @JsonKey(name: 'category_name') + String get categoryName => throw _privateConstructorUsedError; + @JsonKey(name: 'quantity_sold') + int get quantitySold => throw _privateConstructorUsedError; + double get revenue => throw _privateConstructorUsedError; + @JsonKey(name: 'average_price') + double get averagePrice => throw _privateConstructorUsedError; + @JsonKey(name: 'order_count') + int get orderCount => throw _privateConstructorUsedError; + + /// Serializes this ProductAnalyticDataDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ProductAnalyticDataDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ProductAnalyticDataDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProductAnalyticDataDtoCopyWith<$Res> { + factory $ProductAnalyticDataDtoCopyWith( + ProductAnalyticDataDto value, + $Res Function(ProductAnalyticDataDto) then, + ) = _$ProductAnalyticDataDtoCopyWithImpl<$Res, ProductAnalyticDataDto>; + @useResult + $Res call({ + @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, + double revenue, + @JsonKey(name: 'average_price') double averagePrice, + @JsonKey(name: 'order_count') int orderCount, + }); +} + +/// @nodoc +class _$ProductAnalyticDataDtoCopyWithImpl< + $Res, + $Val extends ProductAnalyticDataDto +> + implements $ProductAnalyticDataDtoCopyWith<$Res> { + _$ProductAnalyticDataDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ProductAnalyticDataDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? productId = null, + Object? productName = null, + Object? categoryId = null, + Object? categoryName = null, + Object? quantitySold = null, + Object? revenue = null, + Object? averagePrice = null, + Object? orderCount = null, + }) { + return _then( + _value.copyWith( + productId: null == productId + ? _value.productId + : productId // ignore: cast_nullable_to_non_nullable + as String, + productName: null == productName + ? _value.productName + : productName // ignore: cast_nullable_to_non_nullable + as String, + categoryId: null == categoryId + ? _value.categoryId + : categoryId // ignore: cast_nullable_to_non_nullable + as String, + categoryName: null == categoryName + ? _value.categoryName + : categoryName // ignore: cast_nullable_to_non_nullable + as String, + quantitySold: null == quantitySold + ? _value.quantitySold + : quantitySold // ignore: cast_nullable_to_non_nullable + as int, + revenue: null == revenue + ? _value.revenue + : revenue // ignore: cast_nullable_to_non_nullable + as double, + averagePrice: null == averagePrice + ? _value.averagePrice + : averagePrice // ignore: cast_nullable_to_non_nullable + as double, + orderCount: null == orderCount + ? _value.orderCount + : orderCount // ignore: cast_nullable_to_non_nullable + as int, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ProductAnalyticDataDtoImplCopyWith<$Res> + implements $ProductAnalyticDataDtoCopyWith<$Res> { + factory _$$ProductAnalyticDataDtoImplCopyWith( + _$ProductAnalyticDataDtoImpl value, + $Res Function(_$ProductAnalyticDataDtoImpl) then, + ) = __$$ProductAnalyticDataDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @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, + double revenue, + @JsonKey(name: 'average_price') double averagePrice, + @JsonKey(name: 'order_count') int orderCount, + }); +} + +/// @nodoc +class __$$ProductAnalyticDataDtoImplCopyWithImpl<$Res> + extends + _$ProductAnalyticDataDtoCopyWithImpl<$Res, _$ProductAnalyticDataDtoImpl> + implements _$$ProductAnalyticDataDtoImplCopyWith<$Res> { + __$$ProductAnalyticDataDtoImplCopyWithImpl( + _$ProductAnalyticDataDtoImpl _value, + $Res Function(_$ProductAnalyticDataDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ProductAnalyticDataDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? productId = null, + Object? productName = null, + Object? categoryId = null, + Object? categoryName = null, + Object? quantitySold = null, + Object? revenue = null, + Object? averagePrice = null, + Object? orderCount = null, + }) { + return _then( + _$ProductAnalyticDataDtoImpl( + productId: null == productId + ? _value.productId + : productId // ignore: cast_nullable_to_non_nullable + as String, + productName: null == productName + ? _value.productName + : productName // ignore: cast_nullable_to_non_nullable + as String, + categoryId: null == categoryId + ? _value.categoryId + : categoryId // ignore: cast_nullable_to_non_nullable + as String, + categoryName: null == categoryName + ? _value.categoryName + : categoryName // ignore: cast_nullable_to_non_nullable + as String, + quantitySold: null == quantitySold + ? _value.quantitySold + : quantitySold // ignore: cast_nullable_to_non_nullable + as int, + revenue: null == revenue + ? _value.revenue + : revenue // ignore: cast_nullable_to_non_nullable + as double, + averagePrice: null == averagePrice + ? _value.averagePrice + : averagePrice // ignore: cast_nullable_to_non_nullable + as double, + orderCount: null == orderCount + ? _value.orderCount + : orderCount // ignore: cast_nullable_to_non_nullable + as int, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$ProductAnalyticDataDtoImpl extends _ProductAnalyticDataDto { + const _$ProductAnalyticDataDtoImpl({ + @JsonKey(name: 'product_id') required this.productId, + @JsonKey(name: 'product_name') required this.productName, + @JsonKey(name: 'category_id') required this.categoryId, + @JsonKey(name: 'category_name') required this.categoryName, + @JsonKey(name: 'quantity_sold') required this.quantitySold, + required this.revenue, + @JsonKey(name: 'average_price') required this.averagePrice, + @JsonKey(name: 'order_count') required this.orderCount, + }) : super._(); + + factory _$ProductAnalyticDataDtoImpl.fromJson(Map json) => + _$$ProductAnalyticDataDtoImplFromJson(json); + + @override + @JsonKey(name: 'product_id') + final String productId; + @override + @JsonKey(name: 'product_name') + final String productName; + @override + @JsonKey(name: 'category_id') + final String categoryId; + @override + @JsonKey(name: 'category_name') + final String categoryName; + @override + @JsonKey(name: 'quantity_sold') + final int quantitySold; + @override + final double revenue; + @override + @JsonKey(name: 'average_price') + final double averagePrice; + @override + @JsonKey(name: 'order_count') + final int orderCount; + + @override + String toString() { + return 'ProductAnalyticDataDto(productId: $productId, productName: $productName, categoryId: $categoryId, categoryName: $categoryName, quantitySold: $quantitySold, revenue: $revenue, averagePrice: $averagePrice, orderCount: $orderCount)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProductAnalyticDataDtoImpl && + (identical(other.productId, productId) || + other.productId == productId) && + (identical(other.productName, productName) || + other.productName == productName) && + (identical(other.categoryId, categoryId) || + other.categoryId == categoryId) && + (identical(other.categoryName, categoryName) || + other.categoryName == categoryName) && + (identical(other.quantitySold, quantitySold) || + other.quantitySold == quantitySold) && + (identical(other.revenue, revenue) || other.revenue == revenue) && + (identical(other.averagePrice, averagePrice) || + other.averagePrice == averagePrice) && + (identical(other.orderCount, orderCount) || + other.orderCount == orderCount)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + productId, + productName, + categoryId, + categoryName, + quantitySold, + revenue, + averagePrice, + orderCount, + ); + + /// Create a copy of ProductAnalyticDataDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProductAnalyticDataDtoImplCopyWith<_$ProductAnalyticDataDtoImpl> + get copyWith => + __$$ProductAnalyticDataDtoImplCopyWithImpl<_$ProductAnalyticDataDtoImpl>( + this, + _$identity, + ); + + @override + Map toJson() { + return _$$ProductAnalyticDataDtoImplToJson(this); + } +} + +abstract class _ProductAnalyticDataDto extends ProductAnalyticDataDto { + const factory _ProductAnalyticDataDto({ + @JsonKey(name: 'product_id') required final String productId, + @JsonKey(name: 'product_name') required final String productName, + @JsonKey(name: 'category_id') required final String categoryId, + @JsonKey(name: 'category_name') required final String categoryName, + @JsonKey(name: 'quantity_sold') required final int quantitySold, + required final double revenue, + @JsonKey(name: 'average_price') required final double averagePrice, + @JsonKey(name: 'order_count') required final int orderCount, + }) = _$ProductAnalyticDataDtoImpl; + const _ProductAnalyticDataDto._() : super._(); + + factory _ProductAnalyticDataDto.fromJson(Map json) = + _$ProductAnalyticDataDtoImpl.fromJson; + + @override + @JsonKey(name: 'product_id') + String get productId; + @override + @JsonKey(name: 'product_name') + String get productName; + @override + @JsonKey(name: 'category_id') + String get categoryId; + @override + @JsonKey(name: 'category_name') + String get categoryName; + @override + @JsonKey(name: 'quantity_sold') + int get quantitySold; + @override + double get revenue; + @override + @JsonKey(name: 'average_price') + double get averagePrice; + @override + @JsonKey(name: 'order_count') + int get orderCount; + + /// Create a copy of ProductAnalyticDataDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProductAnalyticDataDtoImplCopyWith<_$ProductAnalyticDataDtoImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/infrastructure/analytic/analytic_dtos.g.dart b/lib/infrastructure/analytic/analytic_dtos.g.dart index 9d3dbdd..6a760d7 100644 --- a/lib/infrastructure/analytic/analytic_dtos.g.dart +++ b/lib/infrastructure/analytic/analytic_dtos.g.dart @@ -517,3 +517,51 @@ Map _$$DashboardRecentSaleDtoImplToJson( 'discount': instance.discount, 'net_sales': instance.netSales, }; + +_$ProductAnalyticDtoImpl _$$ProductAnalyticDtoImplFromJson( + Map json, +) => _$ProductAnalyticDtoImpl( + organizationId: json['organization_id'] as String, + outletId: json['outlet_id'] as String, + dateFrom: json['date_from'] as String, + dateTo: json['date_to'] as String, + data: (json['data'] as List) + .map((e) => ProductAnalyticDataDto.fromJson(e as Map)) + .toList(), +); + +Map _$$ProductAnalyticDtoImplToJson( + _$ProductAnalyticDtoImpl instance, +) => { + 'organization_id': instance.organizationId, + 'outlet_id': instance.outletId, + 'date_from': instance.dateFrom, + 'date_to': instance.dateTo, + 'data': instance.data, +}; + +_$ProductAnalyticDataDtoImpl _$$ProductAnalyticDataDtoImplFromJson( + Map json, +) => _$ProductAnalyticDataDtoImpl( + 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).toDouble(), + averagePrice: (json['average_price'] as num).toDouble(), + orderCount: (json['order_count'] as num).toInt(), +); + +Map _$$ProductAnalyticDataDtoImplToJson( + _$ProductAnalyticDataDtoImpl instance, +) => { + '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, +}; diff --git a/lib/infrastructure/analytic/datasource/remote_data_provider.dart b/lib/infrastructure/analytic/datasource/remote_data_provider.dart index e8e7c7d..f6283dc 100644 --- a/lib/infrastructure/analytic/datasource/remote_data_provider.dart +++ b/lib/infrastructure/analytic/datasource/remote_data_provider.dart @@ -154,4 +154,32 @@ class AnalyticRemoteDataProvider { return DC.error(AnalyticFailure.serverError(e)); } } + + Future> fetchProduct({ + required String outletId, + required DateTime dateFrom, + required DateTime dateTo, + }) async { + try { + final response = await _apiClient.get( + ApiPath.productAnalytic, + params: { + 'date_from': dateFrom.toServerDate, + 'date_to': dateTo.toServerDate, + }, + headers: getAuthorizationHeader(), + ); + + if (response.data['data'] == null) { + return DC.error(AnalyticFailure.empty()); + } + + final dto = ProductAnalyticDto.fromJson(response.data['data']); + + return DC.data(dto); + } on ApiFailure catch (e, s) { + log('fetchProductError', name: _logName, error: e, stackTrace: s); + return DC.error(AnalyticFailure.serverError(e)); + } + } } diff --git a/lib/infrastructure/analytic/dto/product_analytic_dto.dart b/lib/infrastructure/analytic/dto/product_analytic_dto.dart new file mode 100644 index 0000000..68eb722 --- /dev/null +++ b/lib/infrastructure/analytic/dto/product_analytic_dto.dart @@ -0,0 +1,55 @@ +part of '../analytic_dtos.dart'; + +@freezed +class ProductAnalyticDto with _$ProductAnalyticDto { + const ProductAnalyticDto._(); + + const factory ProductAnalyticDto({ + @JsonKey(name: 'organization_id') required String organizationId, + @JsonKey(name: 'outlet_id') required String outletId, + @JsonKey(name: 'date_from') required String dateFrom, + @JsonKey(name: 'date_to') required String dateTo, + required List data, + }) = _ProductAnalyticDto; + + factory ProductAnalyticDto.fromJson(Map json) => + _$ProductAnalyticDtoFromJson(json); + + ProductAnalytic toDomain() => ProductAnalytic( + organizationId: organizationId, + outletId: outletId, + dateFrom: dateFrom, + dateTo: dateTo, + data: data.map((e) => e.toDomain()).toList(), + ); +} + +@freezed +class ProductAnalyticDataDto with _$ProductAnalyticDataDto { + const ProductAnalyticDataDto._(); + + const factory ProductAnalyticDataDto({ + @JsonKey(name: 'product_id') required String productId, + @JsonKey(name: 'product_name') required String productName, + @JsonKey(name: 'category_id') required String categoryId, + @JsonKey(name: 'category_name') required String categoryName, + @JsonKey(name: 'quantity_sold') required int quantitySold, + required double revenue, + @JsonKey(name: 'average_price') required double averagePrice, + @JsonKey(name: 'order_count') required int orderCount, + }) = _ProductAnalyticDataDto; + + factory ProductAnalyticDataDto.fromJson(Map json) => + _$ProductAnalyticDataDtoFromJson(json); + + ProductAnalyticData toDomain() => ProductAnalyticData( + productId: productId, + productName: productName, + categoryId: categoryId, + categoryName: categoryName, + quantitySold: quantitySold, + revenue: revenue, + averagePrice: averagePrice, + orderCount: orderCount, + ); +} diff --git a/lib/infrastructure/analytic/repositories/analytic_repository.dart b/lib/infrastructure/analytic/repositories/analytic_repository.dart index 011f2bc..67b7c9a 100644 --- a/lib/infrastructure/analytic/repositories/analytic_repository.dart +++ b/lib/infrastructure/analytic/repositories/analytic_repository.dart @@ -142,4 +142,31 @@ class AnalyticRepository implements IAnalyticRepository { return left(const AnalyticFailure.unexpectedError()); } } + + @override + Future> getProduct({ + required DateTime dateFrom, + required DateTime dateTo, + }) async { + try { + User currentUser = await _authLocalDataProvider.currentUser(); + + final result = await _dataProvider.fetchProduct( + outletId: currentUser.outletId, + dateFrom: dateFrom, + dateTo: dateTo, + ); + + if (result.hasError) { + return left(result.error!); + } + + final auth = result.data!.toDomain(); + + return right(auth); + } catch (e, s) { + log('getProductError', name: _logName, error: e, stackTrace: s); + return left(const AnalyticFailure.unexpectedError()); + } + } } diff --git a/lib/injection.config.dart b/lib/injection.config.dart index a63e8a5..e6b0cdf 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -15,6 +15,8 @@ import 'package:apskel_owner_flutter/application/analytic/dashboard_analytic_loa as _i516; import 'package:apskel_owner_flutter/application/analytic/inventory_analytic_loader/inventory_analytic_loader_bloc.dart' as _i785; +import 'package:apskel_owner_flutter/application/analytic/product_analytic_loader/product_analytic_loader_bloc.dart' + as _i221; import 'package:apskel_owner_flutter/application/analytic/profit_loss_loader/profit_loss_loader_bloc.dart' as _i11; import 'package:apskel_owner_flutter/application/analytic/sales_loader/sales_loader_bloc.dart' @@ -179,6 +181,9 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i516.DashboardAnalyticLoaderBloc>( () => _i516.DashboardAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), ); + gh.factory<_i221.ProductAnalyticLoaderBloc>( + () => _i221.ProductAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), + ); gh.factory<_i775.LoginFormBloc>( () => _i775.LoginFormBloc(gh<_i49.IAuthRepository>()), ); diff --git a/lib/presentation/router/app_router.gr.dart b/lib/presentation/router/app_router.gr.dart index 30d3060..6854f53 100644 --- a/lib/presentation/router/app_router.gr.dart +++ b/lib/presentation/router/app_router.gr.dart @@ -311,7 +311,7 @@ class ReportRoute extends _i18.PageRouteInfo { static _i18.PageInfo page = _i18.PageInfo( name, builder: (data) { - return const _i13.ReportPage(); + return _i18.WrappedRoute(child: const _i13.ReportPage()); }, ); }