feat: profit sharing
Build & Deploy iOS to TestFlight / build-and-deploy (push) Canceled after 0s

This commit is contained in:
efrilm
2026-08-21 22:31:54 +07:00
parent f9bfb69254
commit 2e4c77888e
48 changed files with 12553 additions and 162 deletions
@@ -0,0 +1,294 @@
part of '../analytic_dtos.dart';
@freezed
class ProfitSharingDto with _$ProfitSharingDto {
const ProfitSharingDto._();
const factory ProfitSharingDto({
@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: 'data') List<ProfitSharingCategoryDto>? data,
@JsonKey(name: 'budget') ProfitSharingBudgetDto? budget,
}) = _ProfitSharingDto;
factory ProfitSharingDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingDtoFromJson(json);
ProfitSharing toDomain() => ProfitSharing(
organizationId: organizationId ?? '',
outletId: outletId ?? '',
outletName: outletName ?? '',
dateFrom: dateFrom?.toLocal() ?? DateTime.fromMillisecondsSinceEpoch(0),
dateTo: dateTo?.toLocal() ?? DateTime.fromMillisecondsSinceEpoch(0),
categories: data?.map((e) => e.toDomain()).toList() ?? [],
budget: budget?.toDomain() ?? ProfitSharingBudget.empty(),
);
}
@freezed
class ProfitSharingCategoryDto with _$ProfitSharingCategoryDto {
const ProfitSharingCategoryDto._();
const factory ProfitSharingCategoryDto({
@JsonKey(name: 'parent_category_id') String? parentCategoryId,
@JsonKey(name: 'parent_category_name') String? parentCategoryName,
@JsonKey(name: 'total_revenue') num? totalRevenue,
@JsonKey(name: 'total_quantity') num? totalQuantity,
@JsonKey(name: 'category_count') num? categoryCount,
@JsonKey(name: 'product_count') num? productCount,
@JsonKey(name: 'order_count') num? orderCount,
@JsonKey(name: 'total_standard_hpp') num? totalStandardHpp,
@JsonKey(name: 'total_fifo_hpp') num? totalFifoHpp,
@JsonKey(name: 'total_moving_average_hpp') num? totalMovingAverageHpp,
}) = _ProfitSharingCategoryDto;
factory ProfitSharingCategoryDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingCategoryDtoFromJson(json);
ProfitSharingCategory toDomain() => ProfitSharingCategory(
parentCategoryId: parentCategoryId ?? '',
parentCategoryName: parentCategoryName ?? '',
totalRevenue: totalRevenue?.toInt() ?? 0,
totalQuantity: totalQuantity?.toInt() ?? 0,
categoryCount: categoryCount?.toInt() ?? 0,
productCount: productCount?.toInt() ?? 0,
orderCount: orderCount?.toInt() ?? 0,
totalStandardHpp: totalStandardHpp?.toInt() ?? 0,
totalFifoHpp: totalFifoHpp?.toInt() ?? 0,
totalMovingAverageHpp: totalMovingAverageHpp?.toInt() ?? 0,
);
}
@freezed
class ProfitSharingBudgetDto with _$ProfitSharingBudgetDto {
const ProfitSharingBudgetDto._();
const factory ProfitSharingBudgetDto({
@JsonKey(name: 'percentages') ProfitSharingPercentageDto? percentages,
@JsonKey(name: 'cut_off_from') DateTime? cutOffFrom,
@JsonKey(name: 'cut_off_to') DateTime? cutOffTo,
@JsonKey(name: 'total') ProfitSharingPeriodDto? total,
@JsonKey(name: 'weekly') List<ProfitSharingPeriodDto>? weekly,
@JsonKey(name: 'monthly') List<ProfitSharingPeriodDto>? monthly,
}) = _ProfitSharingBudgetDto;
factory ProfitSharingBudgetDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingBudgetDtoFromJson(json);
ProfitSharingBudget toDomain() => ProfitSharingBudget(
percentages: percentages?.toDomain() ?? ProfitSharingPercentage.empty(),
cutOffFrom: cutOffFrom?.toLocal() ?? DateTime.fromMillisecondsSinceEpoch(0),
cutOffTo: cutOffTo?.toLocal() ?? DateTime.fromMillisecondsSinceEpoch(0),
total: total?.toDomain() ?? ProfitSharingPeriod.empty(),
weekly: weekly?.map((e) => e.toDomain()).toList() ?? [],
monthly: monthly?.map((e) => e.toDomain()).toList() ?? [],
);
}
@freezed
class ProfitSharingPercentageDto with _$ProfitSharingPercentageDto {
const ProfitSharingPercentageDto._();
const factory ProfitSharingPercentageDto({
@JsonKey(name: 'purchase') num? purchase,
@JsonKey(name: 'owner') num? owner,
@JsonKey(name: 'team') num? team,
}) = _ProfitSharingPercentageDto;
factory ProfitSharingPercentageDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingPercentageDtoFromJson(json);
ProfitSharingPercentage toDomain() => ProfitSharingPercentage(
purchase: purchase?.toDouble() ?? 0,
owner: owner?.toDouble() ?? 0,
team: team?.toDouble() ?? 0,
);
}
@freezed
class ProfitSharingPeriodDto with _$ProfitSharingPeriodDto {
const ProfitSharingPeriodDto._();
const factory ProfitSharingPeriodDto({
@JsonKey(name: 'period_start') DateTime? periodStart,
@JsonKey(name: 'period_end') DateTime? periodEnd,
@JsonKey(name: 'revenue') num? revenue,
@JsonKey(name: 'order_count') num? orderCount,
@JsonKey(name: 'limit_purchase') num? limitPurchase,
@JsonKey(name: 'limit_owner') num? limitOwner,
@JsonKey(name: 'limit_team') num? limitTeam,
@JsonKey(name: 'month') String? month,
@JsonKey(name: 'week_count') num? weekCount,
}) = _ProfitSharingPeriodDto;
factory ProfitSharingPeriodDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingPeriodDtoFromJson(json);
ProfitSharingPeriod toDomain() => ProfitSharingPeriod(
periodStart:
periodStart?.toLocal() ?? DateTime.fromMillisecondsSinceEpoch(0),
periodEnd: periodEnd?.toLocal() ?? DateTime.fromMillisecondsSinceEpoch(0),
revenue: revenue?.toInt() ?? 0,
orderCount: orderCount?.toInt() ?? 0,
limitPurchase: limitPurchase?.toInt() ?? 0,
limitOwner: limitOwner?.toInt() ?? 0,
limitTeam: limitTeam?.toInt() ?? 0,
month: month ?? '',
weekCount: weekCount?.toInt() ?? 0,
);
}
@freezed
class ProfitSharingDetailDto with _$ProfitSharingDetailDto {
const ProfitSharingDetailDto._();
const factory ProfitSharingDetailDto({
@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: 'parent_category_id') String? parentCategoryId,
@JsonKey(name: 'parent_category_name') String? parentCategoryName,
@JsonKey(name: 'summary') ProfitSharingSummaryDto? summary,
@JsonKey(name: 'categories') List<ProfitSharingSubCategoryDto>? categories,
@JsonKey(name: 'budget') ProfitSharingBudgetDto? budget,
}) = _ProfitSharingDetailDto;
factory ProfitSharingDetailDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingDetailDtoFromJson(json);
ProfitSharingDetail toDomain() => ProfitSharingDetail(
organizationId: organizationId ?? '',
outletId: outletId ?? '',
outletName: outletName ?? '',
dateFrom: dateFrom?.toLocal() ?? DateTime.fromMillisecondsSinceEpoch(0),
dateTo: dateTo?.toLocal() ?? DateTime.fromMillisecondsSinceEpoch(0),
parentCategoryId: parentCategoryId ?? '',
parentCategoryName: parentCategoryName ?? '',
summary:
summary?.toDomain(
parentCategoryId: parentCategoryId ?? '',
parentCategoryName: parentCategoryName ?? '',
) ??
ProfitSharingCategory.empty(),
categories: categories?.map((e) => e.toDomain()).toList() ?? [],
budget: budget?.toDomain() ?? ProfitSharingBudget.empty(),
);
}
/// Ringkasan kategori induk pada endpoint detail — bentuknya sama dengan item
/// pada endpoint daftar, hanya saja id & nama kategori ada di level atas.
@freezed
class ProfitSharingSummaryDto with _$ProfitSharingSummaryDto {
const ProfitSharingSummaryDto._();
const factory ProfitSharingSummaryDto({
@JsonKey(name: 'total_revenue') num? totalRevenue,
@JsonKey(name: 'total_quantity') num? totalQuantity,
@JsonKey(name: 'category_count') num? categoryCount,
@JsonKey(name: 'product_count') num? productCount,
@JsonKey(name: 'order_count') num? orderCount,
@JsonKey(name: 'total_standard_hpp') num? totalStandardHpp,
@JsonKey(name: 'total_fifo_hpp') num? totalFifoHpp,
@JsonKey(name: 'total_moving_average_hpp') num? totalMovingAverageHpp,
}) = _ProfitSharingSummaryDto;
factory ProfitSharingSummaryDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingSummaryDtoFromJson(json);
ProfitSharingCategory toDomain({
required String parentCategoryId,
required String parentCategoryName,
}) => ProfitSharingCategory(
parentCategoryId: parentCategoryId,
parentCategoryName: parentCategoryName,
totalRevenue: totalRevenue?.toInt() ?? 0,
totalQuantity: totalQuantity?.toInt() ?? 0,
categoryCount: categoryCount?.toInt() ?? 0,
productCount: productCount?.toInt() ?? 0,
orderCount: orderCount?.toInt() ?? 0,
totalStandardHpp: totalStandardHpp?.toInt() ?? 0,
totalFifoHpp: totalFifoHpp?.toInt() ?? 0,
totalMovingAverageHpp: totalMovingAverageHpp?.toInt() ?? 0,
);
}
@freezed
class ProfitSharingSubCategoryDto with _$ProfitSharingSubCategoryDto {
const ProfitSharingSubCategoryDto._();
const factory ProfitSharingSubCategoryDto({
@JsonKey(name: 'category_id') String? categoryId,
@JsonKey(name: 'category_name') String? categoryName,
@JsonKey(name: 'total_revenue') num? totalRevenue,
@JsonKey(name: 'total_quantity') num? totalQuantity,
@JsonKey(name: 'product_count') num? productCount,
@JsonKey(name: 'order_count') num? orderCount,
@JsonKey(name: 'total_standard_hpp') num? totalStandardHpp,
@JsonKey(name: 'total_fifo_hpp') num? totalFifoHpp,
@JsonKey(name: 'total_moving_average_hpp') num? totalMovingAverageHpp,
@JsonKey(name: 'products') List<ProfitSharingProductDto>? products,
}) = _ProfitSharingSubCategoryDto;
factory ProfitSharingSubCategoryDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingSubCategoryDtoFromJson(json);
ProfitSharingSubCategory toDomain() => ProfitSharingSubCategory(
categoryId: categoryId ?? '',
categoryName: categoryName ?? '',
totalRevenue: totalRevenue?.toInt() ?? 0,
totalQuantity: totalQuantity?.toInt() ?? 0,
productCount: productCount?.toInt() ?? 0,
orderCount: orderCount?.toInt() ?? 0,
totalStandardHpp: totalStandardHpp?.toInt() ?? 0,
totalFifoHpp: totalFifoHpp?.toInt() ?? 0,
totalMovingAverageHpp: totalMovingAverageHpp?.toInt() ?? 0,
products: products?.map((e) => e.toDomain()).toList() ?? [],
);
}
@freezed
class ProfitSharingProductDto with _$ProfitSharingProductDto {
const ProfitSharingProductDto._();
const factory ProfitSharingProductDto({
@JsonKey(name: 'product_id') String? productId,
@JsonKey(name: 'product_name') String? productName,
@JsonKey(name: 'product_sku') String? productSku,
@JsonKey(name: 'product_price') num? productPrice,
@JsonKey(name: 'quantity_sold') num? quantitySold,
@JsonKey(name: 'revenue') num? revenue,
@JsonKey(name: 'average_price') num? averagePrice,
@JsonKey(name: 'order_count') num? orderCount,
@JsonKey(name: 'standard_hpp_per_unit') num? standardHppPerUnit,
@JsonKey(name: 'standard_hpp_total') num? standardHppTotal,
@JsonKey(name: 'fifo_hpp_per_unit') num? fifoHppPerUnit,
@JsonKey(name: 'fifo_hpp_total') num? fifoHppTotal,
@JsonKey(name: 'moving_average_hpp_per_unit') num? movingAverageHppPerUnit,
@JsonKey(name: 'moving_average_hpp_total') num? movingAverageHppTotal,
}) = _ProfitSharingProductDto;
factory ProfitSharingProductDto.fromJson(Map<String, dynamic> json) =>
_$ProfitSharingProductDtoFromJson(json);
ProfitSharingProduct toDomain() => ProfitSharingProduct(
productId: productId ?? '',
productName: productName ?? '',
productSku: productSku ?? '',
productPrice: productPrice?.toInt() ?? 0,
quantitySold: quantitySold?.toInt() ?? 0,
revenue: revenue?.toInt() ?? 0,
averagePrice: averagePrice?.toDouble() ?? 0,
orderCount: orderCount?.toInt() ?? 0,
standardHppPerUnit: standardHppPerUnit?.toDouble() ?? 0,
standardHppTotal: standardHppTotal?.toInt() ?? 0,
fifoHppPerUnit: fifoHppPerUnit?.toDouble() ?? 0,
fifoHppTotal: fifoHppTotal?.toInt() ?? 0,
movingAverageHppPerUnit: movingAverageHppPerUnit?.toDouble() ?? 0,
movingAverageHppTotal: movingAverageHppTotal?.toInt() ?? 0,
);
}