Compare commits

...

2 Commits

Author SHA1 Message Date
Efril
602647ff26 Merge branch 'main' of https://gits.altru.id/apksel-dev/apskel-owner-flutter 2026-05-19 23:08:20 +07:00
Efril
d9a553708b purchasing analytic repo 2026-05-19 23:08:01 +07:00
17 changed files with 4347 additions and 0 deletions

View File

@ -0,0 +1,54 @@
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';
import '../../../domain/analytic/repositories/i_analytic_repository.dart';
part 'purchasing_analytic_loader_event.dart';
part 'purchasing_analytic_loader_state.dart';
part 'purchasing_analytic_loader_bloc.freezed.dart';
@injectable
class PurchasingAnalyticLoaderBloc
extends Bloc<PurchasingAnalyticLoaderEvent, PurchasingAnalyticLoaderState> {
final IAnalyticRepository _analyticRepository;
PurchasingAnalyticLoaderBloc(this._analyticRepository)
: super(PurchasingAnalyticLoaderState.initial()) {
on<PurchasingAnalyticLoaderEvent>(_onEvent);
}
Future<void> _onEvent(
PurchasingAnalyticLoaderEvent event,
Emitter<PurchasingAnalyticLoaderState> emit,
) {
return event.map(
rangeDateChanged: (e) async {
emit(state.copyWith(dateFrom: e.dateFrom, dateTo: e.dateTo));
},
fetched: (e) async {
emit(
state.copyWith(
isFetching: true,
failureOptionPurchasing: none(),
),
);
final result = await _analyticRepository.getPurchasing(
dateFrom: state.dateFrom,
dateTo: state.dateTo,
);
final newState = result.fold(
(f) =>
state.copyWith(failureOptionPurchasing: optionOf(f)),
(purchasing) => state.copyWith(purchasing: purchasing),
);
emit(newState.copyWith(isFetching: false));
},
);
}
}

View File

