243 lines
7.2 KiB
TypeScript
243 lines
7.2 KiB
TypeScript
import { Table, Typography } from 'antd';
|
||
import type { ColumnsType } from 'antd/es/table';
|
||
import type React from 'react';
|
||
import { useMemo } from 'react';
|
||
import type { GoodwillRow, GoodwillTableResponse, GoodwillTreeRow } from '../../../types/goodwill/goodwill';
|
||
import './ConsolidationGoodwillTable.css';
|
||
import { chessTableCellFormatValue } from '../../../utils/chessTableCellFormatValue';
|
||
import { getGoodwillColumns } from './config';
|
||
import { sumAmounts } from '../../../utils/money';
|
||
|
||
const { Text } = Typography;
|
||
|
||
interface ConsolidationGoodwillTableI {
|
||
data: GoodwillTableResponse | null;
|
||
loading: boolean;
|
||
decimals: number;
|
||
units: string;
|
||
toolbar?: React.ReactNode;
|
||
isFullscreen?: boolean;
|
||
isEditMode: boolean;
|
||
editedRows: Record<string, Partial<GoodwillRow>>;
|
||
onRowEdit: (rowId: string, field: keyof GoodwillRow, value: boolean | string) => void;
|
||
visibleKeys: string[];
|
||
}
|
||
|
||
export const ConsolidationGoodwillTable: React.FC<ConsolidationGoodwillTableI> = ({
|
||
data,
|
||
loading,
|
||
decimals,
|
||
units,
|
||
toolbar,
|
||
isFullscreen = false,
|
||
isEditMode,
|
||
editedRows,
|
||
onRowEdit,
|
||
visibleKeys,
|
||
}) => {
|
||
const treeData = useMemo(() => {
|
||
if (!data?.rows) return [];
|
||
|
||
const tree: GoodwillTreeRow[] = [];
|
||
const heads = new Map<string, GoodwillTreeRow>();
|
||
|
||
data.rows.forEach((row) => {
|
||
const headId = row.head_legal_entity.id;
|
||
|
||
if (!heads.has(headId)) {
|
||
const groupNode: GoodwillTreeRow = {
|
||
...row,
|
||
key: `head-${headId}`,
|
||
isGroup: true,
|
||
head_legal_entity: row.head_legal_entity,
|
||
subsidiary_legal_entity: { id: '', name: '' },
|
||
ownership_share: null,
|
||
financial_investment_amount: '0',
|
||
charter_capital_amount: '0',
|
||
additional_capital_amount: '0',
|
||
participation_amount: '0',
|
||
goodwill_amount: '0',
|
||
include_in_kfo: false,
|
||
comment: null,
|
||
updated_at: null,
|
||
updated_by: null,
|
||
children: [],
|
||
};
|
||
heads.set(headId, groupNode);
|
||
tree.push(groupNode);
|
||
}
|
||
|
||
const group = heads.get(headId)!;
|
||
group.children!.push({
|
||
...row,
|
||
key: `${headId}-${row.subsidiary_legal_entity.id}`,
|
||
});
|
||
});
|
||
|
||
tree.forEach((parent) => {
|
||
if (parent.children && parent.children.length > 0) {
|
||
const allChecked = parent.children.every((child) => editedRows[child.key]?.include_in_kfo ?? child.include_in_kfo);
|
||
parent.include_in_kfo = allChecked;
|
||
|
||
let totalFinInv = 0;
|
||
let totalParticipation = 0;
|
||
let totalCharter = 0;
|
||
let totalGoodwill = 0;
|
||
|
||
parent.children.forEach((child) => {
|
||
totalFinInv += Number(child.financial_investment_amount || 0);
|
||
totalParticipation += Number(child.participation_amount || 0);
|
||
totalCharter += Number(child.charter_capital_amount || 0);
|
||
totalGoodwill += Number(child.goodwill_amount || 0);
|
||
});
|
||
|
||
const groupTotalRow: GoodwillTreeRow = {
|
||
key: `total-${parent.key}`,
|
||
head_legal_entity: parent.head_legal_entity,
|
||
subsidiary_legal_entity: { id: '', name: 'Всего' },
|
||
isGroupTotal: true,
|
||
isGroup: false,
|
||
|
||
financial_investment_amount: String(totalFinInv),
|
||
participation_amount: String(totalParticipation),
|
||
charter_capital_amount: String(totalCharter),
|
||
goodwill_amount: String(totalGoodwill),
|
||
|
||
ownership_share: null,
|
||
additional_capital_amount: '0',
|
||
include_in_kfo: false,
|
||
comment: null,
|
||
updated_at: null,
|
||
updated_by: null,
|
||
};
|
||
|
||
parent.children.push(groupTotalRow);
|
||
}
|
||
});
|
||
|
||
return tree;
|
||
}, [data?.rows, editedRows]);
|
||
|
||
const columns: ColumnsType<GoodwillTreeRow> = useMemo(() => {
|
||
return getGoodwillColumns({ units, decimals, isEditMode, editedRows, onRowEdit });
|
||
}, [units, decimals, isEditMode, editedRows, onRowEdit]);
|
||
|
||
const visibleColumns = useMemo(() => {
|
||
return columns.filter((col) => visibleKeys.includes(col.key as string));
|
||
}, [columns, visibleKeys]);
|
||
|
||
const scrollY = isFullscreen ? 'calc(100vh - 200px)' : 'auto';
|
||
|
||
const renderSummary = () => {
|
||
if (!data?.rows) return null;
|
||
|
||
const totalFinInv = sumAmounts(data.rows.map((c) => c.financial_investment_amount)) ?? '0.00';
|
||
const totalParticipation = sumAmounts(data.rows.map((c) => c.participation_amount)) ?? '0.00';
|
||
const totalCharter = sumAmounts(data.rows.map((c) => c.charter_capital_amount)) ?? '0.00';
|
||
const totalGoodwill = sumAmounts(data.rows.map((c) => c.goodwill_amount)) ?? '0.00';
|
||
|
||
return (
|
||
<Table.Summary fixed>
|
||
<Table.Summary.Row className='resRow'>
|
||
{visibleColumns.map((col, index) => {
|
||
if (col.key === 'include_in_kfo') {
|
||
return (
|
||
<Table.Summary.Cell key={col.key} index={index} align='center'>
|
||
<Text strong>—</Text>
|
||
</Table.Summary.Cell>
|
||
);
|
||
}
|
||
|
||
if (col.key === 'name') {
|
||
return (
|
||
<Table.Summary.Cell key={col.key} index={index} align='left'>
|
||
<div style={{ backgroundColor: '#e6f4ea', width: '100%', height: '100%' }}>
|
||
<Text strong>Итого по листу</Text>
|
||
</div>
|
||
</Table.Summary.Cell>
|
||
);
|
||
}
|
||
|
||
if (col.key === 'ownership_share') {
|
||
return (
|
||
<Table.Summary.Cell key={col.key} index={index} align='right'>
|
||
<Text strong>—</Text>
|
||
</Table.Summary.Cell>
|
||
);
|
||
}
|
||
|
||
if (col.key === 'financial_investment_amount') {
|
||
return (
|
||
<Table.Summary.Cell key={col.key} index={index} align='right'>
|
||
<div style={{ backgroundColor: '#e6f4ea' }}>
|
||
<Text strong>{chessTableCellFormatValue(String(totalFinInv), units, decimals)}</Text>
|
||
</div>
|
||
</Table.Summary.Cell>
|
||
);
|
||
}
|
||
|
||
if (col.key === 'participation_amount') {
|
||
return (
|
||
<Table.Summary.Cell key={col.key} index={index} align='right'>
|
||
<div style={{ backgroundColor: '#e6f4ea' }}>
|
||
<Text strong>{chessTableCellFormatValue(String(totalParticipation), units, decimals)}</Text>
|
||
</div>
|
||
</Table.Summary.Cell>
|
||
);
|
||
}
|
||
|
||
if (col.key === 'charter_capital_amount') {
|
||
return (
|
||
<Table.Summary.Cell key={col.key} index={index} align='right'>
|
||
<div style={{ backgroundColor: '#e6f4ea' }}>
|
||
<Text strong>{chessTableCellFormatValue(String(totalCharter), units, decimals)}</Text>
|
||
</div>
|
||
</Table.Summary.Cell>
|
||
);
|
||
}
|
||
|
||
if (col.key === 'goodwill_amount') {
|
||
return (
|
||
<Table.Summary.Cell key={col.key} index={index} align='right'>
|
||
<div style={{ backgroundColor: '#e6f4ea' }}>
|
||
<Text strong>{chessTableCellFormatValue(String(totalGoodwill), units, decimals)}</Text>
|
||
</div>
|
||
</Table.Summary.Cell>
|
||
);
|
||
}
|
||
|
||
if (col.key === 'comment') {
|
||
return (
|
||
<Table.Summary.Cell key={col.key} index={index} align='right'>
|
||
<Text strong>—</Text>
|
||
</Table.Summary.Cell>
|
||
);
|
||
}
|
||
|
||
return null;
|
||
})}
|
||
</Table.Summary.Row>
|
||
</Table.Summary>
|
||
);
|
||
};
|
||
|
||
return (
|
||
<Table<GoodwillTreeRow>
|
||
className='goodwillTable'
|
||
dataSource={treeData}
|
||
columns={visibleColumns}
|
||
rowKey='key'
|
||
pagination={false}
|
||
loading={loading}
|
||
scroll={{ x: 'max-content', y: scrollY }}
|
||
size='small'
|
||
bordered
|
||
title={() => toolbar}
|
||
key={data?.rows?.length}
|
||
expandable={{ defaultExpandAllRows: true }}
|
||
summary={renderSummary}
|
||
rowClassName={(record) => (record.isGroupTotal ? 'group-total-row' : '')}
|
||
/>
|
||
);
|
||
};
|