diff --git a/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.dart b/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.dart new file mode 100644 index 0000000..d3b31ef --- /dev/null +++ b/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.dart @@ -0,0 +1,50 @@ +import 'package:bloc/bloc.dart'; +import 'package:dartz/dartz.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:injectable/injectable.dart'; + +import '../../../domain/analytic/analytic.dart'; + +part 'sales_analytic_loader_event.dart'; +part 'sales_analytic_loader_state.dart'; +part 'sales_analytic_loader_bloc.freezed.dart'; + +@injectable +class SalesAnalyticLoaderBloc + extends Bloc { + final IAnalyticRepository _analyticRepository; + SalesAnalyticLoaderBloc(this._analyticRepository) + : super(SalesAnalyticLoaderState.initial()) { + on(_onSalesAnalyticLoaderEvent); + } + + Future _onSalesAnalyticLoaderEvent( + SalesAnalyticLoaderEvent event, + Emitter emit, + ) { + return event.map( + fetched: (e) async { + emit(state.copyWith(isFetching: true, failureOption: none())); + + final result = await _analyticRepository.getSales( + dateFrom: e.startDate, + dateTo: e.endDate, + ); + + await result.fold( + (failure) async { + emit( + state.copyWith( + isFetching: false, + failureOption: optionOf(failure), + ), + ); + }, + (sales) async { + emit(state.copyWith(isFetching: false, salesAnalytic: sales)); + }, + ); + }, + ); + } +} diff --git a/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.freezed.dart b/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.freezed.dart new file mode 100644 index 0000000..9a44410 --- /dev/null +++ b/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.freezed.dart @@ -0,0 +1,466 @@ +// 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 'sales_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 _$SalesAnalyticLoaderEvent { + DateTime get startDate => throw _privateConstructorUsedError; + DateTime get endDate => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult when({ + required TResult Function(DateTime startDate, DateTime endDate) fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(DateTime startDate, DateTime endDate)? fetched, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(DateTime startDate, DateTime endDate)? 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; + + /// Create a copy of SalesAnalyticLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SalesAnalyticLoaderEventCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SalesAnalyticLoaderEventCopyWith<$Res> { + factory $SalesAnalyticLoaderEventCopyWith( + SalesAnalyticLoaderEvent value, + $Res Function(SalesAnalyticLoaderEvent) then, + ) = _$SalesAnalyticLoaderEventCopyWithImpl<$Res, SalesAnalyticLoaderEvent>; + @useResult + $Res call({DateTime startDate, DateTime endDate}); +} + +/// @nodoc +class _$SalesAnalyticLoaderEventCopyWithImpl< + $Res, + $Val extends SalesAnalyticLoaderEvent +> + implements $SalesAnalyticLoaderEventCopyWith<$Res> { + _$SalesAnalyticLoaderEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SalesAnalyticLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? startDate = null, Object? endDate = null}) { + return _then( + _value.copyWith( + startDate: null == startDate + ? _value.startDate + : startDate // ignore: cast_nullable_to_non_nullable + as DateTime, + endDate: null == endDate + ? _value.endDate + : endDate // ignore: cast_nullable_to_non_nullable + as DateTime, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$FetchedImplCopyWith<$Res> + implements $SalesAnalyticLoaderEventCopyWith<$Res> { + factory _$$FetchedImplCopyWith( + _$FetchedImpl value, + $Res Function(_$FetchedImpl) then, + ) = __$$FetchedImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({DateTime startDate, DateTime endDate}); +} + +/// @nodoc +class __$$FetchedImplCopyWithImpl<$Res> + extends _$SalesAnalyticLoaderEventCopyWithImpl<$Res, _$FetchedImpl> + implements _$$FetchedImplCopyWith<$Res> { + __$$FetchedImplCopyWithImpl( + _$FetchedImpl _value, + $Res Function(_$FetchedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of SalesAnalyticLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? startDate = null, Object? endDate = null}) { + return _then( + _$FetchedImpl( + startDate: null == startDate + ? _value.startDate + : startDate // ignore: cast_nullable_to_non_nullable + as DateTime, + endDate: null == endDate + ? _value.endDate + : endDate // ignore: cast_nullable_to_non_nullable + as DateTime, + ), + ); + } +} + +/// @nodoc + +class _$FetchedImpl implements _Fetched { + const _$FetchedImpl({required this.startDate, required this.endDate}); + + @override + final DateTime startDate; + @override + final DateTime endDate; + + @override + String toString() { + return 'SalesAnalyticLoaderEvent.fetched(startDate: $startDate, endDate: $endDate)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$FetchedImpl && + (identical(other.startDate, startDate) || + other.startDate == startDate) && + (identical(other.endDate, endDate) || other.endDate == endDate)); + } + + @override + int get hashCode => Object.hash(runtimeType, startDate, endDate); + + /// Create a copy of SalesAnalyticLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$FetchedImplCopyWith<_$FetchedImpl> get copyWith => + __$$FetchedImplCopyWithImpl<_$FetchedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(DateTime startDate, DateTime endDate) fetched, + }) { + return fetched(startDate, endDate); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(DateTime startDate, DateTime endDate)? fetched, + }) { + return fetched?.call(startDate, endDate); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(DateTime startDate, DateTime endDate)? fetched, + required TResult orElse(), + }) { + if (fetched != null) { + return fetched(startDate, endDate); + } + 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 SalesAnalyticLoaderEvent { + const factory _Fetched({ + required final DateTime startDate, + required final DateTime endDate, + }) = _$FetchedImpl; + + @override + DateTime get startDate; + @override + DateTime get endDate; + + /// Create a copy of SalesAnalyticLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$FetchedImplCopyWith<_$FetchedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$SalesAnalyticLoaderState { + SalesAnalytic get salesAnalytic => throw _privateConstructorUsedError; + Option get failureOption => + throw _privateConstructorUsedError; + bool get isFetching => throw _privateConstructorUsedError; + + /// Create a copy of SalesAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SalesAnalyticLoaderStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SalesAnalyticLoaderStateCopyWith<$Res> { + factory $SalesAnalyticLoaderStateCopyWith( + SalesAnalyticLoaderState value, + $Res Function(SalesAnalyticLoaderState) then, + ) = _$SalesAnalyticLoaderStateCopyWithImpl<$Res, SalesAnalyticLoaderState>; + @useResult + $Res call({ + SalesAnalytic salesAnalytic, + Option failureOption, + bool isFetching, + }); + + $SalesAnalyticCopyWith<$Res> get salesAnalytic; +} + +/// @nodoc +class _$SalesAnalyticLoaderStateCopyWithImpl< + $Res, + $Val extends SalesAnalyticLoaderState +> + implements $SalesAnalyticLoaderStateCopyWith<$Res> { + _$SalesAnalyticLoaderStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SalesAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? salesAnalytic = null, + Object? failureOption = null, + Object? isFetching = null, + }) { + return _then( + _value.copyWith( + salesAnalytic: null == salesAnalytic + ? _value.salesAnalytic + : salesAnalytic // ignore: cast_nullable_to_non_nullable + as SalesAnalytic, + failureOption: null == failureOption + ? _value.failureOption + : failureOption // ignore: cast_nullable_to_non_nullable + as Option, + isFetching: null == isFetching + ? _value.isFetching + : isFetching // ignore: cast_nullable_to_non_nullable + as bool, + ) + as $Val, + ); + } + + /// Create a copy of SalesAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $SalesAnalyticCopyWith<$Res> get salesAnalytic { + return $SalesAnalyticCopyWith<$Res>(_value.salesAnalytic, (value) { + return _then(_value.copyWith(salesAnalytic: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$SalesAnalyticLoaderStateImplCopyWith<$Res> + implements $SalesAnalyticLoaderStateCopyWith<$Res> { + factory _$$SalesAnalyticLoaderStateImplCopyWith( + _$SalesAnalyticLoaderStateImpl value, + $Res Function(_$SalesAnalyticLoaderStateImpl) then, + ) = __$$SalesAnalyticLoaderStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + SalesAnalytic salesAnalytic, + Option failureOption, + bool isFetching, + }); + + @override + $SalesAnalyticCopyWith<$Res> get salesAnalytic; +} + +/// @nodoc +class __$$SalesAnalyticLoaderStateImplCopyWithImpl<$Res> + extends + _$SalesAnalyticLoaderStateCopyWithImpl< + $Res, + _$SalesAnalyticLoaderStateImpl + > + implements _$$SalesAnalyticLoaderStateImplCopyWith<$Res> { + __$$SalesAnalyticLoaderStateImplCopyWithImpl( + _$SalesAnalyticLoaderStateImpl _value, + $Res Function(_$SalesAnalyticLoaderStateImpl) _then, + ) : super(_value, _then); + + /// Create a copy of SalesAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? salesAnalytic = null, + Object? failureOption = null, + Object? isFetching = null, + }) { + return _then( + _$SalesAnalyticLoaderStateImpl( + salesAnalytic: null == salesAnalytic + ? _value.salesAnalytic + : salesAnalytic // ignore: cast_nullable_to_non_nullable + as SalesAnalytic, + failureOption: null == failureOption + ? _value.failureOption + : failureOption // ignore: cast_nullable_to_non_nullable + as Option, + isFetching: null == isFetching + ? _value.isFetching + : isFetching // ignore: cast_nullable_to_non_nullable + as bool, + ), + ); + } +} + +/// @nodoc + +class _$SalesAnalyticLoaderStateImpl implements _SalesAnalyticLoaderState { + _$SalesAnalyticLoaderStateImpl({ + required this.salesAnalytic, + required this.failureOption, + this.isFetching = false, + }); + + @override + final SalesAnalytic salesAnalytic; + @override + final Option failureOption; + @override + @JsonKey() + final bool isFetching; + + @override + String toString() { + return 'SalesAnalyticLoaderState(salesAnalytic: $salesAnalytic, failureOption: $failureOption, isFetching: $isFetching)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SalesAnalyticLoaderStateImpl && + (identical(other.salesAnalytic, salesAnalytic) || + other.salesAnalytic == salesAnalytic) && + (identical(other.failureOption, failureOption) || + other.failureOption == failureOption) && + (identical(other.isFetching, isFetching) || + other.isFetching == isFetching)); + } + + @override + int get hashCode => + Object.hash(runtimeType, salesAnalytic, failureOption, isFetching); + + /// Create a copy of SalesAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SalesAnalyticLoaderStateImplCopyWith<_$SalesAnalyticLoaderStateImpl> + get copyWith => + __$$SalesAnalyticLoaderStateImplCopyWithImpl< + _$SalesAnalyticLoaderStateImpl + >(this, _$identity); +} + +abstract class _SalesAnalyticLoaderState implements SalesAnalyticLoaderState { + factory _SalesAnalyticLoaderState({ + required final SalesAnalytic salesAnalytic, + required final Option failureOption, + final bool isFetching, + }) = _$SalesAnalyticLoaderStateImpl; + + @override + SalesAnalytic get salesAnalytic; + @override + Option get failureOption; + @override + bool get isFetching; + + /// Create a copy of SalesAnalyticLoaderState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SalesAnalyticLoaderStateImplCopyWith<_$SalesAnalyticLoaderStateImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_event.dart b/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_event.dart new file mode 100644 index 0000000..54b4747 --- /dev/null +++ b/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_event.dart @@ -0,0 +1,9 @@ +part of 'sales_analytic_loader_bloc.dart'; + +@freezed +class SalesAnalyticLoaderEvent with _$SalesAnalyticLoaderEvent { + const factory SalesAnalyticLoaderEvent.fetched({ + required DateTime startDate, + required DateTime endDate, + }) = _Fetched; +} diff --git a/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_state.dart b/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_state.dart new file mode 100644 index 0000000..a63fcc1 --- /dev/null +++ b/lib/application/analytic/sales_analytic_loader/sales_analytic_loader_state.dart @@ -0,0 +1,15 @@ +part of 'sales_analytic_loader_bloc.dart'; + +@freezed +class SalesAnalyticLoaderState with _$SalesAnalyticLoaderState { + factory SalesAnalyticLoaderState({ + required SalesAnalytic salesAnalytic, + required Option failureOption, + @Default(false) bool isFetching, + }) = _SalesAnalyticLoaderState; + + factory SalesAnalyticLoaderState.initial() => SalesAnalyticLoaderState( + failureOption: none(), + salesAnalytic: SalesAnalytic.empty(), + ); +} diff --git a/lib/common/data/report_menu.dart b/lib/common/data/report_menu.dart index 092de06..9292da4 100644 --- a/lib/common/data/report_menu.dart +++ b/lib/common/data/report_menu.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; class ReportMenu { ReportMenu({ diff --git a/lib/common/url/api_path.dart b/lib/common/url/api_path.dart index b1e665e..69523bd 100644 --- a/lib/common/url/api_path.dart +++ b/lib/common/url/api_path.dart @@ -9,4 +9,5 @@ class ApiPath { static const String orders = '/api/v1/orders'; static const String payments = '/api/v1/payments'; static const String analyticDashboard = '/api/v1/analytics/dashboard'; + static const String analyticSales = '/api/v1/analytics/sales'; } diff --git a/lib/domain/analytic/analytic.dart b/lib/domain/analytic/analytic.dart index 230a493..1955b90 100644 --- a/lib/domain/analytic/analytic.dart +++ b/lib/domain/analytic/analytic.dart @@ -6,5 +6,6 @@ import '../../common/api/api_failure.dart'; part 'analytic.freezed.dart'; part 'entities/dashboard_entity.dart'; +part 'entities/sales_entity.dart'; part 'failures/analytic_failure.dart'; part 'repositories/i_analytic_repository.dart'; diff --git a/lib/domain/analytic/analytic.freezed.dart b/lib/domain/analytic/analytic.freezed.dart index 02ec136..4598ae0 100644 --- a/lib/domain/analytic/analytic.freezed.dart +++ b/lib/domain/analytic/analytic.freezed.dart @@ -1493,6 +1493,862 @@ abstract class _DashboardRecentSale implements DashboardRecentSale { throw _privateConstructorUsedError; } +/// @nodoc +mixin _$SalesAnalytic { + String get organizationId => throw _privateConstructorUsedError; + String get outletId => throw _privateConstructorUsedError; + DateTime get dateFrom => throw _privateConstructorUsedError; + DateTime get dateTo => throw _privateConstructorUsedError; + String get groupBy => throw _privateConstructorUsedError; + SalesSummary get summary => throw _privateConstructorUsedError; + List get data => throw _privateConstructorUsedError; + + /// Create a copy of SalesAnalytic + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SalesAnalyticCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SalesAnalyticCopyWith<$Res> { + factory $SalesAnalyticCopyWith( + SalesAnalytic value, + $Res Function(SalesAnalytic) then, + ) = _$SalesAnalyticCopyWithImpl<$Res, SalesAnalytic>; + @useResult + $Res call({ + String organizationId, + String outletId, + DateTime dateFrom, + DateTime dateTo, + String groupBy, + SalesSummary summary, + List data, + }); + + $SalesSummaryCopyWith<$Res> get summary; +} + +/// @nodoc +class _$SalesAnalyticCopyWithImpl<$Res, $Val extends SalesAnalytic> + implements $SalesAnalyticCopyWith<$Res> { + _$SalesAnalyticCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SalesAnalytic + /// 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? groupBy = null, + Object? summary = 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 DateTime, + dateTo: null == dateTo + ? _value.dateTo + : dateTo // ignore: cast_nullable_to_non_nullable + as DateTime, + groupBy: null == groupBy + ? _value.groupBy + : groupBy // ignore: cast_nullable_to_non_nullable + as String, + summary: null == summary + ? _value.summary + : summary // ignore: cast_nullable_to_non_nullable + as SalesSummary, + data: null == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as List, + ) + as $Val, + ); + } + + /// Create a copy of SalesAnalytic + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $SalesSummaryCopyWith<$Res> get summary { + return $SalesSummaryCopyWith<$Res>(_value.summary, (value) { + return _then(_value.copyWith(summary: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$SalesAnalyticImplCopyWith<$Res> + implements $SalesAnalyticCopyWith<$Res> { + factory _$$SalesAnalyticImplCopyWith( + _$SalesAnalyticImpl value, + $Res Function(_$SalesAnalyticImpl) then, + ) = __$$SalesAnalyticImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + String organizationId, + String outletId, + DateTime dateFrom, + DateTime dateTo, + String groupBy, + SalesSummary summary, + List data, + }); + + @override + $SalesSummaryCopyWith<$Res> get summary; +} + +/// @nodoc +class __$$SalesAnalyticImplCopyWithImpl<$Res> + extends _$SalesAnalyticCopyWithImpl<$Res, _$SalesAnalyticImpl> + implements _$$SalesAnalyticImplCopyWith<$Res> { + __$$SalesAnalyticImplCopyWithImpl( + _$SalesAnalyticImpl _value, + $Res Function(_$SalesAnalyticImpl) _then, + ) : super(_value, _then); + + /// Create a copy of SalesAnalytic + /// 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? groupBy = null, + Object? summary = null, + Object? data = null, + }) { + return _then( + _$SalesAnalyticImpl( + 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 DateTime, + dateTo: null == dateTo + ? _value.dateTo + : dateTo // ignore: cast_nullable_to_non_nullable + as DateTime, + groupBy: null == groupBy + ? _value.groupBy + : groupBy // ignore: cast_nullable_to_non_nullable + as String, + summary: null == summary + ? _value.summary + : summary // ignore: cast_nullable_to_non_nullable + as SalesSummary, + data: null == data + ? _value._data + : data // ignore: cast_nullable_to_non_nullable + as List, + ), + ); + } +} + +/// @nodoc + +class _$SalesAnalyticImpl extends _SalesAnalytic { + const _$SalesAnalyticImpl({ + required this.organizationId, + required this.outletId, + required this.dateFrom, + required this.dateTo, + required this.groupBy, + required this.summary, + required final List data, + }) : _data = data, + super._(); + + @override + final String organizationId; + @override + final String outletId; + @override + final DateTime dateFrom; + @override + final DateTime dateTo; + @override + final String groupBy; + @override + final SalesSummary summary; + final List _data; + @override + List get data { + if (_data is EqualUnmodifiableListView) return _data; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_data); + } + + @override + String toString() { + return 'SalesAnalytic(organizationId: $organizationId, outletId: $outletId, dateFrom: $dateFrom, dateTo: $dateTo, groupBy: $groupBy, summary: $summary, data: $data)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SalesAnalyticImpl && + (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) && + (identical(other.groupBy, groupBy) || other.groupBy == groupBy) && + (identical(other.summary, summary) || other.summary == summary) && + const DeepCollectionEquality().equals(other._data, _data)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + organizationId, + outletId, + dateFrom, + dateTo, + groupBy, + summary, + const DeepCollectionEquality().hash(_data), + ); + + /// Create a copy of SalesAnalytic + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SalesAnalyticImplCopyWith<_$SalesAnalyticImpl> get copyWith => + __$$SalesAnalyticImplCopyWithImpl<_$SalesAnalyticImpl>(this, _$identity); +} + +abstract class _SalesAnalytic extends SalesAnalytic { + const factory _SalesAnalytic({ + required final String organizationId, + required final String outletId, + required final DateTime dateFrom, + required final DateTime dateTo, + required final String groupBy, + required final SalesSummary summary, + required final List data, + }) = _$SalesAnalyticImpl; + const _SalesAnalytic._() : super._(); + + @override + String get organizationId; + @override + String get outletId; + @override + DateTime get dateFrom; + @override + DateTime get dateTo; + @override + String get groupBy; + @override + SalesSummary get summary; + @override + List get data; + + /// Create a copy of SalesAnalytic + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SalesAnalyticImplCopyWith<_$SalesAnalyticImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$SalesSummary { + int get totalSales => throw _privateConstructorUsedError; + int get totalOrders => throw _privateConstructorUsedError; + int get totalItems => throw _privateConstructorUsedError; + double get averageOrderValue => throw _privateConstructorUsedError; + int get totalTax => throw _privateConstructorUsedError; + int get totalDiscount => throw _privateConstructorUsedError; + int get netSales => throw _privateConstructorUsedError; + + /// Create a copy of SalesSummary + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SalesSummaryCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SalesSummaryCopyWith<$Res> { + factory $SalesSummaryCopyWith( + SalesSummary value, + $Res Function(SalesSummary) then, + ) = _$SalesSummaryCopyWithImpl<$Res, SalesSummary>; + @useResult + $Res call({ + int totalSales, + int totalOrders, + int totalItems, + double averageOrderValue, + int totalTax, + int totalDiscount, + int netSales, + }); +} + +/// @nodoc +class _$SalesSummaryCopyWithImpl<$Res, $Val extends SalesSummary> + implements $SalesSummaryCopyWith<$Res> { + _$SalesSummaryCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SalesSummary + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? totalSales = null, + Object? totalOrders = null, + Object? totalItems = null, + Object? averageOrderValue = null, + Object? totalTax = null, + Object? totalDiscount = null, + Object? netSales = null, + }) { + return _then( + _value.copyWith( + totalSales: null == totalSales + ? _value.totalSales + : totalSales // ignore: cast_nullable_to_non_nullable + as int, + totalOrders: null == totalOrders + ? _value.totalOrders + : totalOrders // ignore: cast_nullable_to_non_nullable + as int, + totalItems: null == totalItems + ? _value.totalItems + : totalItems // ignore: cast_nullable_to_non_nullable + as int, + averageOrderValue: null == averageOrderValue + ? _value.averageOrderValue + : averageOrderValue // ignore: cast_nullable_to_non_nullable + as double, + totalTax: null == totalTax + ? _value.totalTax + : totalTax // ignore: cast_nullable_to_non_nullable + as int, + totalDiscount: null == totalDiscount + ? _value.totalDiscount + : totalDiscount // ignore: cast_nullable_to_non_nullable + as int, + netSales: null == netSales + ? _value.netSales + : netSales // ignore: cast_nullable_to_non_nullable + as int, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$SalesSummaryImplCopyWith<$Res> + implements $SalesSummaryCopyWith<$Res> { + factory _$$SalesSummaryImplCopyWith( + _$SalesSummaryImpl value, + $Res Function(_$SalesSummaryImpl) then, + ) = __$$SalesSummaryImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + int totalSales, + int totalOrders, + int totalItems, + double averageOrderValue, + int totalTax, + int totalDiscount, + int netSales, + }); +} + +/// @nodoc +class __$$SalesSummaryImplCopyWithImpl<$Res> + extends _$SalesSummaryCopyWithImpl<$Res, _$SalesSummaryImpl> + implements _$$SalesSummaryImplCopyWith<$Res> { + __$$SalesSummaryImplCopyWithImpl( + _$SalesSummaryImpl _value, + $Res Function(_$SalesSummaryImpl) _then, + ) : super(_value, _then); + + /// Create a copy of SalesSummary + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? totalSales = null, + Object? totalOrders = null, + Object? totalItems = null, + Object? averageOrderValue = null, + Object? totalTax = null, + Object? totalDiscount = null, + Object? netSales = null, + }) { + return _then( + _$SalesSummaryImpl( + totalSales: null == totalSales + ? _value.totalSales + : totalSales // ignore: cast_nullable_to_non_nullable + as int, + totalOrders: null == totalOrders + ? _value.totalOrders + : totalOrders // ignore: cast_nullable_to_non_nullable + as int, + totalItems: null == totalItems + ? _value.totalItems + : totalItems // ignore: cast_nullable_to_non_nullable + as int, + averageOrderValue: null == averageOrderValue + ? _value.averageOrderValue + : averageOrderValue // ignore: cast_nullable_to_non_nullable + as double, + totalTax: null == totalTax + ? _value.totalTax + : totalTax // ignore: cast_nullable_to_non_nullable + as int, + totalDiscount: null == totalDiscount + ? _value.totalDiscount + : totalDiscount // ignore: cast_nullable_to_non_nullable + as int, + netSales: null == netSales + ? _value.netSales + : netSales // ignore: cast_nullable_to_non_nullable + as int, + ), + ); + } +} + +/// @nodoc + +class _$SalesSummaryImpl implements _SalesSummary { + const _$SalesSummaryImpl({ + required this.totalSales, + required this.totalOrders, + required this.totalItems, + required this.averageOrderValue, + required this.totalTax, + required this.totalDiscount, + required this.netSales, + }); + + @override + final int totalSales; + @override + final int totalOrders; + @override + final int totalItems; + @override + final double averageOrderValue; + @override + final int totalTax; + @override + final int totalDiscount; + @override + final int netSales; + + @override + String toString() { + return 'SalesSummary(totalSales: $totalSales, totalOrders: $totalOrders, totalItems: $totalItems, averageOrderValue: $averageOrderValue, totalTax: $totalTax, totalDiscount: $totalDiscount, netSales: $netSales)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SalesSummaryImpl && + (identical(other.totalSales, totalSales) || + other.totalSales == totalSales) && + (identical(other.totalOrders, totalOrders) || + other.totalOrders == totalOrders) && + (identical(other.totalItems, totalItems) || + other.totalItems == totalItems) && + (identical(other.averageOrderValue, averageOrderValue) || + other.averageOrderValue == averageOrderValue) && + (identical(other.totalTax, totalTax) || + other.totalTax == totalTax) && + (identical(other.totalDiscount, totalDiscount) || + other.totalDiscount == totalDiscount) && + (identical(other.netSales, netSales) || + other.netSales == netSales)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + totalSales, + totalOrders, + totalItems, + averageOrderValue, + totalTax, + totalDiscount, + netSales, + ); + + /// Create a copy of SalesSummary + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SalesSummaryImplCopyWith<_$SalesSummaryImpl> get copyWith => + __$$SalesSummaryImplCopyWithImpl<_$SalesSummaryImpl>(this, _$identity); +} + +abstract class _SalesSummary implements SalesSummary { + const factory _SalesSummary({ + required final int totalSales, + required final int totalOrders, + required final int totalItems, + required final double averageOrderValue, + required final int totalTax, + required final int totalDiscount, + required final int netSales, + }) = _$SalesSummaryImpl; + + @override + int get totalSales; + @override + int get totalOrders; + @override + int get totalItems; + @override + double get averageOrderValue; + @override + int get totalTax; + @override + int get totalDiscount; + @override + int get netSales; + + /// Create a copy of SalesSummary + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SalesSummaryImplCopyWith<_$SalesSummaryImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$SalesAnalyticItem { + DateTime get date => throw _privateConstructorUsedError; + int get sales => throw _privateConstructorUsedError; + int get orders => throw _privateConstructorUsedError; + int get items => throw _privateConstructorUsedError; + int get tax => throw _privateConstructorUsedError; + int get discount => throw _privateConstructorUsedError; + int get netSales => throw _privateConstructorUsedError; + + /// Create a copy of SalesAnalyticItem + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SalesAnalyticItemCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SalesAnalyticItemCopyWith<$Res> { + factory $SalesAnalyticItemCopyWith( + SalesAnalyticItem value, + $Res Function(SalesAnalyticItem) then, + ) = _$SalesAnalyticItemCopyWithImpl<$Res, SalesAnalyticItem>; + @useResult + $Res call({ + DateTime date, + int sales, + int orders, + int items, + int tax, + int discount, + int netSales, + }); +} + +/// @nodoc +class _$SalesAnalyticItemCopyWithImpl<$Res, $Val extends SalesAnalyticItem> + implements $SalesAnalyticItemCopyWith<$Res> { + _$SalesAnalyticItemCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SalesAnalyticItem + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = null, + Object? sales = null, + Object? orders = null, + Object? items = null, + Object? tax = null, + Object? discount = null, + Object? netSales = null, + }) { + return _then( + _value.copyWith( + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as DateTime, + sales: null == sales + ? _value.sales + : sales // ignore: cast_nullable_to_non_nullable + as int, + orders: null == orders + ? _value.orders + : orders // ignore: cast_nullable_to_non_nullable + as int, + items: null == items + ? _value.items + : items // ignore: cast_nullable_to_non_nullable + as int, + tax: null == tax + ? _value.tax + : tax // ignore: cast_nullable_to_non_nullable + as int, + discount: null == discount + ? _value.discount + : discount // ignore: cast_nullable_to_non_nullable + as int, + netSales: null == netSales + ? _value.netSales + : netSales // ignore: cast_nullable_to_non_nullable + as int, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$SalesAnalyticItemImplCopyWith<$Res> + implements $SalesAnalyticItemCopyWith<$Res> { + factory _$$SalesAnalyticItemImplCopyWith( + _$SalesAnalyticItemImpl value, + $Res Function(_$SalesAnalyticItemImpl) then, + ) = __$$SalesAnalyticItemImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + DateTime date, + int sales, + int orders, + int items, + int tax, + int discount, + int netSales, + }); +} + +/// @nodoc +class __$$SalesAnalyticItemImplCopyWithImpl<$Res> + extends _$SalesAnalyticItemCopyWithImpl<$Res, _$SalesAnalyticItemImpl> + implements _$$SalesAnalyticItemImplCopyWith<$Res> { + __$$SalesAnalyticItemImplCopyWithImpl( + _$SalesAnalyticItemImpl _value, + $Res Function(_$SalesAnalyticItemImpl) _then, + ) : super(_value, _then); + + /// Create a copy of SalesAnalyticItem + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = null, + Object? sales = null, + Object? orders = null, + Object? items = null, + Object? tax = null, + Object? discount = null, + Object? netSales = null, + }) { + return _then( + _$SalesAnalyticItemImpl( + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as DateTime, + sales: null == sales + ? _value.sales + : sales // ignore: cast_nullable_to_non_nullable + as int, + orders: null == orders + ? _value.orders + : orders // ignore: cast_nullable_to_non_nullable + as int, + items: null == items + ? _value.items + : items // ignore: cast_nullable_to_non_nullable + as int, + tax: null == tax + ? _value.tax + : tax // ignore: cast_nullable_to_non_nullable + as int, + discount: null == discount + ? _value.discount + : discount // ignore: cast_nullable_to_non_nullable + as int, + netSales: null == netSales + ? _value.netSales + : netSales // ignore: cast_nullable_to_non_nullable + as int, + ), + ); + } +} + +/// @nodoc + +class _$SalesAnalyticItemImpl implements _SalesAnalyticItem { + const _$SalesAnalyticItemImpl({ + required this.date, + required this.sales, + required this.orders, + required this.items, + required this.tax, + required this.discount, + required this.netSales, + }); + + @override + final DateTime date; + @override + final int sales; + @override + final int orders; + @override + final int items; + @override + final int tax; + @override + final int discount; + @override + final int netSales; + + @override + String toString() { + return 'SalesAnalyticItem(date: $date, sales: $sales, orders: $orders, items: $items, tax: $tax, discount: $discount, netSales: $netSales)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SalesAnalyticItemImpl && + (identical(other.date, date) || other.date == date) && + (identical(other.sales, sales) || other.sales == sales) && + (identical(other.orders, orders) || other.orders == orders) && + (identical(other.items, items) || other.items == items) && + (identical(other.tax, tax) || other.tax == tax) && + (identical(other.discount, discount) || + other.discount == discount) && + (identical(other.netSales, netSales) || + other.netSales == netSales)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + date, + sales, + orders, + items, + tax, + discount, + netSales, + ); + + /// Create a copy of SalesAnalyticItem + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SalesAnalyticItemImplCopyWith<_$SalesAnalyticItemImpl> get copyWith => + __$$SalesAnalyticItemImplCopyWithImpl<_$SalesAnalyticItemImpl>( + this, + _$identity, + ); +} + +abstract class _SalesAnalyticItem implements SalesAnalyticItem { + const factory _SalesAnalyticItem({ + required final DateTime date, + required final int sales, + required final int orders, + required final int items, + required final int tax, + required final int discount, + required final int netSales, + }) = _$SalesAnalyticItemImpl; + + @override + DateTime get date; + @override + int get sales; + @override + int get orders; + @override + int get items; + @override + int get tax; + @override + int get discount; + @override + int get netSales; + + /// Create a copy of SalesAnalyticItem + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SalesAnalyticItemImplCopyWith<_$SalesAnalyticItemImpl> get copyWith => + throw _privateConstructorUsedError; +} + /// @nodoc mixin _$AnalyticFailure { @optionalTypeArgs diff --git a/lib/domain/analytic/entities/sales_entity.dart b/lib/domain/analytic/entities/sales_entity.dart new file mode 100644 index 0000000..255c53e --- /dev/null +++ b/lib/domain/analytic/entities/sales_entity.dart @@ -0,0 +1,85 @@ +part of '../analytic.dart'; + +@freezed +class SalesAnalytic with _$SalesAnalytic { + const SalesAnalytic._(); + + const factory SalesAnalytic({ + required String organizationId, + required String outletId, + required DateTime dateFrom, + required DateTime dateTo, + required String groupBy, + required SalesSummary summary, + required List data, + }) = _SalesAnalytic; + + factory SalesAnalytic.empty() => SalesAnalytic( + organizationId: '', + outletId: '', + dateFrom: DateTime.now(), + dateTo: DateTime.now(), + groupBy: '', + summary: SalesSummary.empty(), + data: const [], + ); + + List get sortedDailyData { + final sortedList = List.from(data); + sortedList.sort((a, b) => b.sales.compareTo(a.sales)); + return sortedList; + } + + SalesAnalyticItem get highestRevenueDay { + if (data.isEmpty) { + return SalesAnalyticItem.empty(); + } + return sortedDailyData.first; + } +} + +@freezed +class SalesSummary with _$SalesSummary { + const factory SalesSummary({ + required int totalSales, + required int totalOrders, + required int totalItems, + required double averageOrderValue, + required int totalTax, + required int totalDiscount, + required int netSales, + }) = _SalesSummary; + + factory SalesSummary.empty() => const SalesSummary( + totalSales: 0, + totalOrders: 0, + totalItems: 0, + averageOrderValue: 0.0, + totalTax: 0, + totalDiscount: 0, + netSales: 0, + ); +} + +@freezed +class SalesAnalyticItem with _$SalesAnalyticItem { + const factory SalesAnalyticItem({ + required DateTime date, + required int sales, + required int orders, + required int items, + required int tax, + required int discount, + required int netSales, + }) = _SalesAnalyticItem; + + factory SalesAnalyticItem.empty() => SalesAnalyticItem( + date: DateTime.now(), + sales: 0, + orders: 0, + items: 0, + tax: 0, + discount: 0, + netSales: 0, + ); +} diff --git a/lib/domain/analytic/repositories/i_analytic_repository.dart b/lib/domain/analytic/repositories/i_analytic_repository.dart index 68d076c..f66003c 100644 --- a/lib/domain/analytic/repositories/i_analytic_repository.dart +++ b/lib/domain/analytic/repositories/i_analytic_repository.dart @@ -5,4 +5,8 @@ abstract class IAnalyticRepository { required DateTime dateFrom, required DateTime dateTo, }); + Future> getSales({ + required DateTime dateFrom, + required DateTime dateTo, + }); } diff --git a/lib/infrastructure/analytic/analytic_dtos.dart b/lib/infrastructure/analytic/analytic_dtos.dart index 2b3e121..2b3b7a4 100644 --- a/lib/infrastructure/analytic/analytic_dtos.dart +++ b/lib/infrastructure/analytic/analytic_dtos.dart @@ -6,3 +6,4 @@ part 'analytic_dtos.freezed.dart'; part 'analytic_dtos.g.dart'; part 'dtos/dashboard_dto.dart'; +part 'dtos/sales_dto.dart'; diff --git a/lib/infrastructure/analytic/analytic_dtos.freezed.dart b/lib/infrastructure/analytic/analytic_dtos.freezed.dart index 232f737..e1a8825 100644 --- a/lib/infrastructure/analytic/analytic_dtos.freezed.dart +++ b/lib/infrastructure/analytic/analytic_dtos.freezed.dart @@ -1745,3 +1745,997 @@ abstract class _DashboardRecentSaleDto extends DashboardRecentSaleDto { _$$DashboardRecentSaleDtoImplCopyWith<_$DashboardRecentSaleDtoImpl> get copyWith => throw _privateConstructorUsedError; } + +SalesAnalyticDto _$SalesAnalyticDtoFromJson(Map json) { + return _SalesAnalyticDto.fromJson(json); +} + +/// @nodoc +mixin _$SalesAnalyticDto { + @JsonKey(name: "organization_id") + String? get organizationId => throw _privateConstructorUsedError; + @JsonKey(name: "outlet_id") + String? get outletId => throw _privateConstructorUsedError; + @JsonKey(name: "date_from") + DateTime? get dateFrom => throw _privateConstructorUsedError; + @JsonKey(name: "date_to") + DateTime? get dateTo => throw _privateConstructorUsedError; + @JsonKey(name: "group_by") + String? get groupBy => throw _privateConstructorUsedError; + @JsonKey(name: "summary") + SalesSummaryDto? get summary => throw _privateConstructorUsedError; + @JsonKey(name: "data") + List? get data => throw _privateConstructorUsedError; + + /// Serializes this SalesAnalyticDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of SalesAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SalesAnalyticDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SalesAnalyticDtoCopyWith<$Res> { + factory $SalesAnalyticDtoCopyWith( + SalesAnalyticDto value, + $Res Function(SalesAnalyticDto) then, + ) = _$SalesAnalyticDtoCopyWithImpl<$Res, SalesAnalyticDto>; + @useResult + $Res call({ + @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") SalesSummaryDto? summary, + @JsonKey(name: "data") List? data, + }); + + $SalesSummaryDtoCopyWith<$Res>? get summary; +} + +/// @nodoc +class _$SalesAnalyticDtoCopyWithImpl<$Res, $Val extends SalesAnalyticDto> + implements $SalesAnalyticDtoCopyWith<$Res> { + _$SalesAnalyticDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SalesAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? organizationId = freezed, + Object? outletId = freezed, + Object? dateFrom = freezed, + Object? dateTo = freezed, + Object? groupBy = freezed, + Object? summary = freezed, + Object? data = freezed, + }) { + return _then( + _value.copyWith( + organizationId: freezed == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String?, + outletId: freezed == outletId + ? _value.outletId + : outletId // ignore: cast_nullable_to_non_nullable + as String?, + dateFrom: freezed == dateFrom + ? _value.dateFrom + : dateFrom // ignore: cast_nullable_to_non_nullable + as DateTime?, + dateTo: freezed == dateTo + ? _value.dateTo + : dateTo // ignore: cast_nullable_to_non_nullable + as DateTime?, + groupBy: freezed == groupBy + ? _value.groupBy + : groupBy // ignore: cast_nullable_to_non_nullable + as String?, + summary: freezed == summary + ? _value.summary + : summary // ignore: cast_nullable_to_non_nullable + as SalesSummaryDto?, + data: freezed == data + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as List?, + ) + as $Val, + ); + } + + /// Create a copy of SalesAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $SalesSummaryDtoCopyWith<$Res>? get summary { + if (_value.summary == null) { + return null; + } + + return $SalesSummaryDtoCopyWith<$Res>(_value.summary!, (value) { + return _then(_value.copyWith(summary: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$SalesAnalyticDtoImplCopyWith<$Res> + implements $SalesAnalyticDtoCopyWith<$Res> { + factory _$$SalesAnalyticDtoImplCopyWith( + _$SalesAnalyticDtoImpl value, + $Res Function(_$SalesAnalyticDtoImpl) then, + ) = __$$SalesAnalyticDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @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") SalesSummaryDto? summary, + @JsonKey(name: "data") List? data, + }); + + @override + $SalesSummaryDtoCopyWith<$Res>? get summary; +} + +/// @nodoc +class __$$SalesAnalyticDtoImplCopyWithImpl<$Res> + extends _$SalesAnalyticDtoCopyWithImpl<$Res, _$SalesAnalyticDtoImpl> + implements _$$SalesAnalyticDtoImplCopyWith<$Res> { + __$$SalesAnalyticDtoImplCopyWithImpl( + _$SalesAnalyticDtoImpl _value, + $Res Function(_$SalesAnalyticDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of SalesAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? organizationId = freezed, + Object? outletId = freezed, + Object? dateFrom = freezed, + Object? dateTo = freezed, + Object? groupBy = freezed, + Object? summary = freezed, + Object? data = freezed, + }) { + return _then( + _$SalesAnalyticDtoImpl( + organizationId: freezed == organizationId + ? _value.organizationId + : organizationId // ignore: cast_nullable_to_non_nullable + as String?, + outletId: freezed == outletId + ? _value.outletId + : outletId // ignore: cast_nullable_to_non_nullable + as String?, + dateFrom: freezed == dateFrom + ? _value.dateFrom + : dateFrom // ignore: cast_nullable_to_non_nullable + as DateTime?, + dateTo: freezed == dateTo + ? _value.dateTo + : dateTo // ignore: cast_nullable_to_non_nullable + as DateTime?, + groupBy: freezed == groupBy + ? _value.groupBy + : groupBy // ignore: cast_nullable_to_non_nullable + as String?, + summary: freezed == summary + ? _value.summary + : summary // ignore: cast_nullable_to_non_nullable + as SalesSummaryDto?, + data: freezed == data + ? _value._data + : data // ignore: cast_nullable_to_non_nullable + as List?, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$SalesAnalyticDtoImpl extends _SalesAnalyticDto { + const _$SalesAnalyticDtoImpl({ + @JsonKey(name: "organization_id") this.organizationId, + @JsonKey(name: "outlet_id") this.outletId, + @JsonKey(name: "date_from") this.dateFrom, + @JsonKey(name: "date_to") this.dateTo, + @JsonKey(name: "group_by") this.groupBy, + @JsonKey(name: "summary") this.summary, + @JsonKey(name: "data") final List? data, + }) : _data = data, + super._(); + + factory _$SalesAnalyticDtoImpl.fromJson(Map json) => + _$$SalesAnalyticDtoImplFromJson(json); + + @override + @JsonKey(name: "organization_id") + final String? organizationId; + @override + @JsonKey(name: "outlet_id") + final String? outletId; + @override + @JsonKey(name: "date_from") + final DateTime? dateFrom; + @override + @JsonKey(name: "date_to") + final DateTime? dateTo; + @override + @JsonKey(name: "group_by") + final String? groupBy; + @override + @JsonKey(name: "summary") + final SalesSummaryDto? summary; + final List? _data; + @override + @JsonKey(name: "data") + List? get data { + final value = _data; + if (value == null) return null; + if (_data is EqualUnmodifiableListView) return _data; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + String toString() { + return 'SalesAnalyticDto(organizationId: $organizationId, outletId: $outletId, dateFrom: $dateFrom, dateTo: $dateTo, groupBy: $groupBy, summary: $summary, data: $data)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SalesAnalyticDtoImpl && + (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) && + (identical(other.groupBy, groupBy) || other.groupBy == groupBy) && + (identical(other.summary, summary) || other.summary == summary) && + const DeepCollectionEquality().equals(other._data, _data)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + organizationId, + outletId, + dateFrom, + dateTo, + groupBy, + summary, + const DeepCollectionEquality().hash(_data), + ); + + /// Create a copy of SalesAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SalesAnalyticDtoImplCopyWith<_$SalesAnalyticDtoImpl> get copyWith => + __$$SalesAnalyticDtoImplCopyWithImpl<_$SalesAnalyticDtoImpl>( + this, + _$identity, + ); + + @override + Map toJson() { + return _$$SalesAnalyticDtoImplToJson(this); + } +} + +abstract class _SalesAnalyticDto extends SalesAnalyticDto { + const factory _SalesAnalyticDto({ + @JsonKey(name: "organization_id") final String? organizationId, + @JsonKey(name: "outlet_id") final String? outletId, + @JsonKey(name: "date_from") final DateTime? dateFrom, + @JsonKey(name: "date_to") final DateTime? dateTo, + @JsonKey(name: "group_by") final String? groupBy, + @JsonKey(name: "summary") final SalesSummaryDto? summary, + @JsonKey(name: "data") final List? data, + }) = _$SalesAnalyticDtoImpl; + const _SalesAnalyticDto._() : super._(); + + factory _SalesAnalyticDto.fromJson(Map json) = + _$SalesAnalyticDtoImpl.fromJson; + + @override + @JsonKey(name: "organization_id") + String? get organizationId; + @override + @JsonKey(name: "outlet_id") + String? get outletId; + @override + @JsonKey(name: "date_from") + DateTime? get dateFrom; + @override + @JsonKey(name: "date_to") + DateTime? get dateTo; + @override + @JsonKey(name: "group_by") + String? get groupBy; + @override + @JsonKey(name: "summary") + SalesSummaryDto? get summary; + @override + @JsonKey(name: "data") + List? get data; + + /// Create a copy of SalesAnalyticDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SalesAnalyticDtoImplCopyWith<_$SalesAnalyticDtoImpl> get copyWith => + throw _privateConstructorUsedError; +} + +SalesSummaryDto _$SalesSummaryDtoFromJson(Map json) { + return _SalesSummaryDto.fromJson(json); +} + +/// @nodoc +mixin _$SalesSummaryDto { + @JsonKey(name: "total_sales") + int? get totalSales => throw _privateConstructorUsedError; + @JsonKey(name: "total_orders") + int? get totalOrders => throw _privateConstructorUsedError; + @JsonKey(name: "total_items") + int? get totalItems => throw _privateConstructorUsedError; + @JsonKey(name: "average_order_value") + double? get averageOrderValue => throw _privateConstructorUsedError; + @JsonKey(name: "total_tax") + int? get totalTax => throw _privateConstructorUsedError; + @JsonKey(name: "total_discount") + int? get totalDiscount => throw _privateConstructorUsedError; + @JsonKey(name: "net_sales") + int? get netSales => throw _privateConstructorUsedError; + + /// Serializes this SalesSummaryDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of SalesSummaryDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SalesSummaryDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SalesSummaryDtoCopyWith<$Res> { + factory $SalesSummaryDtoCopyWith( + SalesSummaryDto value, + $Res Function(SalesSummaryDto) then, + ) = _$SalesSummaryDtoCopyWithImpl<$Res, SalesSummaryDto>; + @useResult + $Res call({ + @JsonKey(name: "total_sales") int? totalSales, + @JsonKey(name: "total_orders") int? totalOrders, + @JsonKey(name: "total_items") int? totalItems, + @JsonKey(name: "average_order_value") double? averageOrderValue, + @JsonKey(name: "total_tax") int? totalTax, + @JsonKey(name: "total_discount") int? totalDiscount, + @JsonKey(name: "net_sales") int? netSales, + }); +} + +/// @nodoc +class _$SalesSummaryDtoCopyWithImpl<$Res, $Val extends SalesSummaryDto> + implements $SalesSummaryDtoCopyWith<$Res> { + _$SalesSummaryDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SalesSummaryDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? totalSales = freezed, + Object? totalOrders = freezed, + Object? totalItems = freezed, + Object? averageOrderValue = freezed, + Object? totalTax = freezed, + Object? totalDiscount = freezed, + Object? netSales = freezed, + }) { + return _then( + _value.copyWith( + totalSales: freezed == totalSales + ? _value.totalSales + : totalSales // ignore: cast_nullable_to_non_nullable + as int?, + totalOrders: freezed == totalOrders + ? _value.totalOrders + : totalOrders // ignore: cast_nullable_to_non_nullable + as int?, + totalItems: freezed == totalItems + ? _value.totalItems + : totalItems // ignore: cast_nullable_to_non_nullable + as int?, + averageOrderValue: freezed == averageOrderValue + ? _value.averageOrderValue + : averageOrderValue // ignore: cast_nullable_to_non_nullable + as double?, + totalTax: freezed == totalTax + ? _value.totalTax + : totalTax // ignore: cast_nullable_to_non_nullable + as int?, + totalDiscount: freezed == totalDiscount + ? _value.totalDiscount + : totalDiscount // ignore: cast_nullable_to_non_nullable + as int?, + netSales: freezed == netSales + ? _value.netSales + : netSales // ignore: cast_nullable_to_non_nullable + as int?, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$SalesSummaryDtoImplCopyWith<$Res> + implements $SalesSummaryDtoCopyWith<$Res> { + factory _$$SalesSummaryDtoImplCopyWith( + _$SalesSummaryDtoImpl value, + $Res Function(_$SalesSummaryDtoImpl) then, + ) = __$$SalesSummaryDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @JsonKey(name: "total_sales") int? totalSales, + @JsonKey(name: "total_orders") int? totalOrders, + @JsonKey(name: "total_items") int? totalItems, + @JsonKey(name: "average_order_value") double? averageOrderValue, + @JsonKey(name: "total_tax") int? totalTax, + @JsonKey(name: "total_discount") int? totalDiscount, + @JsonKey(name: "net_sales") int? netSales, + }); +} + +/// @nodoc +class __$$SalesSummaryDtoImplCopyWithImpl<$Res> + extends _$SalesSummaryDtoCopyWithImpl<$Res, _$SalesSummaryDtoImpl> + implements _$$SalesSummaryDtoImplCopyWith<$Res> { + __$$SalesSummaryDtoImplCopyWithImpl( + _$SalesSummaryDtoImpl _value, + $Res Function(_$SalesSummaryDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of SalesSummaryDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? totalSales = freezed, + Object? totalOrders = freezed, + Object? totalItems = freezed, + Object? averageOrderValue = freezed, + Object? totalTax = freezed, + Object? totalDiscount = freezed, + Object? netSales = freezed, + }) { + return _then( + _$SalesSummaryDtoImpl( + totalSales: freezed == totalSales + ? _value.totalSales + : totalSales // ignore: cast_nullable_to_non_nullable + as int?, + totalOrders: freezed == totalOrders + ? _value.totalOrders + : totalOrders // ignore: cast_nullable_to_non_nullable + as int?, + totalItems: freezed == totalItems + ? _value.totalItems + : totalItems // ignore: cast_nullable_to_non_nullable + as int?, + averageOrderValue: freezed == averageOrderValue + ? _value.averageOrderValue + : averageOrderValue // ignore: cast_nullable_to_non_nullable + as double?, + totalTax: freezed == totalTax + ? _value.totalTax + : totalTax // ignore: cast_nullable_to_non_nullable + as int?, + totalDiscount: freezed == totalDiscount + ? _value.totalDiscount + : totalDiscount // ignore: cast_nullable_to_non_nullable + as int?, + netSales: freezed == netSales + ? _value.netSales + : netSales // ignore: cast_nullable_to_non_nullable + as int?, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$SalesSummaryDtoImpl extends _SalesSummaryDto { + const _$SalesSummaryDtoImpl({ + @JsonKey(name: "total_sales") this.totalSales, + @JsonKey(name: "total_orders") this.totalOrders, + @JsonKey(name: "total_items") this.totalItems, + @JsonKey(name: "average_order_value") this.averageOrderValue, + @JsonKey(name: "total_tax") this.totalTax, + @JsonKey(name: "total_discount") this.totalDiscount, + @JsonKey(name: "net_sales") this.netSales, + }) : super._(); + + factory _$SalesSummaryDtoImpl.fromJson(Map json) => + _$$SalesSummaryDtoImplFromJson(json); + + @override + @JsonKey(name: "total_sales") + final int? totalSales; + @override + @JsonKey(name: "total_orders") + final int? totalOrders; + @override + @JsonKey(name: "total_items") + final int? totalItems; + @override + @JsonKey(name: "average_order_value") + final double? averageOrderValue; + @override + @JsonKey(name: "total_tax") + final int? totalTax; + @override + @JsonKey(name: "total_discount") + final int? totalDiscount; + @override + @JsonKey(name: "net_sales") + final int? netSales; + + @override + String toString() { + return 'SalesSummaryDto(totalSales: $totalSales, totalOrders: $totalOrders, totalItems: $totalItems, averageOrderValue: $averageOrderValue, totalTax: $totalTax, totalDiscount: $totalDiscount, netSales: $netSales)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SalesSummaryDtoImpl && + (identical(other.totalSales, totalSales) || + other.totalSales == totalSales) && + (identical(other.totalOrders, totalOrders) || + other.totalOrders == totalOrders) && + (identical(other.totalItems, totalItems) || + other.totalItems == totalItems) && + (identical(other.averageOrderValue, averageOrderValue) || + other.averageOrderValue == averageOrderValue) && + (identical(other.totalTax, totalTax) || + other.totalTax == totalTax) && + (identical(other.totalDiscount, totalDiscount) || + other.totalDiscount == totalDiscount) && + (identical(other.netSales, netSales) || + other.netSales == netSales)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + totalSales, + totalOrders, + totalItems, + averageOrderValue, + totalTax, + totalDiscount, + netSales, + ); + + /// Create a copy of SalesSummaryDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SalesSummaryDtoImplCopyWith<_$SalesSummaryDtoImpl> get copyWith => + __$$SalesSummaryDtoImplCopyWithImpl<_$SalesSummaryDtoImpl>( + this, + _$identity, + ); + + @override + Map toJson() { + return _$$SalesSummaryDtoImplToJson(this); + } +} + +abstract class _SalesSummaryDto extends SalesSummaryDto { + const factory _SalesSummaryDto({ + @JsonKey(name: "total_sales") final int? totalSales, + @JsonKey(name: "total_orders") final int? totalOrders, + @JsonKey(name: "total_items") final int? totalItems, + @JsonKey(name: "average_order_value") final double? averageOrderValue, + @JsonKey(name: "total_tax") final int? totalTax, + @JsonKey(name: "total_discount") final int? totalDiscount, + @JsonKey(name: "net_sales") final int? netSales, + }) = _$SalesSummaryDtoImpl; + const _SalesSummaryDto._() : super._(); + + factory _SalesSummaryDto.fromJson(Map json) = + _$SalesSummaryDtoImpl.fromJson; + + @override + @JsonKey(name: "total_sales") + int? get totalSales; + @override + @JsonKey(name: "total_orders") + int? get totalOrders; + @override + @JsonKey(name: "total_items") + int? get totalItems; + @override + @JsonKey(name: "average_order_value") + double? get averageOrderValue; + @override + @JsonKey(name: "total_tax") + int? get totalTax; + @override + @JsonKey(name: "total_discount") + int? get totalDiscount; + @override + @JsonKey(name: "net_sales") + int? get netSales; + + /// Create a copy of SalesSummaryDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SalesSummaryDtoImplCopyWith<_$SalesSummaryDtoImpl> get copyWith => + throw _privateConstructorUsedError; +} + +SalesAnalyticItemDto _$SalesAnalyticItemDtoFromJson(Map json) { + return _SalesAnalyticItemDto.fromJson(json); +} + +/// @nodoc +mixin _$SalesAnalyticItemDto { + @JsonKey(name: "date") + DateTime? get date => throw _privateConstructorUsedError; + @JsonKey(name: "sales") + int? get sales => throw _privateConstructorUsedError; + @JsonKey(name: "orders") + int? get orders => throw _privateConstructorUsedError; + @JsonKey(name: "items") + int? get items => throw _privateConstructorUsedError; + @JsonKey(name: "tax") + int? get tax => throw _privateConstructorUsedError; + @JsonKey(name: "discount") + int? get discount => throw _privateConstructorUsedError; + @JsonKey(name: "net_sales") + int? get netSales => throw _privateConstructorUsedError; + + /// Serializes this SalesAnalyticItemDto to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of SalesAnalyticItemDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SalesAnalyticItemDtoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SalesAnalyticItemDtoCopyWith<$Res> { + factory $SalesAnalyticItemDtoCopyWith( + SalesAnalyticItemDto value, + $Res Function(SalesAnalyticItemDto) then, + ) = _$SalesAnalyticItemDtoCopyWithImpl<$Res, SalesAnalyticItemDto>; + @useResult + $Res call({ + @JsonKey(name: "date") DateTime? 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, + }); +} + +/// @nodoc +class _$SalesAnalyticItemDtoCopyWithImpl< + $Res, + $Val extends SalesAnalyticItemDto +> + implements $SalesAnalyticItemDtoCopyWith<$Res> { + _$SalesAnalyticItemDtoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SalesAnalyticItemDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = freezed, + Object? sales = freezed, + Object? orders = freezed, + Object? items = freezed, + Object? tax = freezed, + Object? discount = freezed, + Object? netSales = freezed, + }) { + return _then( + _value.copyWith( + date: freezed == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as DateTime?, + sales: freezed == sales + ? _value.sales + : sales // ignore: cast_nullable_to_non_nullable + as int?, + orders: freezed == orders + ? _value.orders + : orders // ignore: cast_nullable_to_non_nullable + as int?, + items: freezed == items + ? _value.items + : items // ignore: cast_nullable_to_non_nullable + as int?, + tax: freezed == tax + ? _value.tax + : tax // ignore: cast_nullable_to_non_nullable + as int?, + discount: freezed == discount + ? _value.discount + : discount // ignore: cast_nullable_to_non_nullable + as int?, + netSales: freezed == netSales + ? _value.netSales + : netSales // ignore: cast_nullable_to_non_nullable + as int?, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$SalesAnalyticItemDtoImplCopyWith<$Res> + implements $SalesAnalyticItemDtoCopyWith<$Res> { + factory _$$SalesAnalyticItemDtoImplCopyWith( + _$SalesAnalyticItemDtoImpl value, + $Res Function(_$SalesAnalyticItemDtoImpl) then, + ) = __$$SalesAnalyticItemDtoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + @JsonKey(name: "date") DateTime? 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, + }); +} + +/// @nodoc +class __$$SalesAnalyticItemDtoImplCopyWithImpl<$Res> + extends _$SalesAnalyticItemDtoCopyWithImpl<$Res, _$SalesAnalyticItemDtoImpl> + implements _$$SalesAnalyticItemDtoImplCopyWith<$Res> { + __$$SalesAnalyticItemDtoImplCopyWithImpl( + _$SalesAnalyticItemDtoImpl _value, + $Res Function(_$SalesAnalyticItemDtoImpl) _then, + ) : super(_value, _then); + + /// Create a copy of SalesAnalyticItemDto + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = freezed, + Object? sales = freezed, + Object? orders = freezed, + Object? items = freezed, + Object? tax = freezed, + Object? discount = freezed, + Object? netSales = freezed, + }) { + return _then( + _$SalesAnalyticItemDtoImpl( + date: freezed == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as DateTime?, + sales: freezed == sales + ? _value.sales + : sales // ignore: cast_nullable_to_non_nullable + as int?, + orders: freezed == orders + ? _value.orders + : orders // ignore: cast_nullable_to_non_nullable + as int?, + items: freezed == items + ? _value.items + : items // ignore: cast_nullable_to_non_nullable + as int?, + tax: freezed == tax + ? _value.tax + : tax // ignore: cast_nullable_to_non_nullable + as int?, + discount: freezed == discount + ? _value.discount + : discount // ignore: cast_nullable_to_non_nullable + as int?, + netSales: freezed == netSales + ? _value.netSales + : netSales // ignore: cast_nullable_to_non_nullable + as int?, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$SalesAnalyticItemDtoImpl extends _SalesAnalyticItemDto { + const _$SalesAnalyticItemDtoImpl({ + @JsonKey(name: "date") this.date, + @JsonKey(name: "sales") this.sales, + @JsonKey(name: "orders") this.orders, + @JsonKey(name: "items") this.items, + @JsonKey(name: "tax") this.tax, + @JsonKey(name: "discount") this.discount, + @JsonKey(name: "net_sales") this.netSales, + }) : super._(); + + factory _$SalesAnalyticItemDtoImpl.fromJson(Map json) => + _$$SalesAnalyticItemDtoImplFromJson(json); + + @override + @JsonKey(name: "date") + final DateTime? date; + @override + @JsonKey(name: "sales") + final int? sales; + @override + @JsonKey(name: "orders") + final int? orders; + @override + @JsonKey(name: "items") + final int? items; + @override + @JsonKey(name: "tax") + final int? tax; + @override + @JsonKey(name: "discount") + final int? discount; + @override + @JsonKey(name: "net_sales") + final int? netSales; + + @override + String toString() { + return 'SalesAnalyticItemDto(date: $date, sales: $sales, orders: $orders, items: $items, tax: $tax, discount: $discount, netSales: $netSales)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SalesAnalyticItemDtoImpl && + (identical(other.date, date) || other.date == date) && + (identical(other.sales, sales) || other.sales == sales) && + (identical(other.orders, orders) || other.orders == orders) && + (identical(other.items, items) || other.items == items) && + (identical(other.tax, tax) || other.tax == tax) && + (identical(other.discount, discount) || + other.discount == discount) && + (identical(other.netSales, netSales) || + other.netSales == netSales)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + date, + sales, + orders, + items, + tax, + discount, + netSales, + ); + + /// Create a copy of SalesAnalyticItemDto + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SalesAnalyticItemDtoImplCopyWith<_$SalesAnalyticItemDtoImpl> + get copyWith => + __$$SalesAnalyticItemDtoImplCopyWithImpl<_$SalesAnalyticItemDtoImpl>( + this, + _$identity, + ); + + @override + Map toJson() { + return _$$SalesAnalyticItemDtoImplToJson(this); + } +} + +abstract class _SalesAnalyticItemDto extends SalesAnalyticItemDto { + const factory _SalesAnalyticItemDto({ + @JsonKey(name: "date") final DateTime? date, + @JsonKey(name: "sales") final int? sales, + @JsonKey(name: "orders") final int? orders, + @JsonKey(name: "items") final int? items, + @JsonKey(name: "tax") final int? tax, + @JsonKey(name: "discount") final int? discount, + @JsonKey(name: "net_sales") final int? netSales, + }) = _$SalesAnalyticItemDtoImpl; + const _SalesAnalyticItemDto._() : super._(); + + factory _SalesAnalyticItemDto.fromJson(Map json) = + _$SalesAnalyticItemDtoImpl.fromJson; + + @override + @JsonKey(name: "date") + DateTime? get date; + @override + @JsonKey(name: "sales") + int? get sales; + @override + @JsonKey(name: "orders") + int? get orders; + @override + @JsonKey(name: "items") + int? get items; + @override + @JsonKey(name: "tax") + int? get tax; + @override + @JsonKey(name: "discount") + int? get discount; + @override + @JsonKey(name: "net_sales") + int? get netSales; + + /// Create a copy of SalesAnalyticItemDto + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SalesAnalyticItemDtoImplCopyWith<_$SalesAnalyticItemDtoImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/infrastructure/analytic/analytic_dtos.g.dart b/lib/infrastructure/analytic/analytic_dtos.g.dart index 08c70ef..47a962a 100644 --- a/lib/infrastructure/analytic/analytic_dtos.g.dart +++ b/lib/infrastructure/analytic/analytic_dtos.g.dart @@ -137,3 +137,83 @@ Map _$$DashboardRecentSaleDtoImplToJson( 'discount': instance.discount, 'net_sales': instance.netSales, }; + +_$SalesAnalyticDtoImpl _$$SalesAnalyticDtoImplFromJson( + Map 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 + : SalesSummaryDto.fromJson(json['summary'] as Map), + data: (json['data'] as List?) + ?.map((e) => SalesAnalyticItemDto.fromJson(e as Map)) + .toList(), +); + +Map _$$SalesAnalyticDtoImplToJson( + _$SalesAnalyticDtoImpl instance, +) => { + '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, +}; + +_$SalesSummaryDtoImpl _$$SalesSummaryDtoImplFromJson( + Map json, +) => _$SalesSummaryDtoImpl( + totalSales: (json['total_sales'] as num?)?.toInt(), + totalOrders: (json['total_orders'] as num?)?.toInt(), + totalItems: (json['total_items'] as num?)?.toInt(), + averageOrderValue: (json['average_order_value'] as num?)?.toDouble(), + totalTax: (json['total_tax'] as num?)?.toInt(), + totalDiscount: (json['total_discount'] as num?)?.toInt(), + netSales: (json['net_sales'] as num?)?.toInt(), +); + +Map _$$SalesSummaryDtoImplToJson( + _$SalesSummaryDtoImpl instance, +) => { + '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, +}; + +_$SalesAnalyticItemDtoImpl _$$SalesAnalyticItemDtoImplFromJson( + Map json, +) => _$SalesAnalyticItemDtoImpl( + date: json['date'] == null ? null : DateTime.parse(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 _$$SalesAnalyticItemDtoImplToJson( + _$SalesAnalyticItemDtoImpl instance, +) => { + 'date': instance.date?.toIso8601String(), + 'sales': instance.sales, + 'orders': instance.orders, + 'items': instance.items, + 'tax': instance.tax, + 'discount': instance.discount, + 'net_sales': instance.netSales, +}; diff --git a/lib/infrastructure/analytic/datasources/remote_data_provider.dart b/lib/infrastructure/analytic/datasources/remote_data_provider.dart index 1290d44..1dd0d12 100644 --- a/lib/infrastructure/analytic/datasources/remote_data_provider.dart +++ b/lib/infrastructure/analytic/datasources/remote_data_provider.dart @@ -47,4 +47,33 @@ class AnalyticRemoteDataProvider { return DC.error(AnalyticFailure.serverError(e)); } } + + Future> fetchSales({ + required DateTime dateFrom, + required DateTime dateTo, + }) async { + try { + final response = await _apiClient.get( + ApiPath.analyticSales, + params: { + 'date_from': dateFrom.toServerDate(), + 'date_to': dateTo.toServerDate(), + }, + headers: getAuthorizationHeader(), + ); + + if (response.data['success'] == false) { + return DC.error(AnalyticFailure.unexpectedError()); + } + + final sales = SalesAnalyticDto.fromJson( + response.data['data'] as Map, + ); + + return DC.data(sales); + } on ApiFailure catch (e, s) { + log('fetchSales', name: _logName, error: e, stackTrace: s); + return DC.error(AnalyticFailure.serverError(e)); + } + } } diff --git a/lib/infrastructure/analytic/dtos/sales_dto.dart b/lib/infrastructure/analytic/dtos/sales_dto.dart new file mode 100644 index 0000000..b079ce7 --- /dev/null +++ b/lib/infrastructure/analytic/dtos/sales_dto.dart @@ -0,0 +1,88 @@ +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") SalesSummaryDto? summary, + @JsonKey(name: "data") List? data, + }) = _SalesAnalyticDto; + + factory SalesAnalyticDto.fromJson(Map json) => + _$SalesAnalyticDtoFromJson(json); + + // Optional mapping ke domain + SalesAnalytic toDomain() => SalesAnalytic( + organizationId: organizationId ?? '', + outletId: outletId ?? '', + dateFrom: dateFrom ?? DateTime.now(), + dateTo: dateTo ?? DateTime.now(), + groupBy: groupBy ?? '', + summary: summary?.toDomain() ?? SalesSummary.empty(), + data: data?.map((e) => e.toDomain()).toList() ?? [], + ); +} + +@freezed +class SalesSummaryDto with _$SalesSummaryDto { + const SalesSummaryDto._(); + + const factory SalesSummaryDto({ + @JsonKey(name: "total_sales") int? totalSales, + @JsonKey(name: "total_orders") int? totalOrders, + @JsonKey(name: "total_items") int? totalItems, + @JsonKey(name: "average_order_value") double? averageOrderValue, + @JsonKey(name: "total_tax") int? totalTax, + @JsonKey(name: "total_discount") int? totalDiscount, + @JsonKey(name: "net_sales") int? netSales, + }) = _SalesSummaryDto; + + factory SalesSummaryDto.fromJson(Map json) => + _$SalesSummaryDtoFromJson(json); + + // Optional mapping ke domain + SalesSummary toDomain() => SalesSummary( + totalSales: totalSales ?? 0, + totalOrders: totalOrders ?? 0, + totalItems: totalItems ?? 0, + averageOrderValue: averageOrderValue ?? 0.0, + totalTax: totalTax ?? 0, + totalDiscount: totalDiscount ?? 0, + netSales: netSales ?? 0, + ); +} + +@freezed +class SalesAnalyticItemDto with _$SalesAnalyticItemDto { + const SalesAnalyticItemDto._(); + + const factory SalesAnalyticItemDto({ + @JsonKey(name: "date") DateTime? 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, + }) = _SalesAnalyticItemDto; + + factory SalesAnalyticItemDto.fromJson(Map json) => + _$SalesAnalyticItemDtoFromJson(json); + + // Optional mapping ke domain + SalesAnalyticItem toDomain() => SalesAnalyticItem( + date: date ?? DateTime.now(), + sales: sales ?? 0, + orders: orders ?? 0, + items: items ?? 0, + tax: tax ?? 0, + discount: discount ?? 0, + netSales: netSales ?? 0, + ); +} diff --git a/lib/infrastructure/analytic/repositories/analytic_repository.dart b/lib/infrastructure/analytic/repositories/analytic_repository.dart index 366b591..7deb4a6 100644 --- a/lib/infrastructure/analytic/repositories/analytic_repository.dart +++ b/lib/infrastructure/analytic/repositories/analytic_repository.dart @@ -37,4 +37,28 @@ class AnalyticRepository implements IAnalyticRepository { return left(const AnalyticFailure.unexpectedError()); } } + + @override + Future> 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 sales = result.data!.toDomain(); + + return right(sales); + } catch (e) { + log('getSalesError', name: _logName, error: e); + return left(const AnalyticFailure.unexpectedError()); + } + } } diff --git a/lib/injection.config.dart b/lib/injection.config.dart index a8efc5e..668f16a 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -11,6 +11,8 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:apskel_pos_flutter_v2/application/analytic/dashboard_analytic_loader/dashboard_analytic_loader_bloc.dart' as _i80; +import 'package:apskel_pos_flutter_v2/application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.dart' + as _i413; import 'package:apskel_pos_flutter_v2/application/auth/auth_bloc.dart' as _i343; import 'package:apskel_pos_flutter_v2/application/auth/login_form/login_form_bloc.dart' as _i46; @@ -138,8 +140,8 @@ extension GetItInjectableX on _i174.GetIt { () => sharedPreferencesDi.prefs, preResolve: true, ); - gh.factory<_i13.CheckoutFormBloc>(() => _i13.CheckoutFormBloc()); gh.factory<_i334.SplitBillFormBloc>(() => _i334.SplitBillFormBloc()); + gh.factory<_i13.CheckoutFormBloc>(() => _i13.CheckoutFormBloc()); gh.factory<_i257.ReportBloc>(() => _i257.ReportBloc()); gh.singleton<_i487.DatabaseHelper>(() => databaseDi.databaseHelper); gh.lazySingleton<_i361.Dio>(() => dioDi.dio); @@ -186,12 +188,12 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i95.TableRemoteDataProvider>( () => _i95.TableRemoteDataProvider(gh<_i457.ApiClient>()), ); - gh.factory<_i841.CustomerRemoteDataProvider>( - () => _i841.CustomerRemoteDataProvider(gh<_i457.ApiClient>()), - ); gh.factory<_i708.AnalyticRemoteDataProvider>( () => _i708.AnalyticRemoteDataProvider(gh<_i457.ApiClient>()), ); + gh.factory<_i841.CustomerRemoteDataProvider>( + () => _i841.CustomerRemoteDataProvider(gh<_i457.ApiClient>()), + ); gh.factory<_i776.IAuthRepository>( () => _i941.AuthRepository( gh<_i370.AuthRemoteDataProvider>(), @@ -293,6 +295,9 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i80.DashboardAnalyticLoaderBloc>( () => _i80.DashboardAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()), ); + gh.factory<_i413.SalesAnalyticLoaderBloc>( + () => _i413.SalesAnalyticLoaderBloc(gh<_i346.IAnalyticRepository>()), + ); return this; } } diff --git a/lib/presentation/components/widgets/report/report_summary_card.dart b/lib/presentation/components/widgets/report/report_summary_card.dart index 398cfac..1b20a38 100644 --- a/lib/presentation/components/widgets/report/report_summary_card.dart +++ b/lib/presentation/components/widgets/report/report_summary_card.dart @@ -23,7 +23,6 @@ class ReportSummaryCard extends StatelessWidget { decoration: BoxDecoration( color: AppColor.white, borderRadius: BorderRadius.circular(14), - border: Border.all(color: Colors.grey[200]!), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/presentation/pages/main/pages/report/report_page.dart b/lib/presentation/pages/main/pages/report/report_page.dart index f1faf28..bb16fba 100644 --- a/lib/presentation/pages/main/pages/report/report_page.dart +++ b/lib/presentation/pages/main/pages/report/report_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../../../application/analytic/dashboard_analytic_loader/dashboard_analytic_loader_bloc.dart'; +import '../../../../../application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.dart'; import '../../../../../application/report/report_bloc.dart'; import '../../../../../common/data/report_menu.dart'; import '../../../../../common/theme/theme.dart'; @@ -13,6 +14,7 @@ import '../../../../components/picker/date_range_picker.dart'; import '../../../../components/spaces/space.dart'; import '../../../../router/app_router.gr.dart'; import 'sections/report_dashboard_section.dart'; +import 'sections/report_sales_section.dart'; import 'widgets/report_menu_card.dart'; @RoutePage() @@ -119,7 +121,20 @@ class ReportPage extends StatelessWidget implements AutoRouteWrapper { }, ), 1 => Text(state.title), - 2 => Text(state.title), + 2 => + BlocBuilder< + SalesAnalyticLoaderBloc, + SalesAnalyticLoaderState + >( + builder: (context, sales) { + return ReportSalesSection( + menu: reportMenus[state.selectedMenu], + state: sales, + startDate: state.startDate, + endDate: state.endDate, + ); + }, + ), 3 => Text(state.title), 4 => Text(state.title), 5 => Text(state.title), @@ -151,6 +166,12 @@ class ReportPage extends StatelessWidget implements AutoRouteWrapper { ); case 1: case 2: + return context.read().add( + SalesAnalyticLoaderEvent.fetched( + startDate: state.startDate, + endDate: state.endDate, + ), + ); case 3: case 4: case 5: @@ -174,6 +195,15 @@ class ReportPage extends StatelessWidget implements AutoRouteWrapper { ), ), ), + BlocProvider( + create: (context) => getIt() + ..add( + SalesAnalyticLoaderEvent.fetched( + startDate: DateTime.now().subtract(const Duration(days: 30)), + endDate: DateTime.now(), + ), + ), + ), ], child: this, ); diff --git a/lib/presentation/pages/main/pages/report/sections/report_sales_section.dart b/lib/presentation/pages/main/pages/report/sections/report_sales_section.dart new file mode 100644 index 0000000..58cfc57 --- /dev/null +++ b/lib/presentation/pages/main/pages/report/sections/report_sales_section.dart @@ -0,0 +1,260 @@ +import 'package:flutter/material.dart'; + +import '../../../../../../application/analytic/sales_analytic_loader/sales_analytic_loader_bloc.dart'; +import '../../../../../../common/data/report_menu.dart'; +import '../../../../../../common/extension/extension.dart'; +import '../../../../../../common/theme/theme.dart'; +import '../../../../../components/loader/loader_with_text.dart'; +import '../../../../../components/spaces/space.dart'; +import '../../../../../components/widgets/report/report_header.dart'; +import '../../../../../components/widgets/report/report_summary_card.dart'; + +class ReportSalesSection extends StatelessWidget { + final ReportMenu menu; + final SalesAnalyticLoaderState state; + final DateTime startDate; + final DateTime endDate; + const ReportSalesSection({ + super.key, + required this.menu, + required this.state, + required this.startDate, + required this.endDate, + }); + + @override + Widget build(BuildContext context) { + if (state.isFetching) { + return const Center(child: LoaderWithText()); + } + + return ListView( + padding: EdgeInsets.all(16), + children: [ + ReportHeader(menu: menu, endDate: endDate, startDate: startDate), + _buildSummary(), + Container( + margin: EdgeInsets.only(top: 16), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(14), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Kinerja Harian', + style: AppStyle.lg.copyWith( + fontWeight: FontWeight.w600, + color: AppColor.textPrimary, + ), + ), + SpaceHeight(12), + ListView.builder( + itemCount: state.salesAnalytic.sortedDailyData.length, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + final dayData = state.salesAnalytic.sortedDailyData[index]; + return _buildDailyPerformanceItem( + date: dayData.date.toSimpleMonthDate(), + sales: dayData.sales.currencyFormatRpV2, + orders: dayData.orders, + items: dayData.items, + isHighest: dayData == state.salesAnalytic.highestRevenueDay, + ); + }, + ), + ], + ), + ), + SpaceHeight(16), + _buildSummaryFooter(), + ], + ); + } + + Widget _buildSummaryFooter() { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppColor.white, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: AppColor.success, + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Text( + 'Kinerja puncak pada ${state.salesAnalytic.highestRevenueDay.date.toSimpleMonthDate()} dengan pendapatan ${state.salesAnalytic.highestRevenueDay.sales.currencyFormatRpV2} (pesanan ${state.salesAnalytic.highestRevenueDay.orders})', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: const Color(0xFF374151), + ), + ), + ), + ], + ), + ); + } + + Widget _buildDailyPerformanceItem({ + required String date, + required String sales, + required int orders, + required int items, + required bool isHighest, + }) { + return Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: isHighest ? const Color(0xFF10B981) : const Color(0xFFE5E7EB), + width: isHighest ? 2 : 1, + ), + ), + child: Row( + children: [ + Container( + width: 60, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + date, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: const Color(0xFF111827), + ), + ), + if (isHighest) + Container( + margin: const EdgeInsets.only(top: 4), + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ), + decoration: BoxDecoration( + color: const Color(0xFF10B981), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + 'TOP', + style: TextStyle( + fontSize: 8, + fontWeight: FontWeight.w700, + color: Colors.white, + ), + ), + ), + ], + ), + ), + const SizedBox(width: 16), + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + sales, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + color: const Color(0xFF111827), + ), + ), + Text( + 'Pendapatan', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w400, + color: const Color(0xFF6B7280), + ), + ), + ], + ), + ), + Expanded( + flex: 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + '$orders pesanan', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: const Color(0xFF374151), + ), + ), + Text( + '$items item', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w400, + color: const Color(0xFF6B7280), + ), + ), + ], + ), + ), + ], + ), + ); + } + + Padding _buildSummary() { + return Padding( + padding: const EdgeInsets.only(top: 16), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: ReportSummaryCard( + color: AppColor.success, + icon: Icons.trending_up, + title: "Jumlah Penjualan", + value: + state.salesAnalytic.summary.totalSales.currencyFormatRpV2, + ), + ), + SpaceWidth(12), + Expanded( + child: ReportSummaryCard( + color: AppColor.info, + icon: Icons.shopping_cart_outlined, + title: "Jumlah Pesanan", + value: state.salesAnalytic.summary.totalOrders.toString(), + ), + ), + ], + ), + SpaceHeight(12), + ReportSummaryCard( + color: AppColor.primary, + icon: Icons.attach_money_outlined, + title: "Nilai Pesanan Rata-rata", + value: state.salesAnalytic.summary.averageOrderValue.toString(), + ), + ], + ), + ); + } +}