feat: profit loss

This commit is contained in:
efrilm
2025-08-06 13:38:49 +07:00
parent db06f0dd13
commit f067417ab2
9 changed files with 2394 additions and 1 deletions
@@ -8,6 +8,7 @@ import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
import 'package:enaklo_pos/data/models/response/dashboard_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/payment_method_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/product_analytic_response_model.dart';
import 'package:enaklo_pos/data/models/response/profit_loss_response_model.dart';
import 'package:enaklo_pos/data/models/response/sales_analytic_response_model.dart';
import 'package:intl/intl.dart';
@@ -149,4 +150,38 @@ class AnalyticRemoteDatasource {
return left('Unexpected error occurred');
}
}
Future<Either<String, ProfitLossResponseModel>> getProfitLoss({
required DateTime dateFrom,
required DateTime dateTo,
}) async {
final authData = await AuthLocalDataSource().getAuthData();
final headers = {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
};
try {
final response = await dio.get(
'${Variables.baseUrl}/api/v1/analytics/profit-loss',
queryParameters: {
'date_from': DateFormat('dd-MM-yyyy').format(dateFrom),
'date_to': DateFormat('dd-MM-yyyy').format(dateTo),
},
options: Options(headers: headers),
);
if (response.statusCode == 200) {
return right(ProfitLossResponseModel.fromMap(response.data));
} else {
return left('Terjadi Kesalahan, Coba lagi nanti.');
}
} on DioException catch (e) {
log('Dio error: ${e.message}');
return left(e.response?.data.toString() ?? e.message ?? 'Unknown error');
} catch (e) {
log('Unexpected error: $e');
return left('Unexpected error occurred');
}
}
}
@@ -0,0 +1,273 @@
class ProfitLossResponseModel {
final bool success;
final ProfitLossData data;
final dynamic errors;
ProfitLossResponseModel({
required this.success,
required this.data,
this.errors,
});
/// Dari JSON ke model (misal response dari API)
factory ProfitLossResponseModel.fromJson(Map<String, dynamic> json) {
return ProfitLossResponseModel(
success: json['success'],
data: ProfitLossData.fromMap(json['data']),
errors: json['errors'],
);
}
/// Dari model ke JSON (misal saat kirim ke API)
Map<String, dynamic> toJson() {
return {
'success': success,
'data': data.toMap(),
'errors': errors,
};
}
/// Alias dari fromJson, kadang dibutuhkan untuk naming yang konsisten
factory ProfitLossResponseModel.fromMap(Map<String, dynamic> map) {
return ProfitLossResponseModel(
success: map['success'],
data: ProfitLossData.fromMap(map['data']),
errors: map['errors'],
);
}
/// Alias dari toJson
Map<String, dynamic> toMap() {
return {
'success': success,
'data': data.toMap(),
'errors': errors,
};
}
}
class ProfitLossData {
final String organizationId;
final String dateFrom;
final String dateTo;
final String groupBy;
final ProfitLossSummary summary;
final List<ProfitLossItem> data;
final List<ProfitLossProduct> productData;
ProfitLossData({
required this.organizationId,
required this.dateFrom,
required this.dateTo,
required this.groupBy,
required this.summary,
required this.data,
required this.productData,
});
factory ProfitLossData.fromMap(Map<String, dynamic> map) {
return ProfitLossData(
organizationId: map['organization_id'],
dateFrom: map['date_from'],
dateTo: map['date_to'],
groupBy: map['group_by'],
summary: ProfitLossSummary.fromMap(map['summary']),
data: List<ProfitLossItem>.from(
map['data'].map((x) => ProfitLossItem.fromMap(x))),
productData: List<ProfitLossProduct>.from(
map['product_data'].map((x) => ProfitLossProduct.fromMap(x))),
);
}
Map<String, dynamic> toMap() {
return {
'organization_id': organizationId,
'date_from': dateFrom,
'date_to': dateTo,
'group_by': groupBy,
'summary': summary.toMap(),
'data': data.map((x) => x.toMap()).toList(),
'product_data': productData.map((x) => x.toMap()).toList(),
};
}
}
class ProfitLossSummary {
final int totalRevenue;
final int totalCost;
final int grossProfit;
final double grossProfitMargin;
final int totalTax;
final int totalDiscount;
final int netProfit;
final double netProfitMargin;
final int totalOrders;
final int averageProfit;
final double profitabilityRatio;
ProfitLossSummary({
required this.totalRevenue,
required this.totalCost,
required this.grossProfit,
required this.grossProfitMargin,
required this.totalTax,
required this.totalDiscount,
required this.netProfit,
required this.netProfitMargin,
required this.totalOrders,
required this.averageProfit,
required this.profitabilityRatio,
});
factory ProfitLossSummary.fromMap(Map<String, dynamic> map) {
return ProfitLossSummary(
totalRevenue: map['total_revenue'],
totalCost: map['total_cost'],
grossProfit: map['gross_profit'],
grossProfitMargin: (map['gross_profit_margin'] as num).toDouble(),
totalTax: map['total_tax'],
totalDiscount: map['total_discount'],
netProfit: map['net_profit'],
netProfitMargin: (map['net_profit_margin'] as num).toDouble(),
totalOrders: map['total_orders'],
averageProfit: map['average_profit'],
profitabilityRatio: (map['profitability_ratio'] as num).toDouble(),
);
}
Map<String, dynamic> toMap() {
return {
'total_revenue': totalRevenue,
'total_cost': totalCost,
'gross_profit': grossProfit,
'gross_profit_margin': grossProfitMargin,
'total_tax': totalTax,
'total_discount': totalDiscount,
'net_profit': netProfit,
'net_profit_margin': netProfitMargin,
'total_orders': totalOrders,
'average_profit': averageProfit,
'profitability_ratio': profitabilityRatio,
};
}
}
class ProfitLossItem {
final String date;
final int revenue;
final int cost;
final int grossProfit;
final double grossProfitMargin;
final int tax;
final int discount;
final int netProfit;
final double netProfitMargin;
final int orders;
ProfitLossItem({
required this.date,
required this.revenue,
required this.cost,
required this.grossProfit,
required this.grossProfitMargin,
required this.tax,
required this.discount,
required this.netProfit,
required this.netProfitMargin,
required this.orders,
});
factory ProfitLossItem.fromMap(Map<String, dynamic> map) {
return ProfitLossItem(
date: map['date'],
revenue: map['revenue'],
cost: map['cost'],
grossProfit: map['gross_profit'],
grossProfitMargin: (map['gross_profit_margin'] as num).toDouble(),
tax: map['tax'],
discount: map['discount'],
netProfit: map['net_profit'],
netProfitMargin: (map['net_profit_margin'] as num).toDouble(),
orders: map['orders'],
);
}
Map<String, dynamic> toMap() {
return {
'date': date,
'revenue': revenue,
'cost': cost,
'gross_profit': grossProfit,
'gross_profit_margin': grossProfitMargin,
'tax': tax,
'discount': discount,
'net_profit': netProfit,
'net_profit_margin': netProfitMargin,
'orders': orders,
};
}
}
class ProfitLossProduct {
final String productId;
final String productName;
final String categoryId;
final String categoryName;
final int quantitySold;
final int revenue;
final int cost;
final int grossProfit;
final double grossProfitMargin;
final int averagePrice;
final int averageCost;
final int profitPerUnit;
ProfitLossProduct({
required this.productId,
required this.productName,
required this.categoryId,
required this.categoryName,
required this.quantitySold,
required this.revenue,
required this.cost,
required this.grossProfit,
required this.grossProfitMargin,
required this.averagePrice,
required this.averageCost,
required this.profitPerUnit,
});
factory ProfitLossProduct.fromMap(Map<String, dynamic> map) {
return ProfitLossProduct(
productId: map['product_id'],
productName: map['product_name'],
categoryId: map['category_id'],
categoryName: map['category_name'],
quantitySold: map['quantity_sold'],
revenue: map['revenue'],
cost: map['cost'],
grossProfit: map['gross_profit'],
grossProfitMargin: (map['gross_profit_margin'] as num).toDouble(),
averagePrice: map['average_price'],
averageCost: map['average_cost'],
profitPerUnit: map['profit_per_unit'],
);
}
Map<String, dynamic> toMap() {
return {
'product_id': productId,
'product_name': productName,
'category_id': categoryId,
'category_name': categoryName,
'quantity_sold': quantitySold,
'revenue': revenue,
'cost': cost,
'gross_profit': grossProfit,
'gross_profit_margin': grossProfitMargin,
'average_price': averagePrice,
'average_cost': averageCost,
'profit_per_unit': profitPerUnit,
};
}
}