@ -0,0 +1,627 @@
// 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 'purchasing_analytic_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(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 _$PurchasingAnalyticLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime dateFrom, DateTime dateTo)
rangeDateChanged,
required TResult Function() fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function()? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function()? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PurchasingAnalyticLoaderEventCopyWith<$Res> {
factory $PurchasingAnalyticLoaderEventCopyWith(
PurchasingAnalyticLoaderEvent value,
$Res Function(PurchasingAnalyticLoaderEvent) then,
) =
_$PurchasingAnalyticLoaderEventCopyWithImpl<
$Res,
PurchasingAnalyticLoaderEvent
>;
}
/// @nodoc
class _$PurchasingAnalyticLoaderEventCopyWithImpl<
$Res,
$Val extends PurchasingAnalyticLoaderEvent
>
implements $PurchasingAnalyticLoaderEventCopyWith<$Res> {
_$PurchasingAnalyticLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of PurchasingAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$RangeDateChangedImplCopyWith<$Res> {
factory _$$RangeDateChangedImplCopyWith(
_$RangeDateChangedImpl value,
$Res Function(_$RangeDateChangedImpl) then,
) = __$$RangeDateChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({DateTime dateFrom, DateTime dateTo});
}
/// @nodoc
class __$$RangeDateChangedImplCopyWithImpl<$Res>
extends
_$PurchasingAnalyticLoaderEventCopyWithImpl<
$Res,
_$RangeDateChangedImpl
>
implements _$$RangeDateChangedImplCopyWith<$Res> {
__$$RangeDateChangedImplCopyWithImpl(
_$RangeDateChangedImpl _value,
$Res Function(_$RangeDateChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of PurchasingAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? dateFrom = null, Object? dateTo = null}) {
return _then(
_$RangeDateChangedImpl(
null == dateFrom
? _value.dateFrom
: dateFrom // ignore: cast_nullable_to_non_nullable
as DateTime,
null == dateTo
? _value.dateTo
: dateTo // ignore: cast_nullable_to_non_nullable
as DateTime,
),
);
}
}
/// @nodoc
class _$RangeDateChangedImpl implements _RangeDateChanged {
const _$RangeDateChangedImpl(this.dateFrom, this.dateTo);
@override
final DateTime dateFrom;
@override
final DateTime dateTo;
@override
String toString() {
return 'PurchasingAnalyticLoaderEvent.rangeDateChanged(dateFrom: $dateFrom, dateTo: $dateTo)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$RangeDateChangedImpl &&
(identical(other.dateFrom, dateFrom) ||
other.dateFrom == dateFrom) &&
(identical(other.dateTo, dateTo) || other.dateTo == dateTo));
}
@override
int get hashCode => Object.hash(runtimeType, dateFrom, dateTo);
/// Create a copy of PurchasingAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$RangeDateChangedImplCopyWith<_$RangeDateChangedImpl> get copyWith =>
__$$RangeDateChangedImplCopyWithImpl<_$RangeDateChangedImpl>(
this,
_$identity,
);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime dateFrom, DateTime dateTo)
rangeDateChanged,
required TResult Function() fetched,
}) {
return rangeDateChanged(dateFrom, dateTo);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function()? fetched,
}) {
return rangeDateChanged?.call(dateFrom, dateTo);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function()? fetched,
required TResult orElse(),
}) {
if (rangeDateChanged != null) {
return rangeDateChanged(dateFrom, dateTo);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_Fetched value) fetched,
}) {
return rangeDateChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return rangeDateChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (rangeDateChanged != null) {
return rangeDateChanged(this);
}
return orElse();
}
}
abstract class _RangeDateChanged implements PurchasingAnalyticLoaderEvent {
const factory _RangeDateChanged(
final DateTime dateFrom,
final DateTime dateTo,
) = _$RangeDateChangedImpl;
DateTime get dateFrom;
DateTime get dateTo;
/// Create a copy of PurchasingAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$RangeDateChangedImplCopyWith<_$RangeDateChangedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith(
_$FetchedImpl value,
$Res Function(_$FetchedImpl) then,
) = __$$FetchedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$FetchedImplCopyWithImpl<$Res>
extends _$PurchasingAnalyticLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of PurchasingAnalyticLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$FetchedImpl implements _Fetched {
const _$FetchedImpl();
@override
String toString() {
return 'PurchasingAnalyticLoaderEvent.fetched()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$FetchedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime dateFrom, DateTime dateTo)
rangeDateChanged,
required TResult Function() fetched,
}) {
return fetched();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function()? fetched,
}) {
return fetched?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function()? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements PurchasingAnalyticLoaderEvent {
const factory _Fetched() = _$FetchedImpl;
}
/// @nodoc
mixin _$PurchasingAnalyticLoaderState {
PurchasingAnalytic get purchasing => throw _privateConstructorUsedError;
Option<AnalyticFailure> get failureOptionPurchasing =>
throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
DateTime get dateFrom => throw _privateConstructorUsedError;
DateTime get dateTo => throw _privateConstructorUsedError;
/// Create a copy of PurchasingAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$PurchasingAnalyticLoaderStateCopyWith<PurchasingAnalyticLoaderState>
get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PurchasingAnalyticLoaderStateCopyWith<$Res> {
factory $PurchasingAnalyticLoaderStateCopyWith(
PurchasingAnalyticLoaderState value,
$Res Function(PurchasingAnalyticLoaderState) then,
) =
_$PurchasingAnalyticLoaderStateCopyWithImpl<
$Res,
PurchasingAnalyticLoaderState
>;
@useResult
$Res call({
PurchasingAnalytic purchasing,
Option<AnalyticFailure> failureOptionPurchasing,
bool isFetching,
DateTime dateFrom,
DateTime dateTo,
});
$PurchasingAnalyticCopyWith<$Res> get purchasing;
}
/// @nodoc
class _$PurchasingAnalyticLoaderStateCopyWithImpl<
$Res,
$Val extends PurchasingAnalyticLoaderState
>
implements $PurchasingAnalyticLoaderStateCopyWith<$Res> {
_$PurchasingAnalyticLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of PurchasingAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? purchasing = null,
Object? failureOptionPurchasing = null,
Object? isFetching = null,
Object? dateFrom = null,
Object? dateTo = null,
}) {
return _then(
_value.copyWith(
purchasing: null == purchasing
? _value.purchasing
: purchasing // ignore: cast_nullable_to_non_nullable
as PurchasingAnalytic,
failureOptionPurchasing: null == failureOptionPurchasing
? _value.failureOptionPurchasing
: failureOptionPurchasing // ignore: cast_nullable_to_non_nullable
as Option<AnalyticFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
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,
)
as $Val,
);
}
/// Create a copy of PurchasingAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$PurchasingAnalyticCopyWith<$Res> get purchasing {
return $PurchasingAnalyticCopyWith<$Res>(_value.purchasing, (value) {
return _then(_value.copyWith(purchasing: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$PurchasingAnalyticLoaderStateImplCopyWith<$Res>
implements $PurchasingAnalyticLoaderStateCopyWith<$Res> {
factory _$$PurchasingAnalyticLoaderStateImplCopyWith(
_$PurchasingAnalyticLoaderStateImpl value,
$Res Function(_$PurchasingAnalyticLoaderStateImpl) then,
) = __$$PurchasingAnalyticLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
PurchasingAnalytic purchasing,
Option<AnalyticFailure> failureOptionPurchasing,
bool isFetching,
DateTime dateFrom,
DateTime dateTo,
});
@override
$PurchasingAnalyticCopyWith<$Res> get purchasing;
}
/// @nodoc
class __$$PurchasingAnalyticLoaderStateImplCopyWithImpl<$Res>
extends
_$PurchasingAnalyticLoaderStateCopyWithImpl<
$Res,
_$PurchasingAnalyticLoaderStateImpl
>
implements _$$PurchasingAnalyticLoaderStateImplCopyWith<$Res> {
__$$PurchasingAnalyticLoaderStateImplCopyWithImpl(
_$PurchasingAnalyticLoaderStateImpl _value,
$Res Function(_$PurchasingAnalyticLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of PurchasingAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? purchasing = null,
Object? failureOptionPurchasing = null,
Object? isFetching = null,
Object? dateFrom = null,
Object? dateTo = null,
}) {
return _then(
_$PurchasingAnalyticLoaderStateImpl(
purchasing: null == purchasing
? _value.purchasing
: purchasing // ignore: cast_nullable_to_non_nullable
as PurchasingAnalytic,
failureOptionPurchasing: null == failureOptionPurchasing
? _value.failureOptionPurchasing
: failureOptionPurchasing // ignore: cast_nullable_to_non_nullable
as Option<AnalyticFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
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,
),
);
}
}
/// @nodoc
class _$PurchasingAnalyticLoaderStateImpl
implements _PurchasingAnalyticLoaderState {
const _$PurchasingAnalyticLoaderStateImpl({
required this.purchasing,
required this.failureOptionPurchasing,
this.isFetching = false,
required this.dateFrom,
required this.dateTo,
});
@override
final PurchasingAnalytic purchasing;
@override
final Option<AnalyticFailure> failureOptionPurchasing;
@override
@JsonKey()
final bool isFetching;
@override
final DateTime dateFrom;
@override
final DateTime dateTo;
@override
String toString() {
return 'PurchasingAnalyticLoaderState(purchasing: $purchasing, failureOptionPurchasing: $failureOptionPurchasing, isFetching: $isFetching, dateFrom: $dateFrom, dateTo: $dateTo)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$PurchasingAnalyticLoaderStateImpl &&
(identical(other.purchasing, purchasing) ||
other.purchasing == purchasing) &&
(identical(
other.failureOptionPurchasing,
failureOptionPurchasing,
) ||
other.failureOptionPurchasing == failureOptionPurchasing) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching) &&
(identical(other.dateFrom, dateFrom) ||
other.dateFrom == dateFrom) &&
(identical(other.dateTo, dateTo) || other.dateTo == dateTo));
}
@override
int get hashCode => Object.hash(
runtimeType,
purchasing,
failureOptionPurchasing,
isFetching,
dateFrom,
dateTo,
);
/// Create a copy of PurchasingAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$PurchasingAnalyticLoaderStateImplCopyWith<
_$PurchasingAnalyticLoaderStateImpl
>
get copyWith =>
__$$PurchasingAnalyticLoaderStateImplCopyWithImpl<
_$PurchasingAnalyticLoaderStateImpl
>(this, _$identity);
}
abstract class _PurchasingAnalyticLoaderState
implements PurchasingAnalyticLoaderState {
const factory _PurchasingAnalyticLoaderState({
required final PurchasingAnalytic purchasing,
required final Option<AnalyticFailure> failureOptionPurchasing,
final bool isFetching,
required final DateTime dateFrom,
required final DateTime dateTo,
}) = _$PurchasingAnalyticLoaderStateImpl;
@override
PurchasingAnalytic get purchasing;
@override
Option<AnalyticFailure> get failureOptionPurchasing;
@override
bool get isFetching;
@override
DateTime get dateFrom;
@override
DateTime get dateTo;
/// Create a copy of PurchasingAnalyticLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$PurchasingAnalyticLoaderStateImplCopyWith<
_$PurchasingAnalyticLoaderStateImpl
>
get copyWith => throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,11 @@
part of 'purchasing_analytic_loader_bloc.dart';
@freezed
class PurchasingAnalyticLoaderEvent with _$PurchasingAnalyticLoaderEvent {
const factory PurchasingAnalyticLoaderEvent.rangeDateChanged(
DateTime dateFrom,
DateTime dateTo,
) = _RangeDateChanged;
const factory PurchasingAnalyticLoaderEvent.fetched() = _Fetched;
}

View File

@ -0,0 +1,20 @@
part of 'purchasing_analytic_loader_bloc.dart';
@freezed
class PurchasingAnalyticLoaderState with _$PurchasingAnalyticLoaderState {
const factory PurchasingAnalyticLoaderState({
required PurchasingAnalytic purchasing,
required Option<AnalyticFailure> failureOptionPurchasing,
@Default(false) bool isFetching,
required DateTime dateFrom,
required DateTime dateTo,
}) = _PurchasingAnalyticLoaderState;
factory PurchasingAnalyticLoaderState.initial() =>
PurchasingAnalyticLoaderState(
purchasing: PurchasingAnalytic.empty(),
failureOptionPurchasing: none(),
dateFrom: DateTime.now().subtract(const Duration(days: 30)),
dateTo: DateTime.now(),
);
}

View File

@ -11,6 +11,7 @@ class ApiPath {
static const String productAnalytic = '/api/v1/analytics/products'; static const String productAnalytic = '/api/v1/analytics/products';
static const String paymentMethodAnalytic = static const String paymentMethodAnalytic =
'/api/v1/analytics/paymentMethods'; '/api/v1/analytics/paymentMethods';
static const String purchasingAnalytic = '/api/v1/analytics/purchasing';
// Inventory // Inventory
static const String inventoryReportDetail = static const String inventoryReportDetail =

View File

@ -11,4 +11,5 @@ part 'entities/inventory_analytic_entity.dart';
part 'entities/dashboard_analytic_entity.dart'; part 'entities/dashboard_analytic_entity.dart';
part 'entities/product_analytic_entity.dart'; part 'entities/product_analytic_entity.dart';
part 'entities/payment_method_analytic_entity.dart'; part 'entities/payment_method_analytic_entity.dart';
part 'entities/purchasing_analytic_entity.dart';
part 'failures/analytic_failure.dart'; part 'failures/analytic_failure.dart';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
part of '../analytic.dart';
@freezed
class PurchasingAnalytic with _$PurchasingAnalytic {
const factory PurchasingAnalytic({
required String organizationId,
required String outletId,
required String outletName,
required DateTime dateFrom,
required DateTime dateTo,
required String groupBy,
required PurchasingAnalyticSummary summary,
required List<PurchasingAnalyticData> data,
required List<PurchasingIngredientData> ingredientData,
required List<PurchasingVendorData> vendorData,
}) = _PurchasingAnalytic;
factory PurchasingAnalytic.empty() => PurchasingAnalytic(
organizationId: '',
outletId: '',
outletName: '',
dateFrom: DateTime.fromMillisecondsSinceEpoch(0),
dateTo: DateTime.fromMillisecondsSinceEpoch(0),
groupBy: '',
summary: PurchasingAnalyticSummary.empty(),
data: [],
ingredientData: [],
vendorData: [],
);
}
@freezed
class PurchasingAnalyticSummary with _$PurchasingAnalyticSummary {
const factory PurchasingAnalyticSummary({
required int totalPurchases,
required int totalPurchaseOrders,
required int totalQuantity,
required double averagePurchaseOrderValue,
required int totalIngredients,
required int totalVendors,
}) = _PurchasingAnalyticSummary;
factory PurchasingAnalyticSummary.empty() =>
const PurchasingAnalyticSummary(
totalPurchases: 0,
totalPurchaseOrders: 0,
totalQuantity: 0,
averagePurchaseOrderValue: 0,
totalIngredients: 0,
totalVendors: 0,
);
}
@freezed
class PurchasingAnalyticData with _$PurchasingAnalyticData {
const factory PurchasingAnalyticData({
required DateTime date,
required int purchases,
required int purchaseOrders,
required int quantity,
required int ingredients,
required int vendors,
}) = _PurchasingAnalyticData;
factory PurchasingAnalyticData.empty() => PurchasingAnalyticData(
date: DateTime.fromMillisecondsSinceEpoch(0),
purchases: 0,
purchaseOrders: 0,
quantity: 0,
ingredients: 0,
vendors: 0,
);
}
@freezed
class PurchasingIngredientData with _$PurchasingIngredientData {
const factory PurchasingIngredientData({
required String ingredientId,
required String ingredientName,
required int quantity,
required int totalCost,
required double averageUnitCost,
required int purchaseOrderCount,
}) = _PurchasingIngredientData;
factory PurchasingIngredientData.empty() =>
const PurchasingIngredientData(
ingredientId: '',
ingredientName: '',
quantity: 0,
totalCost: 0,
averageUnitCost: 0,
purchaseOrderCount: 0,
);
}
@freezed
class PurchasingVendorData with _$PurchasingVendorData {
const factory PurchasingVendorData({
required String vendorId,
required String vendorName,
required int totalCost,
required int purchaseOrderCount,
required int ingredientCount,
required int quantity,
}) = _PurchasingVendorData;
factory PurchasingVendorData.empty() => const PurchasingVendorData(
vendorId: '',
vendorName: '',
totalCost: 0,
purchaseOrderCount: 0,
ingredientCount: 0,
quantity: 0,
);
}

View File

@ -44,4 +44,10 @@ abstract class IAnalyticRepository {
required DateTime dateTo, required DateTime dateTo,
String? outletId, String? outletId,
}); });
Future<Either<AnalyticFailure, PurchasingAnalytic>> getPurchasing({
required DateTime dateFrom,
required DateTime dateTo,
String? outletId,
});
} }

