220 lines
6.6 KiB
Dart
220 lines
6.6 KiB
Dart
part of '../analytic.dart';
|
|
|
|
/// Bagi hasil (profit sharing) berdasarkan omzet per parent category.
|
|
@freezed
|
|
class ProfitSharing with _$ProfitSharing {
|
|
const factory ProfitSharing({
|
|
required String organizationId,
|
|
required String outletId,
|
|
required String outletName,
|
|
required DateTime dateFrom,
|
|
required DateTime dateTo,
|
|
required List<ProfitSharingCategory> categories,
|
|
required ProfitSharingBudget budget,
|
|
}) = _ProfitSharing;
|
|
|
|
factory ProfitSharing.empty() => ProfitSharing(
|
|
organizationId: '',
|
|
outletId: '',
|
|
outletName: '',
|
|
dateFrom: DateTime.fromMillisecondsSinceEpoch(0),
|
|
dateTo: DateTime.fromMillisecondsSinceEpoch(0),
|
|
categories: [],
|
|
budget: ProfitSharingBudget.empty(),
|
|
);
|
|
}
|
|
|
|
@freezed
|
|
class ProfitSharingCategory with _$ProfitSharingCategory {
|
|
const ProfitSharingCategory._();
|
|
|
|
const factory ProfitSharingCategory({
|
|
required String parentCategoryId,
|
|
required String parentCategoryName,
|
|
required int totalRevenue,
|
|
required int totalQuantity,
|
|
required int categoryCount,
|
|
required int productCount,
|
|
required int orderCount,
|
|
required int totalStandardHpp,
|
|
required int totalFifoHpp,
|
|
required int totalMovingAverageHpp,
|
|
}) = _ProfitSharingCategory;
|
|
|
|
factory ProfitSharingCategory.empty() => const ProfitSharingCategory(
|
|
parentCategoryId: '',
|
|
parentCategoryName: '',
|
|
totalRevenue: 0,
|
|
totalQuantity: 0,
|
|
categoryCount: 0,
|
|
productCount: 0,
|
|
orderCount: 0,
|
|
totalStandardHpp: 0,
|
|
totalFifoHpp: 0,
|
|
totalMovingAverageHpp: 0,
|
|
);
|
|
|
|
/// Laba kotor memakai HPP standar (acuan yang dipakai di laporan laba rugi).
|
|
int get grossProfit => totalRevenue - totalStandardHpp;
|
|
|
|
double get grossMargin =>
|
|
totalRevenue == 0 ? 0 : (grossProfit / totalRevenue) * 100;
|
|
|
|
/// % HPP standar terhadap omzet.
|
|
double get standardHppPercentage =>
|
|
totalRevenue == 0 ? 0 : (totalStandardHpp / totalRevenue) * 100;
|
|
|
|
/// % HPP riil (FIFO) terhadap omzet — dipakai untuk status kesehatan margin.
|
|
double get realHppPercentage =>
|
|
totalRevenue == 0 ? 0 : (totalFifoHpp / totalRevenue) * 100;
|
|
}
|
|
|
|
@freezed
|
|
class ProfitSharingBudget with _$ProfitSharingBudget {
|
|
const factory ProfitSharingBudget({
|
|
required ProfitSharingPercentage percentages,
|
|
required DateTime cutOffFrom,
|
|
required DateTime cutOffTo,
|
|
required ProfitSharingPeriod total,
|
|
required List<ProfitSharingPeriod> weekly,
|
|
required List<ProfitSharingPeriod> monthly,
|
|
}) = _ProfitSharingBudget;
|
|
|
|
factory ProfitSharingBudget.empty() => ProfitSharingBudget(
|
|
percentages: ProfitSharingPercentage.empty(),
|
|
cutOffFrom: DateTime.fromMillisecondsSinceEpoch(0),
|
|
cutOffTo: DateTime.fromMillisecondsSinceEpoch(0),
|
|
total: ProfitSharingPeriod.empty(),
|
|
weekly: [],
|
|
monthly: [],
|
|
);
|
|
}
|
|
|
|
@freezed
|
|
class ProfitSharingPercentage with _$ProfitSharingPercentage {
|
|
const factory ProfitSharingPercentage({
|
|
required double purchase,
|
|
required double owner,
|
|
required double team,
|
|
}) = _ProfitSharingPercentage;
|
|
|
|
factory ProfitSharingPercentage.empty() =>
|
|
const ProfitSharingPercentage(purchase: 0, owner: 0, team: 0);
|
|
}
|
|
|
|
/// Satu baris periode bagi hasil. Dipakai untuk total, mingguan, dan bulanan.
|
|
/// [month] dan [weekCount] hanya terisi untuk data bulanan.
|
|
@freezed
|
|
class ProfitSharingPeriod with _$ProfitSharingPeriod {
|
|
const ProfitSharingPeriod._();
|
|
|
|
const factory ProfitSharingPeriod({
|
|
required DateTime periodStart,
|
|
required DateTime periodEnd,
|
|
required int revenue,
|
|
required int orderCount,
|
|
required int limitPurchase,
|
|
required int limitOwner,
|
|
required int limitTeam,
|
|
@Default('') String month,
|
|
@Default(0) int weekCount,
|
|
}) = _ProfitSharingPeriod;
|
|
|
|
factory ProfitSharingPeriod.empty() => ProfitSharingPeriod(
|
|
periodStart: DateTime.fromMillisecondsSinceEpoch(0),
|
|
periodEnd: DateTime.fromMillisecondsSinceEpoch(0),
|
|
revenue: 0,
|
|
orderCount: 0,
|
|
limitPurchase: 0,
|
|
limitOwner: 0,
|
|
limitTeam: 0,
|
|
);
|
|
|
|
bool get hasRevenue => revenue > 0;
|
|
|
|
int get averageOrderValue => orderCount == 0 ? 0 : revenue ~/ orderCount;
|
|
}
|
|
|
|
/// Rincian satu kategori induk: ringkasan, sub kategori beserta produknya,
|
|
/// dan bagi hasil khusus kategori tersebut.
|
|
@freezed
|
|
class ProfitSharingDetail with _$ProfitSharingDetail {
|
|
const factory ProfitSharingDetail({
|
|
required String organizationId,
|
|
required String outletId,
|
|
required String outletName,
|
|
required DateTime dateFrom,
|
|
required DateTime dateTo,
|
|
required String parentCategoryId,
|
|
required String parentCategoryName,
|
|
required ProfitSharingCategory summary,
|
|
required List<ProfitSharingSubCategory> categories,
|
|
required ProfitSharingBudget budget,
|
|
}) = _ProfitSharingDetail;
|
|
|
|
factory ProfitSharingDetail.empty() => ProfitSharingDetail(
|
|
organizationId: '',
|
|
outletId: '',
|
|
outletName: '',
|
|
dateFrom: DateTime.fromMillisecondsSinceEpoch(0),
|
|
dateTo: DateTime.fromMillisecondsSinceEpoch(0),
|
|
parentCategoryId: '',
|
|
parentCategoryName: '',
|
|
summary: ProfitSharingCategory.empty(),
|
|
categories: [],
|
|
budget: ProfitSharingBudget.empty(),
|
|
);
|
|
}
|
|
|
|
@freezed
|
|
class ProfitSharingSubCategory with _$ProfitSharingSubCategory {
|
|
const ProfitSharingSubCategory._();
|
|
|
|
const factory ProfitSharingSubCategory({
|
|
required String categoryId,
|
|
required String categoryName,
|
|
required int totalRevenue,
|
|
required int totalQuantity,
|
|
required int productCount,
|
|
required int orderCount,
|
|
required int totalStandardHpp,
|
|
required int totalFifoHpp,
|
|
required int totalMovingAverageHpp,
|
|
required List<ProfitSharingProduct> products,
|
|
}) = _ProfitSharingSubCategory;
|
|
|
|
double get standardHppPercentage =>
|
|
totalRevenue == 0 ? 0 : (totalStandardHpp / totalRevenue) * 100;
|
|
|
|
double get realHppPercentage =>
|
|
totalRevenue == 0 ? 0 : (totalFifoHpp / totalRevenue) * 100;
|
|
}
|
|
|
|
@freezed
|
|
class ProfitSharingProduct with _$ProfitSharingProduct {
|
|
const ProfitSharingProduct._();
|
|
|
|
const factory ProfitSharingProduct({
|
|
required String productId,
|
|
required String productName,
|
|
required String productSku,
|
|
required int productPrice,
|
|
required int quantitySold,
|
|
required int revenue,
|
|
required double averagePrice,
|
|
required int orderCount,
|
|
required double standardHppPerUnit,
|
|
required int standardHppTotal,
|
|
required double fifoHppPerUnit,
|
|
required int fifoHppTotal,
|
|
required double movingAverageHppPerUnit,
|
|
required int movingAverageHppTotal,
|
|
}) = _ProfitSharingProduct;
|
|
|
|
double get standardHppPercentage =>
|
|
revenue == 0 ? 0 : (standardHppTotal / revenue) * 100;
|
|
|
|
double get realHppPercentage =>
|
|
revenue == 0 ? 0 : (fifoHppTotal / revenue) * 100;
|
|
}
|