[] = [
+ {
+ id: 'no',
+ header: 'No',
+ cell: (props) => props.row.index + 1,
+ footer: () => TOTAL
,
+ },
+ {
+ id: 'kandang_name',
+ header: 'Kandang',
+ accessorKey: 'kandang.name',
+ cell: (props) => {
+ const kandang = props.row.original.kandang;
+ return kandang?.name || '-';
+ },
+ footer: () => ALL
,
+ },
+ {
+ id: 'weight_range',
+ header: 'Rentang Bobot',
+ accessorKey: 'weight_range',
+ cell: (props) => {
+ const weightRange = props.row.original.weight_range;
+ return weightRange
+ ? `${formatNumber(weightRange.weight_min)} - ${formatNumber(weightRange.weight_max)}`
+ : '-';
+ },
+ footer: () => -
,
+ },
+ {
+ id: 'avg_weight_kg',
+ header: 'Rata-Rata Bobot (KG)',
+ accessorKey: 'avg_weight_kg',
+ cell: (props) => {
+ const value = props.row.original.avg_weight_kg;
+ return {formatNumber(value)}
;
+ },
+ footer: () => (
+
+ {formatNumber(summaryTotal?.average_weight_kg || 0)}
+
+ ),
+ },
+ {
+ id: 'remaining_chicken_birds',
+ header: 'Sisa Ayam (Ekor)',
+ accessorKey: 'remaining_chicken_birds',
+ cell: (props) => {
+ const value = props.row.original.remaining_chicken_birds;
+ return {formatNumber(value)}
;
+ },
+ footer: () => (
+
+ {formatNumber(summaryTotal?.total_remaining_chicken_birds || 0)}
+
+ ),
+ },
+ {
+ id: 'remaining_chicken_weight_kg',
+ header: 'Sisa Ayam (KG)',
+ accessorKey: 'remaining_chicken_weight_kg',
+ cell: (props) => {
+ const value = props.row.original.remaining_chicken_weight_kg;
+ return {formatNumber(value)}
;
+ },
+ footer: () => (
+
+ {formatNumber(summaryTotal?.total_remaining_chicken_weight_kg || 0)}
+
+ ),
+ },
+ {
+ id: 'egg_production_pieces',
+ header: 'Produksi Telur (Butir)',
+ accessorKey: 'egg_production_pieces',
+ cell: (props) => {
+ const value = props.row.original.egg_production_pieces;
+ return {formatNumber(value)}
;
+ },
+ footer: () => (
+
+ {formatNumber(summaryTotal?.total_egg_production_pieces || 0)}
+
+ ),
+ },
+ {
+ id: 'egg_production_kg',
+ header: 'Produksi Telur (KG)',
+ accessorKey: 'egg_production_kg',
+ cell: (props) => {
+ const value = props.row.original.egg_production_kg;
+ return {formatNumber(value)}
;
+ },
+ footer: () => (
+
+ {formatNumber(summaryTotal?.total_remaining_chicken_weight_kg || 0)}
+
+ ),
+ },
+ {
+ id: 'feed_suppliers',
+ header: 'Feed (Supplier)',
+ accessorKey: 'feed_suppliers',
+ cell: (props) => {
+ const suppliers = props.row.original.feed_suppliers;
+ return (
+ suppliers
+ ?.map((s: { alias?: string; name: string }) => s.alias || s.name)
+ .join(' | ') || '-'
+ );
+ },
+ footer: () => (
+
+ {allFeedSuppliers || '-'}
+
+ ),
+ },
+ {
+ id: 'doc_suppliers',
+ header: 'DOC (Supplier)',
+ accessorKey: 'doc_suppliers',
+ cell: (props) => {
+ const suppliers = props.row.original.doc_suppliers;
+ return (
+ suppliers
+ ?.map((s: { alias?: string; name: string }) => s.alias || s.name)
+ .join(' | ') || '-'
+ );
+ },
+ footer: () => (
+
+ {allDocSuppliers || '-'}
+
+ ),
+ },
+ {
+ id: 'average_doc_price_rp',
+ header: 'Rata-Rata Harga DOC (RP)',
+ accessorKey: 'average_doc_price_rp',
+ cell: (props) => {
+ const value = props.row.original.average_doc_price_rp;
+ return {formatCurrency(value)}
;
+ },
+ footer: () => (
+
+ {formatCurrency(summaryTotal?.total_average_doc_price_rp || 0)}
+
+ ),
+ },
+ {
+ id: 'egg_value_rp',
+ header: 'Nilai Nominal Telur (RP)',
+ accessorKey: 'egg_value_rp',
+ cell: (props) => {
+ const value = props.row.original.egg_value_rp;
+ return {formatCurrency(value)}
;
+ },
+ footer: () => (
+
+ {formatCurrency(summaryTotal?.total_egg_value_rp || 0)}
+
+ ),
+ },
+ {
+ id: 'hpp_rp',
+ header: 'HPP Ayam (RP)',
+ accessorKey: 'hpp_rp',
+ cell: (props) => {
+ const value = props.row.original.hpp_rp;
+ return {formatCurrency(value)}
;
+ },
+ footer: () => (
+
+ {formatCurrency(summaryTotal?.total_hpp_rp || 0)}
+
+ ),
+ },
+ {
+ id: 'egg_hpp_rp_per_kg',
+ header: 'HPP Telur (RP/KG)',
+ accessorKey: 'egg_hpp_rp_per_kg',
+ cell: (props) => {
+ const value = props.row.original.egg_hpp_rp_per_kg;
+ return {formatCurrency(value)}
;
+ },
+ footer: () => (
+
+ {formatCurrency(summaryTotal?.average_egg_hpp_rp_per_kg || 0)}
+
+ ),
+ },
+ {
+ id: 'remaining_value_rp',
+ header: 'Nilai Nominal Sisa Ayam (RP)',
+ accessorKey: 'remaining_value_rp',
+ cell: (props) => {
+ const value = props.row.original.remaining_value_rp;
+ return {formatCurrency(value)}
;
+ },
+ footer: () => (
+
+ {formatCurrency(summaryTotal?.total_remaining_value_rp || 0)}
+
+ ),
+ },
+ ];
+ return tableColumns;
+ };
+
+ // ===== CUSTOM ROW RENDERER =====
+ const renderCustomRow = useCallback(
+ (row: Row) => {
+ if (row.index === data.length - 1) {
+ const defaultRow = (
+
+ {row.getVisibleCells().map((cell) => (
+ |
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+ |
+ ))}
+
+ );
+
+ const customRows = [
+
+ |
+ Rekapitulasi per rentang bobot
+ |
+
,
+ ];
+
+ if (perWeightRangeSummary.length > 0) {
+ perWeightRangeSummary.forEach(
+ (item: HppPerKandangPerWeightRange, index = 0) => {
+ customRows.push(
+
+ | {index + 1} |
+ ALL |
+ {item.label} |
+
+ {formatNumber(item.avg_weight_kg)}
+ |
+
+ {formatNumber(item.remaining_chicken_birds)}
+ |
+
+ {formatNumber(item.remaining_chicken_weight_kg)}
+ |
+
+ {formatNumber(item.egg_production_pieces)}
+ |
+
+ {formatNumber(item.egg_production_kg)}
+ |
+
+ {item.feed_suppliers
+ ?.map((s) => s.alias || s.name)
+ .join(' | ') || '-'}
+ |
+
+ {item.doc_suppliers
+ ?.map((s) => s.alias || s.name)
+ .join(' | ') || '-'}
+ |
+
+ {formatCurrency(item.average_doc_price_rp)}
+ |
+
+ {formatCurrency(item.egg_value_rp)}
+ |
+ {formatCurrency(item.hpp_rp)} |
+
+ {formatCurrency(item.egg_hpp_rp_per_kg)}
+ |
+
+ {formatCurrency(item.remaining_value_rp)}
+ |
+
+ );
+ }
+ );
+ }
+
+ return [defaultRow, ...customRows];
+ }
+
+ return null;
+ },
+ [data, perWeightRangeSummary]
+ );
+
+ return (
+
+
HPP Harian Kandang (${period})`
+ : 'Laporan > HPP Harian Kandang'
+ }
+ className={{ wrapper: 'w-full', body: 'p-1!' }}
+ >
+
+
+ (tableFilterState.area_id || [])
+ .map(String)
+ .includes(String(opt.value))
+ )}
+ onChange={areaChangeHandler}
+ isLoading={isLoadingAreas}
+ isClearable
+ />
+
+ (tableFilterState.location_id || [])
+ .map(String)
+ .includes(String(opt.value))
+ )}
+ onChange={locationChangeHandler}
+ isLoading={isLoadingLocations}
+ isClearable
+ />
+
+ (tableFilterState.kandang_id || [])
+ .map(String)
+ .includes(String(opt.value))
+ )}
+ onChange={kandangChangeHandler}
+ isLoading={isLoadingKandangs}
+ isClearable
+ />
+
+
+
+
+
+
+
+
+
opt.value === 'true') ||
+ null
+ : showUnrecordedOptions.find((opt) => opt.value === 'false') ||
+ null
+ }
+ onChange={showUnrecordedChangeHandler}
+ />
+
+
+
+
+
+
+ Export
+
+
+ }
+ align='end'
+ >
+
+
+
+
+
+
+ {!isSubmitted ? (
+
+ Silakan pilih filter dan klik tombol Cari untuk menampilkan data.
+
+ ) : isLoading ? (
+
+
+
+ ) : data.length === 0 ? (
+
+ Tidak ada data yang dapat ditampilkan...
+
+ ) : (
+ 0}
+ renderCustomRow={renderCustomRow}
+ className={{
+ containerClassName: 'w-full mt-6',
+ tableWrapperClassName: 'overflow-x-auto mt-4',
+ tableClassName: 'w-full table-auto text-sm',
+ headerRowClassName: 'border-b border-b-gray-200 bg-gray-50',
+ headerColumnClassName:
+ 'px-4 py-3 text-xs font-semibold text-gray-700 text-left border border-gray-200',
+ bodyRowClassName:
+ 'hover:bg-gray-50 transition-colors border-b border-l border-r border-b-gray-200 border-l-gray-200 border-r-gray-200',
+ bodyColumnClassName:
+ 'px-4 py-3 text-xs text-gray-900 whitespace-nowrap',
+ tableFooterClassName:
+ 'bg-gray-100 font-semibold border border-gray-200',
+ footerRowClassName: 'border-t-2 border-gray-300',
+ footerColumnClassName:
+ 'px-4 py-3 text-xs text-gray-900 whitespace-nowrap',
+ }}
+ />
+ )}
+
+
+ );
+};
+
+export default HppPerKandangTab;
diff --git a/src/services/api/report/marketing-sale.ts b/src/services/api/report/marketing-sale.ts
new file mode 100644
index 00000000..bb9c1f49
--- /dev/null
+++ b/src/services/api/report/marketing-sale.ts
@@ -0,0 +1,53 @@
+import { BaseApiService } from '@/services/api/base';
+import { BaseApiResponse } from '@/types/api/api-general';
+import { HppPerKandangReport } from '@/types/api/report/hpp-per-kandang';
+
+export class MarketingSaleReportService extends BaseApiService<
+ HppPerKandangReport,
+ unknown,
+ unknown
+> {
+ constructor(basePath: string) {
+ super(basePath);
+ }
+
+ async getHppPerKandangReport(
+ area_id?: string,
+ location_id?: string,
+ kandang_id?: string,
+ weight_min?: string,
+ weight_max?: string,
+ period?: string,
+ sort_by?: string,
+ show_unrecorded?: boolean,
+ page?: number,
+ limit?: number
+ ): Promise | undefined> {
+ return await this.customRequest>(
+ `hpp-per-kandang`,
+ {
+ method: 'GET',
+ params: {
+ area_id: area_id,
+ location_id: location_id,
+ kandang_id: kandang_id,
+ weight_min: weight_min,
+ weight_max: weight_max,
+ period: period,
+ sort_by: sort_by,
+ show_unrecorded: show_unrecorded,
+ page: page,
+ limit: limit,
+ },
+ }
+ );
+ }
+}
+
+export const SaleReportApi = new MarketingSaleReportService(
+ 'reports/marketings'
+);
+
+// export const SaleReportApi = new MarketingSaleReportService(
+// 'http://localhost:4010/api/reports/marketings'
+// );
diff --git a/src/types/api/report/hpp-per-kandang.d.ts b/src/types/api/report/hpp-per-kandang.d.ts
new file mode 100644
index 00000000..824a3837
--- /dev/null
+++ b/src/types/api/report/hpp-per-kandang.d.ts
@@ -0,0 +1,69 @@
+import { BaseMetadata } from '@types/api/base-metadata';
+import { Supplier } from '@/types/api/master-data/supplier';
+import { Kandang } from '@/types/api/master-data/kandang';
+
+export type HppPerKandangRow = {
+ id: number;
+ kandang: Kandang;
+ weight_range: {
+ weight_min: number;
+ weight_max: number;
+ };
+ remaining_chicken_birds: number;
+ remaining_chicken_weight_kg: number;
+ avg_weight_kg: number;
+ egg_production_pieces: number;
+ egg_production_kg: number;
+ egg_hpp_rp_per_kg: number;
+ egg_value_rp: number;
+ feed_suppliers: Supplier[];
+ doc_suppliers: Supplier[];
+ average_doc_price_rp: number;
+ hpp_rp: number;
+ remaining_value_rp: number;
+};
+
+export type HppPerKandangSummaryTotal = {
+ total_remaining_chicken_birds: number;
+ total_remaining_chicken_weight_kg: number;
+ average_weight_kg: number;
+ total_remaining_value_rp: number;
+ total_egg_production_pieces: number;
+ total_egg_production_kg: number;
+ average_egg_hpp_rp_per_kg: number;
+ total_egg_value_rp: number;
+ total_hpp_rp: number;
+ total_average_doc_price_rp: number;
+};
+
+export type HppPerKandangPerWeightRange = {
+ id: number;
+ weight_range: {
+ weight_min: number;
+ weight_max: number;
+ };
+ label: string;
+ remaining_chicken_birds: number;
+ remaining_chicken_weight_kg: number;
+ avg_weight_kg: number;
+ egg_production_pieces: number;
+ egg_production_kg: number;
+ egg_hpp_rp_per_kg: number;
+ egg_value_rp: number;
+ feed_suppliers: Supplier[];
+ doc_suppliers: Supplier[];
+ average_doc_price_rp: number;
+ hpp_rp: number;
+ remaining_value_rp: number;
+};
+
+export type HppPerKandangSummary = {
+ per_weight_range: HppPerKandangPerWeightRange[];
+ total: HppPerKandangSummaryTotal;
+};
+
+export type HppPerKandangReport = BaseMetadata & {
+ period: string;
+ rows: HppPerKandangRow[];
+ summary: HppPerKandangSummary;
+};