View File

@ -12,3 +12,4 @@ part 'dto/inventory_analytic_dto.dart';
part 'dto/dashboard_analytic_dto.dart'; part 'dto/dashboard_analytic_dto.dart';
part 'dto/product_analytic_dto.dart'; part 'dto/product_analytic_dto.dart';
part 'dto/payment_method_analytic_dto.dart'; part 'dto/payment_method_analytic_dto.dart';
part 'dto/purchasing_analytic_dto.dart';

File diff suppressed because it is too large Load Diff

View File

@ -637,3 +637,139 @@ Map<String, dynamic> _$$PaymentMethodSummaryDtoImplToJson(
'total_payments': instance.totalPayments, 'total_payments': instance.totalPayments,
'average_order_value': instance.averageOrderValue, 'average_order_value': instance.averageOrderValue,
}; };
_$PurchasingAnalyticDtoImpl _$$PurchasingAnalyticDtoImplFromJson(
Map<String, dynamic> json,
) => _$PurchasingAnalyticDtoImpl(
organizationId: json['organization_id'] as String?,
outletId: json['outlet_id'] as String?,
outletName: json['outlet_name'] 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
: PurchasingAnalyticSummaryDto.fromJson(
json['summary'] as Map<String, dynamic>,
),
data: (json['data'] as List<dynamic>?)
?.map(
(e) => PurchasingAnalyticDataDto.fromJson(e as Map<String, dynamic>),
)
.toList(),
ingredientData: (json['ingredient_data'] as List<dynamic>?)
?.map(
(e) => PurchasingIngredientDataDto.fromJson(e as Map<String, dynamic>),
)
.toList(),
vendorData: (json['vendor_data'] as List<dynamic>?)
?.map((e) => PurchasingVendorDataDto.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$PurchasingAnalyticDtoImplToJson(
_$PurchasingAnalyticDtoImpl instance,
) => <String, dynamic>{
'organization_id': instance.organizationId,
'outlet_id': instance.outletId,
'outlet_name': instance.outletName,
'date_from': instance.dateFrom?.toIso8601String(),
'date_to': instance.dateTo?.toIso8601String(),
'group_by': instance.groupBy,
'summary': instance.summary,
'data': instance.data,
'ingredient_data': instance.ingredientData,
'vendor_data': instance.vendorData,
};
_$PurchasingAnalyticSummaryDtoImpl _$$PurchasingAnalyticSummaryDtoImplFromJson(
Map<String, dynamic> json,
) => _$PurchasingAnalyticSummaryDtoImpl(
totalPurchases: json['total_purchases'] as num?,
totalPurchaseOrders: json['total_purchase_orders'] as num?,
totalQuantity: json['total_quantity'] as num?,
averagePurchaseOrderValue: json['average_purchase_order_value'] as num?,
totalIngredients: json['total_ingredients'] as num?,
totalVendors: json['total_vendors'] as num?,
);
Map<String, dynamic> _$$PurchasingAnalyticSummaryDtoImplToJson(
_$PurchasingAnalyticSummaryDtoImpl instance,
) => <String, dynamic>{
'total_purchases': instance.totalPurchases,
'total_purchase_orders': instance.totalPurchaseOrders,
'total_quantity': instance.totalQuantity,
'average_purchase_order_value': instance.averagePurchaseOrderValue,
'total_ingredients': instance.totalIngredients,
'total_vendors': instance.totalVendors,
};
_$PurchasingAnalyticDataDtoImpl _$$PurchasingAnalyticDataDtoImplFromJson(
Map<String, dynamic> json,
) => _$PurchasingAnalyticDataDtoImpl(
date: json['date'] == null ? null : DateTime.parse(json['date'] as String),
purchases: json['purchases'] as num?,
purchaseOrders: json['purchase_orders'] as num?,
quantity: json['quantity'] as num?,
ingredients: json['ingredients'] as num?,
vendors: json['vendors'] as num?,
);
Map<String, dynamic> _$$PurchasingAnalyticDataDtoImplToJson(
_$PurchasingAnalyticDataDtoImpl instance,
) => <String, dynamic>{
'date': instance.date?.toIso8601String(),
'purchases': instance.purchases,
'purchase_orders': instance.purchaseOrders,
'quantity': instance.quantity,
'ingredients': instance.ingredients,
'vendors': instance.vendors,
};
_$PurchasingIngredientDataDtoImpl _$$PurchasingIngredientDataDtoImplFromJson(
Map<String, dynamic> json,
) => _$PurchasingIngredientDataDtoImpl(
ingredientId: json['ingredient_id'] as String?,
ingredientName: json['ingredient_name'] as String?,
quantity: json['quantity'] as num?,
totalCost: json['total_cost'] as num?,
averageUnitCost: json['average_unit_cost'] as num?,
purchaseOrderCount: json['purchase_order_count'] as num?,
);
Map<String, dynamic> _$$PurchasingIngredientDataDtoImplToJson(
_$PurchasingIngredientDataDtoImpl instance,
) => <String, dynamic>{
'ingredient_id': instance.ingredientId,
'ingredient_name': instance.ingredientName,
'quantity': instance.quantity,
'total_cost': instance.totalCost,
'average_unit_cost': instance.averageUnitCost,
'purchase_order_count': instance.purchaseOrderCount,
};
_$PurchasingVendorDataDtoImpl _$$PurchasingVendorDataDtoImplFromJson(
Map<String, dynamic> json,
) => _$PurchasingVendorDataDtoImpl(
vendorId: json['vendor_id'] as String?,
vendorName: json['vendor_name'] as String?,
totalCost: json['total_cost'] as num?,
purchaseOrderCount: json['purchase_order_count'] as num?,
ingredientCount: json['ingredient_count'] as num?,
quantity: json['quantity'] as num?,
);
Map<String, dynamic> _$$PurchasingVendorDataDtoImplToJson(
_$PurchasingVendorDataDtoImpl instance,
) => <String, dynamic>{
'vendor_id': instance.vendorId,
'vendor_name': instance.vendorName,
'total_cost': instance.totalCost,
'purchase_order_count': instance.purchaseOrderCount,
'ingredient_count': instance.ingredientCount,
'quantity': instance.quantity,
};

View File

@ -231,4 +231,35 @@ class AnalyticRemoteDataProvider {
return DC.error(AnalyticFailure.serverError(e)); return DC.error(AnalyticFailure.serverError(e));
} }
} }
Future<DC<AnalyticFailure, PurchasingAnalyticDto>> fetchPurchasing({
required DateTime dateFrom,
required DateTime dateTo,
String? outletId,
}) async {
try {
final Map<String, dynamic> params = {
'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate,
};
if (outletId != null) params['outlet_id'] = outletId;
final response = await _apiClient.get(
ApiPath.purchasingAnalytic,
params: params,
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(AnalyticFailure.empty());
}
final dto = PurchasingAnalyticDto.fromJson(response.data['data']);
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchPurchasingError', name: _logName, error: e, stackTrace: s);
return DC.error(AnalyticFailure.serverError(e));
}
}
} }

