feat: inventory
This commit is contained in:
@@ -8,3 +8,4 @@ part 'analytic_dtos.g.dart';
|
||||
part 'dto/sales_analytic_dto.dart';
|
||||
part 'dto/profit_loss_analytic_dto.dart';
|
||||
part 'dto/category_analytic_dto.dart';
|
||||
part 'dto/inventory_analytic_dto.dart';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -257,3 +257,131 @@ Map<String, dynamic> _$$CategoryAnalyticItemDtoImplToJson(
|
||||
'product_count': instance.productCount,
|
||||
'order_count': instance.orderCount,
|
||||
};
|
||||
|
||||
_$InventoryAnalyticDtoImpl _$$InventoryAnalyticDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$InventoryAnalyticDtoImpl(
|
||||
summary: json['summary'] == null
|
||||
? null
|
||||
: InventorySummaryDto.fromJson(json['summary'] as Map<String, dynamic>),
|
||||
products: (json['products'] as List<dynamic>?)
|
||||
?.map((e) => InventoryProductDto.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
ingredients: (json['ingredients'] as List<dynamic>?)
|
||||
?.map((e) => InventoryIngredientDto.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$InventoryAnalyticDtoImplToJson(
|
||||
_$InventoryAnalyticDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'summary': instance.summary,
|
||||
'products': instance.products,
|
||||
'ingredients': instance.ingredients,
|
||||
};
|
||||
|
||||
_$InventorySummaryDtoImpl _$$InventorySummaryDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$InventorySummaryDtoImpl(
|
||||
totalProducts: (json['total_products'] as num?)?.toInt(),
|
||||
totalIngredients: (json['total_ingredients'] as num?)?.toInt(),
|
||||
totalValue: (json['total_value'] as num?)?.toInt(),
|
||||
lowStockProducts: (json['low_stock_products'] as num?)?.toInt(),
|
||||
lowStockIngredients: (json['low_stock_ingredients'] as num?)?.toInt(),
|
||||
zeroStockProducts: (json['zero_stock_products'] as num?)?.toInt(),
|
||||
zeroStockIngredients: (json['zero_stock_ingredients'] as num?)?.toInt(),
|
||||
totalSoldProducts: (json['total_sold_products'] as num?)?.toInt(),
|
||||
totalSoldIngredients: (json['total_sold_ingredients'] as num?)?.toInt(),
|
||||
outletId: json['outlet_id'] as String?,
|
||||
outletName: json['outlet_name'] as String?,
|
||||
generatedAt: json['generated_at'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$InventorySummaryDtoImplToJson(
|
||||
_$InventorySummaryDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'total_products': instance.totalProducts,
|
||||
'total_ingredients': instance.totalIngredients,
|
||||
'total_value': instance.totalValue,
|
||||
'low_stock_products': instance.lowStockProducts,
|
||||
'low_stock_ingredients': instance.lowStockIngredients,
|
||||
'zero_stock_products': instance.zeroStockProducts,
|
||||
'zero_stock_ingredients': instance.zeroStockIngredients,
|
||||
'total_sold_products': instance.totalSoldProducts,
|
||||
'total_sold_ingredients': instance.totalSoldIngredients,
|
||||
'outlet_id': instance.outletId,
|
||||
'outlet_name': instance.outletName,
|
||||
'generated_at': instance.generatedAt,
|
||||
};
|
||||
|
||||
_$InventoryProductDtoImpl _$$InventoryProductDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$InventoryProductDtoImpl(
|
||||
id: json['id'] as String?,
|
||||
productId: json['product_id'] as String?,
|
||||
productName: json['product_name'] as String?,
|
||||
categoryName: json['category_name'] as String?,
|
||||
quantity: (json['quantity'] as num?)?.toInt(),
|
||||
reorderLevel: (json['reorder_level'] as num?)?.toInt(),
|
||||
unitCost: (json['unit_cost'] as num?)?.toInt(),
|
||||
totalValue: (json['total_value'] as num?)?.toInt(),
|
||||
totalIn: (json['total_in'] as num?)?.toInt(),
|
||||
totalOut: (json['total_out'] as num?)?.toInt(),
|
||||
isLowStock: json['is_low_stock'] as bool?,
|
||||
isZeroStock: json['is_zero_stock'] as bool?,
|
||||
updatedAt: json['updated_at'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$InventoryProductDtoImplToJson(
|
||||
_$InventoryProductDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'product_id': instance.productId,
|
||||
'product_name': instance.productName,
|
||||
'category_name': instance.categoryName,
|
||||
'quantity': instance.quantity,
|
||||
'reorder_level': instance.reorderLevel,
|
||||
'unit_cost': instance.unitCost,
|
||||
'total_value': instance.totalValue,
|
||||
'total_in': instance.totalIn,
|
||||
'total_out': instance.totalOut,
|
||||
'is_low_stock': instance.isLowStock,
|
||||
'is_zero_stock': instance.isZeroStock,
|
||||
'updated_at': instance.updatedAt,
|
||||
};
|
||||
|
||||
_$InventoryIngredientDtoImpl _$$InventoryIngredientDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$InventoryIngredientDtoImpl(
|
||||
id: json['id'] as String?,
|
||||
ingredientId: json['ingredient_id'] as String?,
|
||||
ingredientName: json['ingredient_name'] as String?,
|
||||
unitName: json['unit_name'] as String?,
|
||||
quantity: (json['quantity'] as num?)?.toInt(),
|
||||
reorderLevel: (json['reorder_level'] as num?)?.toInt(),
|
||||
unitCost: (json['unit_cost'] as num?)?.toInt(),
|
||||
totalValue: (json['total_value'] as num?)?.toInt(),
|
||||
totalIn: (json['total_in'] as num?)?.toInt(),
|
||||
totalOut: (json['total_out'] as num?)?.toInt(),
|
||||
isLowStock: json['is_low_stock'] as bool?,
|
||||
isZeroStock: json['is_zero_stock'] as bool?,
|
||||
updatedAt: json['updated_at'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$InventoryIngredientDtoImplToJson(
|
||||
_$InventoryIngredientDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'ingredient_id': instance.ingredientId,
|
||||
'ingredient_name': instance.ingredientName,
|
||||
'unit_name': instance.unitName,
|
||||
'quantity': instance.quantity,
|
||||
'reorder_level': instance.reorderLevel,
|
||||
'unit_cost': instance.unitCost,
|
||||
'total_value': instance.totalValue,
|
||||
'total_in': instance.totalIn,
|
||||
'total_out': instance.totalOut,
|
||||
'is_low_stock': instance.isLowStock,
|
||||
'is_zero_stock': instance.isZeroStock,
|
||||
'updated_at': instance.updatedAt,
|
||||
};
|
||||
|
||||
@@ -98,4 +98,32 @@ class AnalyticRemoteDataProvider {
|
||||
return DC.error(AnalyticFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<DC<AnalyticFailure, InventoryAnalyticDto>> fetchInventory({
|
||||
required String outletId,
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.get(
|
||||
'${ApiPath.inventoryReportDetail}/$outletId',
|
||||
params: {
|
||||
'date_from': dateFrom.toServerDate,
|
||||
'date_to': dateTo.toServerDate,
|
||||
},
|
||||
headers: getAuthorizationHeader(),
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(AnalyticFailure.empty());
|
||||
}
|
||||
|
||||
final dto = InventoryAnalyticDto.fromJson(response.data['data']);
|
||||
|
||||
return DC.data(dto);
|
||||
} on ApiFailure catch (e, s) {
|
||||
log('fetchInventoryError', name: _logName, error: e, stackTrace: s);
|
||||
return DC.error(AnalyticFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
part of '../analytic_dtos.dart';
|
||||
|
||||
@freezed
|
||||
class InventoryAnalyticDto with _$InventoryAnalyticDto {
|
||||
const InventoryAnalyticDto._();
|
||||
|
||||
const factory InventoryAnalyticDto({
|
||||
@JsonKey(name: "summary") InventorySummaryDto? summary,
|
||||
@JsonKey(name: "products") List<InventoryProductDto>? products,
|
||||
@JsonKey(name: "ingredients") List<InventoryIngredientDto>? ingredients,
|
||||
}) = _InventoryAnalyticDto;
|
||||
|
||||
factory InventoryAnalyticDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$InventoryAnalyticDtoFromJson(json);
|
||||
|
||||
InventoryAnalytic toDomain() => InventoryAnalytic(
|
||||
summary: summary?.toDomain() ?? InventorySummary.empty(),
|
||||
products: products?.map((e) => e.toDomain()).toList() ?? [],
|
||||
ingredients: ingredients?.map((e) => e.toDomain()).toList() ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class InventorySummaryDto with _$InventorySummaryDto {
|
||||
const factory InventorySummaryDto({
|
||||
@JsonKey(name: "total_products") int? totalProducts,
|
||||
@JsonKey(name: "total_ingredients") int? totalIngredients,
|
||||
@JsonKey(name: "total_value") int? totalValue,
|
||||
@JsonKey(name: "low_stock_products") int? lowStockProducts,
|
||||
@JsonKey(name: "low_stock_ingredients") int? lowStockIngredients,
|
||||
@JsonKey(name: "zero_stock_products") int? zeroStockProducts,
|
||||
@JsonKey(name: "zero_stock_ingredients") int? zeroStockIngredients,
|
||||
@JsonKey(name: "total_sold_products") int? totalSoldProducts,
|
||||
@JsonKey(name: "total_sold_ingredients") int? totalSoldIngredients,
|
||||
@JsonKey(name: "outlet_id") String? outletId,
|
||||
@JsonKey(name: "outlet_name") String? outletName,
|
||||
@JsonKey(name: "generated_at") String? generatedAt,
|
||||
}) = _InventorySummaryDto;
|
||||
|
||||
factory InventorySummaryDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$InventorySummaryDtoFromJson(json);
|
||||
}
|
||||
|
||||
extension InventorySummaryDtoX on InventorySummaryDto {
|
||||
InventorySummary toDomain() => InventorySummary(
|
||||
totalProducts: totalProducts ?? 0,
|
||||
totalIngredients: totalIngredients ?? 0,
|
||||
totalValue: totalValue ?? 0,
|
||||
lowStockProducts: lowStockProducts ?? 0,
|
||||
lowStockIngredients: lowStockIngredients ?? 0,
|
||||
zeroStockProducts: zeroStockProducts ?? 0,
|
||||
zeroStockIngredients: zeroStockIngredients ?? 0,
|
||||
totalSoldProducts: totalSoldProducts ?? 0,
|
||||
totalSoldIngredients: totalSoldIngredients ?? 0,
|
||||
outletId: outletId ?? "",
|
||||
outletName: outletName ?? "",
|
||||
generatedAt: generatedAt ?? "",
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class InventoryProductDto with _$InventoryProductDto {
|
||||
const factory InventoryProductDto({
|
||||
@JsonKey(name: "id") String? id,
|
||||
@JsonKey(name: "product_id") String? productId,
|
||||
@JsonKey(name: "product_name") String? productName,
|
||||
@JsonKey(name: "category_name") String? categoryName,
|
||||
@JsonKey(name: "quantity") int? quantity,
|
||||
@JsonKey(name: "reorder_level") int? reorderLevel,
|
||||
@JsonKey(name: "unit_cost") int? unitCost,
|
||||
@JsonKey(name: "total_value") int? totalValue,
|
||||
@JsonKey(name: "total_in") int? totalIn,
|
||||
@JsonKey(name: "total_out") int? totalOut,
|
||||
@JsonKey(name: "is_low_stock") bool? isLowStock,
|
||||
@JsonKey(name: "is_zero_stock") bool? isZeroStock,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
}) = _InventoryProductDto;
|
||||
|
||||
factory InventoryProductDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$InventoryProductDtoFromJson(json);
|
||||
}
|
||||
|
||||
extension InventoryProductDtoX on InventoryProductDto {
|
||||
InventoryProduct toDomain() => InventoryProduct(
|
||||
id: id ?? "",
|
||||
productId: productId ?? "",
|
||||
productName: productName ?? "",
|
||||
categoryName: categoryName ?? "",
|
||||
quantity: quantity ?? 0,
|
||||
reorderLevel: reorderLevel ?? 0,
|
||||
unitCost: unitCost ?? 0,
|
||||
totalValue: totalValue ?? 0,
|
||||
totalIn: totalIn ?? 0,
|
||||
totalOut: totalOut ?? 0,
|
||||
isLowStock: isLowStock ?? false,
|
||||
isZeroStock: isZeroStock ?? false,
|
||||
updatedAt: updatedAt ?? "",
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class InventoryIngredientDto with _$InventoryIngredientDto {
|
||||
const factory InventoryIngredientDto({
|
||||
@JsonKey(name: "id") String? id,
|
||||
@JsonKey(name: "ingredient_id") String? ingredientId,
|
||||
@JsonKey(name: "ingredient_name") String? ingredientName,
|
||||
@JsonKey(name: "unit_name") String? unitName,
|
||||
@JsonKey(name: "quantity") int? quantity,
|
||||
@JsonKey(name: "reorder_level") int? reorderLevel,
|
||||
@JsonKey(name: "unit_cost") int? unitCost,
|
||||
@JsonKey(name: "total_value") int? totalValue,
|
||||
@JsonKey(name: "total_in") int? totalIn,
|
||||
@JsonKey(name: "total_out") int? totalOut,
|
||||
@JsonKey(name: "is_low_stock") bool? isLowStock,
|
||||
@JsonKey(name: "is_zero_stock") bool? isZeroStock,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
}) = _InventoryIngredientDto;
|
||||
|
||||
factory InventoryIngredientDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$InventoryIngredientDtoFromJson(json);
|
||||
}
|
||||
|
||||
extension InventoryIngredientDtoX on InventoryIngredientDto {
|
||||
InventoryIngredient toDomain() => InventoryIngredient(
|
||||
id: id ?? "",
|
||||
ingredientId: ingredientId ?? "",
|
||||
ingredientName: ingredientName ?? "",
|
||||
unitName: unitName ?? "",
|
||||
quantity: quantity ?? 0,
|
||||
reorderLevel: reorderLevel ?? 0,
|
||||
unitCost: unitCost ?? 0,
|
||||
totalValue: totalValue ?? 0,
|
||||
totalIn: totalIn ?? 0,
|
||||
totalOut: totalOut ?? 0,
|
||||
isLowStock: isLowStock ?? false,
|
||||
isZeroStock: isZeroStock ?? false,
|
||||
updatedAt: updatedAt ?? "",
|
||||
);
|
||||
}
|
||||
@@ -5,14 +5,17 @@ import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/analytic/analytic.dart';
|
||||
import '../../../domain/analytic/repositories/i_analytic_repository.dart';
|
||||
import '../../../domain/auth/auth.dart';
|
||||
import '../../auth/datasources/local_data_provider.dart';
|
||||
import '../datasource/remote_data_provider.dart';
|
||||
|
||||
@Injectable(as: IAnalyticRepository)
|
||||
class AnalyticRepository implements IAnalyticRepository {
|
||||
final AnalyticRemoteDataProvider _dataProvider;
|
||||
final AuthLocalDataProvider _authLocalDataProvider;
|
||||
final String _logName = 'AnalyticRepository';
|
||||
|
||||
AnalyticRepository(this._dataProvider);
|
||||
AnalyticRepository(this._dataProvider, this._authLocalDataProvider);
|
||||
|
||||
@override
|
||||
Future<Either<AnalyticFailure, SalesAnalytic>> getSales({
|
||||
@@ -85,4 +88,31 @@ class AnalyticRepository implements IAnalyticRepository {
|
||||
return left(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<AnalyticFailure, InventoryAnalytic>> getInventory({
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
User currentUser = await _authLocalDataProvider.currentUser();
|
||||
|
||||
final result = await _dataProvider.fetchInventory(
|
||||
outletId: currentUser.outletId,
|
||||
dateFrom: dateFrom,
|
||||
dateTo: dateTo,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
return left(result.error!);
|
||||
}
|
||||
|
||||
final auth = result.data!.toDomain();
|
||||
|
||||
return right(auth);
|
||||
} catch (e, s) {
|
||||
log('getInventoryError', name: _logName, error: e, stackTrace: s);
|
||||
return left(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user