report profit loss
This commit is contained in:
@@ -9,3 +9,4 @@ part 'dtos/dashboard_dto.dart';
|
||||
part 'dtos/sales_dto.dart';
|
||||
part 'dtos/product_analytic_dto.dart';
|
||||
part 'dtos/payment_method_analytic_dto.dart';
|
||||
part 'dtos/profit_loss_analytic_dto.dart';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -347,3 +347,135 @@ Map<String, dynamic> _$$PaymentMethodAnalyticSummaryDtoImplToJson(
|
||||
'total_payments': instance.totalPayments,
|
||||
'average_order_value': instance.averageOrderValue,
|
||||
};
|
||||
|
||||
_$ProfitLossAnalyticDtoImpl _$$ProfitLossAnalyticDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$ProfitLossAnalyticDtoImpl(
|
||||
organizationId: json['organization_id'] as String?,
|
||||
dateFrom: json['date_from'] as String?,
|
||||
dateTo: json['date_to'] as String?,
|
||||
groupBy: json['group_by'] as String?,
|
||||
summary: json['summary'] == null
|
||||
? null
|
||||
: ProfitLossAnalyticSummaryDto.fromJson(
|
||||
json['summary'] as Map<String, dynamic>,
|
||||
),
|
||||
data: (json['data'] as List<dynamic>?)
|
||||
?.map(
|
||||
(e) => ProfitLossAnalyticItemDto.fromJson(e as Map<String, dynamic>),
|
||||
)
|
||||
.toList(),
|
||||
productData: (json['product_data'] as List<dynamic>?)
|
||||
?.map(
|
||||
(e) => ProfitLossAnalyticProductDto.fromJson(e as Map<String, dynamic>),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ProfitLossAnalyticDtoImplToJson(
|
||||
_$ProfitLossAnalyticDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'organization_id': instance.organizationId,
|
||||
'date_from': instance.dateFrom,
|
||||
'date_to': instance.dateTo,
|
||||
'group_by': instance.groupBy,
|
||||
'summary': instance.summary,
|
||||
'data': instance.data,
|
||||
'product_data': instance.productData,
|
||||
};
|
||||
|
||||
_$ProfitLossAnalyticSummaryDtoImpl _$$ProfitLossAnalyticSummaryDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$ProfitLossAnalyticSummaryDtoImpl(
|
||||
totalRevenue: (json['total_revenue'] as num?)?.toInt(),
|
||||
totalCost: json['total_cost'] as num?,
|
||||
grossProfit: json['gross_profit'] as num?,
|
||||
grossProfitMargin: (json['gross_profit_margin'] as num?)?.toDouble(),
|
||||
totalTax: (json['total_tax'] as num?)?.toInt(),
|
||||
totalDiscount: (json['total_discount'] as num?)?.toInt(),
|
||||
netProfit: json['net_profit'] as num?,
|
||||
netProfitMargin: (json['net_profit_margin'] as num?)?.toDouble(),
|
||||
totalOrders: (json['total_orders'] as num?)?.toInt(),
|
||||
averageProfit: (json['average_profit'] as num?)?.toDouble(),
|
||||
profitabilityRatio: (json['profitability_ratio'] as num?)?.toDouble(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ProfitLossAnalyticSummaryDtoImplToJson(
|
||||
_$ProfitLossAnalyticSummaryDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'total_revenue': instance.totalRevenue,
|
||||
'total_cost': instance.totalCost,
|
||||
'gross_profit': instance.grossProfit,
|
||||
'gross_profit_margin': instance.grossProfitMargin,
|
||||
'total_tax': instance.totalTax,
|
||||
'total_discount': instance.totalDiscount,
|
||||
'net_profit': instance.netProfit,
|
||||
'net_profit_margin': instance.netProfitMargin,
|
||||
'total_orders': instance.totalOrders,
|
||||
'average_profit': instance.averageProfit,
|
||||
'profitability_ratio': instance.profitabilityRatio,
|
||||
};
|
||||
|
||||
_$ProfitLossAnalyticItemDtoImpl _$$ProfitLossAnalyticItemDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$ProfitLossAnalyticItemDtoImpl(
|
||||
date: json['date'] as String?,
|
||||
revenue: (json['revenue'] as num?)?.toInt(),
|
||||
cost: json['cost'] as num?,
|
||||
grossProfit: json['gross_profit'] as num?,
|
||||
grossProfitMargin: (json['gross_profit_margin'] as num?)?.toDouble(),
|
||||
tax: (json['tax'] as num?)?.toInt(),
|
||||
discount: (json['discount'] as num?)?.toInt(),
|
||||
netProfit: json['net_profit'] as num?,
|
||||
netProfitMargin: (json['net_profit_margin'] as num?)?.toDouble(),
|
||||
orders: (json['orders'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ProfitLossAnalyticItemDtoImplToJson(
|
||||
_$ProfitLossAnalyticItemDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'date': instance.date,
|
||||
'revenue': instance.revenue,
|
||||
'cost': instance.cost,
|
||||
'gross_profit': instance.grossProfit,
|
||||
'gross_profit_margin': instance.grossProfitMargin,
|
||||
'tax': instance.tax,
|
||||
'discount': instance.discount,
|
||||
'net_profit': instance.netProfit,
|
||||
'net_profit_margin': instance.netProfitMargin,
|
||||
'orders': instance.orders,
|
||||
};
|
||||
|
||||
_$ProfitLossAnalyticProductDtoImpl _$$ProfitLossAnalyticProductDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$ProfitLossAnalyticProductDtoImpl(
|
||||
productId: json['product_id'] as String?,
|
||||
productName: json['product_name'] as String?,
|
||||
categoryId: json['category_id'] as String?,
|
||||
categoryName: json['category_name'] as String?,
|
||||
quantitySold: (json['quantity_sold'] as num?)?.toInt(),
|
||||
revenue: (json['revenue'] as num?)?.toInt(),
|
||||
cost: json['cost'] as num?,
|
||||
grossProfit: json['gross_profit'] as num?,
|
||||
grossProfitMargin: (json['gross_profit_margin'] as num?)?.toDouble(),
|
||||
averagePrice: (json['average_price'] as num?)?.toInt(),
|
||||
averageCost: json['average_cost'] as num?,
|
||||
profitPerUnit: json['profit_per_unit'] as num?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ProfitLossAnalyticProductDtoImplToJson(
|
||||
_$ProfitLossAnalyticProductDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'product_id': instance.productId,
|
||||
'product_name': instance.productName,
|
||||
'category_id': instance.categoryId,
|
||||
'category_name': instance.categoryName,
|
||||
'quantity_sold': instance.quantitySold,
|
||||
'revenue': instance.revenue,
|
||||
'cost': instance.cost,
|
||||
'gross_profit': instance.grossProfit,
|
||||
'gross_profit_margin': instance.grossProfitMargin,
|
||||
'average_price': instance.averagePrice,
|
||||
'average_cost': instance.averageCost,
|
||||
'profit_per_unit': instance.profitPerUnit,
|
||||
};
|
||||
|
||||
@@ -134,4 +134,33 @@ class AnalyticRemoteDataProvider {
|
||||
return DC.error(AnalyticFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<DC<AnalyticFailure, ProfitLossAnalyticDto>> fetchProfitLoss({
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.get(
|
||||
ApiPath.analyticProfitLoss,
|
||||
params: {
|
||||
'date_from': dateFrom.toServerDate(),
|
||||
'date_to': dateTo.toServerDate(),
|
||||
},
|
||||
headers: getAuthorizationHeader(),
|
||||
);
|
||||
|
||||
if (response.data['success'] == false) {
|
||||
return DC.error(AnalyticFailure.unexpectedError());
|
||||
}
|
||||
|
||||
final profitLoss = ProfitLossAnalyticDto.fromJson(
|
||||
response.data['data'] as Map<String, dynamic>,
|
||||
);
|
||||
|
||||
return DC.data(profitLoss);
|
||||
} on ApiFailure catch (e, s) {
|
||||
log('fetchProfitLoss', name: _logName, error: e, stackTrace: s);
|
||||
return DC.error(AnalyticFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
part of '../analytic_dtos.dart';
|
||||
|
||||
@freezed
|
||||
class ProfitLossAnalyticDto with _$ProfitLossAnalyticDto {
|
||||
const ProfitLossAnalyticDto._();
|
||||
|
||||
const factory ProfitLossAnalyticDto({
|
||||
@JsonKey(name: "organization_id") String? organizationId,
|
||||
@JsonKey(name: "date_from") String? dateFrom,
|
||||
@JsonKey(name: "date_to") String? dateTo,
|
||||
@JsonKey(name: "group_by") String? groupBy,
|
||||
@JsonKey(name: "summary") ProfitLossAnalyticSummaryDto? summary,
|
||||
@JsonKey(name: "data") List<ProfitLossAnalyticItemDto>? data,
|
||||
@JsonKey(name: "product_data")
|
||||
List<ProfitLossAnalyticProductDto>? productData,
|
||||
}) = _ProfitLossAnalyticDto;
|
||||
|
||||
factory ProfitLossAnalyticDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$ProfitLossAnalyticDtoFromJson(json);
|
||||
|
||||
// Optional: mapper ke domain entity
|
||||
ProfitLossAnalytic toDomain() => ProfitLossAnalytic(
|
||||
organizationId: organizationId ?? '',
|
||||
dateFrom: dateFrom ?? '',
|
||||
dateTo: dateTo ?? '',
|
||||
groupBy: groupBy ?? 'day',
|
||||
summary: summary?.toDomain() ?? ProfitLossAnalyticSummary.empty(),
|
||||
data: data?.map((e) => e.toDomain()).toList() ?? [],
|
||||
productData: productData?.map((e) => e.toDomain()).toList() ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ProfitLossAnalyticSummaryDto with _$ProfitLossAnalyticSummaryDto {
|
||||
const ProfitLossAnalyticSummaryDto._();
|
||||
|
||||
const factory ProfitLossAnalyticSummaryDto({
|
||||
@JsonKey(name: "total_revenue") int? totalRevenue,
|
||||
@JsonKey(name: "total_cost") num? totalCost,
|
||||
@JsonKey(name: "gross_profit") num? grossProfit,
|
||||
@JsonKey(name: "gross_profit_margin") double? grossProfitMargin,
|
||||
@JsonKey(name: "total_tax") int? totalTax,
|
||||
@JsonKey(name: "total_discount") int? totalDiscount,
|
||||
@JsonKey(name: "net_profit") num? netProfit,
|
||||
@JsonKey(name: "net_profit_margin") double? netProfitMargin,
|
||||
@JsonKey(name: "total_orders") int? totalOrders,
|
||||
@JsonKey(name: "average_profit") double? averageProfit,
|
||||
@JsonKey(name: "profitability_ratio") double? profitabilityRatio,
|
||||
}) = _ProfitLossAnalyticSummaryDto;
|
||||
|
||||
factory ProfitLossAnalyticSummaryDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$ProfitLossAnalyticSummaryDtoFromJson(json);
|
||||
|
||||
// Optional mapper ke domain
|
||||
ProfitLossAnalyticSummary toDomain() => ProfitLossAnalyticSummary(
|
||||
totalRevenue: totalRevenue ?? 0,
|
||||
totalCost: totalCost ?? 0,
|
||||
grossProfit: grossProfit ?? 0,
|
||||
grossProfitMargin: grossProfitMargin ?? 0.0,
|
||||
totalTax: totalTax ?? 0,
|
||||
totalDiscount: totalDiscount ?? 0,
|
||||
netProfit: netProfit ?? 0,
|
||||
netProfitMargin: netProfitMargin ?? 0.0,
|
||||
totalOrders: totalOrders ?? 0,
|
||||
averageProfit: averageProfit ?? 0.0,
|
||||
profitabilityRatio: profitabilityRatio ?? 0.0,
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ProfitLossAnalyticItemDto with _$ProfitLossAnalyticItemDto {
|
||||
const ProfitLossAnalyticItemDto._();
|
||||
|
||||
const factory ProfitLossAnalyticItemDto({
|
||||
@JsonKey(name: "date") String? date,
|
||||
@JsonKey(name: "revenue") int? revenue,
|
||||
@JsonKey(name: "cost") num? cost,
|
||||
@JsonKey(name: "gross_profit") num? grossProfit,
|
||||
@JsonKey(name: "gross_profit_margin") double? grossProfitMargin,
|
||||
@JsonKey(name: "tax") int? tax,
|
||||
@JsonKey(name: "discount") int? discount,
|
||||
@JsonKey(name: "net_profit") num? netProfit,
|
||||
@JsonKey(name: "net_profit_margin") double? netProfitMargin,
|
||||
@JsonKey(name: "orders") int? orders,
|
||||
}) = _ProfitLossAnalyticItemDto;
|
||||
|
||||
factory ProfitLossAnalyticItemDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$ProfitLossAnalyticItemDtoFromJson(json);
|
||||
|
||||
// Optional mapper ke domain
|
||||
ProfitLossAnalyticItem toDomain() => ProfitLossAnalyticItem(
|
||||
date: date ?? '',
|
||||
revenue: revenue ?? 0,
|
||||
cost: cost ?? 0,
|
||||
grossProfit: grossProfit ?? 0,
|
||||
grossProfitMargin: grossProfitMargin ?? 0.0,
|
||||
tax: tax ?? 0,
|
||||
discount: discount ?? 0,
|
||||
netProfit: netProfit ?? 0,
|
||||
netProfitMargin: netProfitMargin ?? 0.0,
|
||||
orders: orders ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ProfitLossAnalyticProductDto with _$ProfitLossAnalyticProductDto {
|
||||
const ProfitLossAnalyticProductDto._();
|
||||
|
||||
const factory ProfitLossAnalyticProductDto({
|
||||
@JsonKey(name: "product_id") String? productId,
|
||||
@JsonKey(name: "product_name") String? productName,
|
||||
@JsonKey(name: "category_id") String? categoryId,
|
||||
@JsonKey(name: "category_name") String? categoryName,
|
||||
@JsonKey(name: "quantity_sold") int? quantitySold,
|
||||
@JsonKey(name: "revenue") int? revenue,
|
||||
@JsonKey(name: "cost") num? cost,
|
||||
@JsonKey(name: "gross_profit") num? grossProfit,
|
||||
@JsonKey(name: "gross_profit_margin") double? grossProfitMargin,
|
||||
@JsonKey(name: "average_price") int? averagePrice,
|
||||
@JsonKey(name: "average_cost") num? averageCost,
|
||||
@JsonKey(name: "profit_per_unit") num? profitPerUnit,
|
||||
}) = _ProfitLossAnalyticProductDto;
|
||||
|
||||
factory ProfitLossAnalyticProductDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$ProfitLossAnalyticProductDtoFromJson(json);
|
||||
|
||||
// Optional mapper ke domain
|
||||
ProfitLossAnalyticProduct toDomain() => ProfitLossAnalyticProduct(
|
||||
productId: productId ?? '',
|
||||
productName: productName ?? '',
|
||||
categoryId: categoryId ?? '',
|
||||
categoryName: categoryName ?? '',
|
||||
quantitySold: quantitySold ?? 0,
|
||||
revenue: revenue ?? 0,
|
||||
cost: cost ?? 0,
|
||||
grossProfit: grossProfit ?? 0,
|
||||
grossProfitMargin: grossProfitMargin ?? 0.0,
|
||||
averagePrice: averagePrice ?? 0,
|
||||
averageCost: averageCost ?? 0,
|
||||
profitPerUnit: profitPerUnit ?? 0,
|
||||
);
|
||||
}
|
||||
@@ -109,4 +109,28 @@ class AnalyticRepository implements IAnalyticRepository {
|
||||
return left(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<AnalyticFailure, ProfitLossAnalytic>> getProfitLoss({
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.fetchProfitLoss(
|
||||
dateFrom: dateFrom,
|
||||
dateTo: dateTo,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
return left(result.error!);
|
||||
}
|
||||
|
||||
final profitLoss = result.data!.toDomain();
|
||||
|
||||
return right(profitLoss);
|
||||
} catch (e) {
|
||||
log('getProfitLossError', name: _logName, error: e);
|
||||
return left(const AnalyticFailure.unexpectedError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user