View File

@ -0,0 +1,143 @@
part of '../analytic_dtos.dart';
@freezed
class PurchasingAnalyticDto with _$PurchasingAnalyticDto {
const PurchasingAnalyticDto._();
const factory PurchasingAnalyticDto({
@JsonKey(name: 'organization_id') String? organizationId,
@JsonKey(name: 'outlet_id') String? outletId,
@JsonKey(name: 'outlet_name') String? outletName,
@JsonKey(name: 'date_from') DateTime? dateFrom,
@JsonKey(name: 'date_to') DateTime? dateTo,
@JsonKey(name: 'group_by') String? groupBy,
@JsonKey(name: 'summary') PurchasingAnalyticSummaryDto? summary,
@JsonKey(name: 'data') List<PurchasingAnalyticDataDto>? data,
@JsonKey(name: 'ingredient_data')
List<PurchasingIngredientDataDto>? ingredientData,
@JsonKey(name: 'vendor_data') List<PurchasingVendorDataDto>? vendorData,
}) = _PurchasingAnalyticDto;
factory PurchasingAnalyticDto.fromJson(Map<String, dynamic> json) =>
_$PurchasingAnalyticDtoFromJson(json);
PurchasingAnalytic toDomain() => PurchasingAnalytic(
organizationId: organizationId ?? '',
outletId: outletId ?? '',
outletName: outletName ?? '',
dateFrom: dateFrom ?? DateTime.fromMillisecondsSinceEpoch(0),
dateTo: dateTo ?? DateTime.fromMillisecondsSinceEpoch(0),
groupBy: groupBy ?? '',
summary: summary?.toDomain() ?? PurchasingAnalyticSummary.empty(),
data: data?.map((e) => e.toDomain()).toList() ?? [],
ingredientData:
ingredientData?.map((e) => e.toDomain()).toList() ?? [],
vendorData: vendorData?.map((e) => e.toDomain()).toList() ?? [],
);
}
@freezed
class PurchasingAnalyticSummaryDto with _$PurchasingAnalyticSummaryDto {
const PurchasingAnalyticSummaryDto._();
const factory PurchasingAnalyticSummaryDto({
@JsonKey(name: 'total_purchases') num? totalPurchases,
@JsonKey(name: 'total_purchase_orders') num? totalPurchaseOrders,
@JsonKey(name: 'total_quantity') num? totalQuantity,
@JsonKey(name: 'average_purchase_order_value')
num? averagePurchaseOrderValue,
@JsonKey(name: 'total_ingredients') num? totalIngredients,
@JsonKey(name: 'total_vendors') num? totalVendors,
}) = _PurchasingAnalyticSummaryDto;
factory PurchasingAnalyticSummaryDto.fromJson(Map<String, dynamic> json) =>
_$PurchasingAnalyticSummaryDtoFromJson(json);
PurchasingAnalyticSummary toDomain() => PurchasingAnalyticSummary(
totalPurchases: totalPurchases?.toInt() ?? 0,
totalPurchaseOrders: totalPurchaseOrders?.toInt() ?? 0,
totalQuantity: totalQuantity?.toInt() ?? 0,
averagePurchaseOrderValue:
averagePurchaseOrderValue?.toDouble() ?? 0,
totalIngredients: totalIngredients?.toInt() ?? 0,
totalVendors: totalVendors?.toInt() ?? 0,
);
}
@freezed
class PurchasingAnalyticDataDto with _$PurchasingAnalyticDataDto {
const PurchasingAnalyticDataDto._();
const factory PurchasingAnalyticDataDto({
@JsonKey(name: 'date') DateTime? date,
@JsonKey(name: 'purchases') num? purchases,
@JsonKey(name: 'purchase_orders') num? purchaseOrders,
@JsonKey(name: 'quantity') num? quantity,
@JsonKey(name: 'ingredients') num? ingredients,
@JsonKey(name: 'vendors') num? vendors,
}) = _PurchasingAnalyticDataDto;
factory PurchasingAnalyticDataDto.fromJson(Map<String, dynamic> json) =>
_$PurchasingAnalyticDataDtoFromJson(json);
PurchasingAnalyticData toDomain() => PurchasingAnalyticData(
date: date ?? DateTime.fromMillisecondsSinceEpoch(0),
purchases: purchases?.toInt() ?? 0,
purchaseOrders: purchaseOrders?.toInt() ?? 0,
quantity: quantity?.toInt() ?? 0,
ingredients: ingredients?.toInt() ?? 0,
vendors: vendors?.toInt() ?? 0,
);
}
@freezed
class PurchasingIngredientDataDto with _$PurchasingIngredientDataDto {
const PurchasingIngredientDataDto._();
const factory PurchasingIngredientDataDto({
@JsonKey(name: 'ingredient_id') String? ingredientId,
@JsonKey(name: 'ingredient_name') String? ingredientName,
@JsonKey(name: 'quantity') num? quantity,
@JsonKey(name: 'total_cost') num? totalCost,
@JsonKey(name: 'average_unit_cost') num? averageUnitCost,
@JsonKey(name: 'purchase_order_count') num? purchaseOrderCount,
}) = _PurchasingIngredientDataDto;
factory PurchasingIngredientDataDto.fromJson(Map<String, dynamic> json) =>
_$PurchasingIngredientDataDtoFromJson(json);
PurchasingIngredientData toDomain() => PurchasingIngredientData(
ingredientId: ingredientId ?? '',
ingredientName: ingredientName ?? '',
quantity: quantity?.toInt() ?? 0,
totalCost: totalCost?.toInt() ?? 0,
averageUnitCost: averageUnitCost?.toDouble() ?? 0,
purchaseOrderCount: purchaseOrderCount?.toInt() ?? 0,
);
}
@freezed
class PurchasingVendorDataDto with _$PurchasingVendorDataDto {
const PurchasingVendorDataDto._();
const factory PurchasingVendorDataDto({
@JsonKey(name: 'vendor_id') String? vendorId,
@JsonKey(name: 'vendor_name') String? vendorName,
@JsonKey(name: 'total_cost') num? totalCost,
@JsonKey(name: 'purchase_order_count') num? purchaseOrderCount,
@JsonKey(name: 'ingredient_count') num? ingredientCount,
@JsonKey(name: 'quantity') num? quantity,
}) = _PurchasingVendorDataDto;
factory PurchasingVendorDataDto.fromJson(Map<String, dynamic> json) =>
_$PurchasingVendorDataDtoFromJson(json);
PurchasingVendorData toDomain() => PurchasingVendorData(
vendorId: vendorId ?? '',
vendorName: vendorName ?? '',
totalCost: totalCost?.toInt() ?? 0,
purchaseOrderCount: purchaseOrderCount?.toInt() ?? 0,
ingredientCount: ingredientCount?.toInt() ?? 0,
quantity: quantity?.toInt() ?? 0,
);
}

View File

@ -176,4 +176,25 @@ class AnalyticRepository implements IAnalyticRepository {
return left(const AnalyticFailure.unexpectedError()); return left(const AnalyticFailure.unexpectedError());
} }
} }
@override
Future<Either<AnalyticFailure, PurchasingAnalytic>> getPurchasing({
required DateTime dateFrom,
required DateTime dateTo,
String? outletId,
}) async {
try {
final result = await _dataProvider.fetchPurchasing(
dateFrom: dateFrom,
dateTo: dateTo,
outletId: _resolveOutletId(outletId),
);
if (result.hasError) return left(result.error!);
return right(result.data!.toDomain());
} catch (e, s) {
log('getPurchasingError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError());
}
}
} }

View File

@ -21,6 +21,8 @@ import 'package:apskel_owner_flutter/application/analytic/product_analytic_loade
as _i221; as _i221;
import 'package:apskel_owner_flutter/application/analytic/profit_loss_loader/profit_loss_loader_bloc.dart' import 'package:apskel_owner_flutter/application/analytic/profit_loss_loader/profit_loss_loader_bloc.dart'
as _i11; as _i11;
import 'package:apskel_owner_flutter/application/analytic/purchasing_analytic_loader/purchasing_analytic_loader_bloc.dart'
as _i755;
import 'package:apskel_owner_flutter/application/analytic/sales_loader/sales_loader_bloc.dart' import 'package:apskel_owner_flutter/application/analytic/sales_loader/sales_loader_bloc.dart'
as _i889; as _i889;
import 'package:apskel_owner_flutter/application/auth/auth_bloc.dart' as _i945; import 'package:apskel_owner_flutter/application/auth/auth_bloc.dart' as _i945;
@ -248,6 +250,9 @@ extension GetItInjectableX on _i174.GetIt {
gh<_i850.OutletLocalDataProvider>(), gh<_i850.OutletLocalDataProvider>(),
), ),
); );
gh.factory<_i755.PurchasingAnalyticLoaderBloc>(
() => _i755.PurchasingAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()),
);
gh.factory<_i889.SalesLoaderBloc>( gh.factory<_i889.SalesLoaderBloc>(
() => _i889.SalesLoaderBloc(gh<_i477.IAnalyticRepository>()), () => _i889.SalesLoaderBloc(gh<_i477.IAnalyticRepository>()),
); );

View File

@ -56,6 +56,11 @@ class HomeFeature extends StatelessWidget {
iconPath: Assets.icons.icReportProduct.path, iconPath: Assets.icons.icReportProduct.path,
onTap: () => context.router.push(ProductAnalyticRoute()), onTap: () => context.router.push(ProductAnalyticRoute()),
), ),
// HomeFeatureTile(
// title: context.lang.inventory,
// iconPath: Assets.icons.icReportProduct.path,
// onTap: () => context.router.push(InventoryRoute()),
// ),
], ],
), ),
// Row( // Row(