Skip to content

Commit

Permalink
Tax reports WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
rylorin committed Mar 27, 2024
1 parent ea5f3b1 commit 9c7ab00
Show file tree
Hide file tree
Showing 11 changed files with 139 additions and 48 deletions.
51 changes: 46 additions & 5 deletions src/app/components/Portfolio/Report/ReportIndex.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,45 @@
import { Link, Table, TableCaption, TableContainer, Tbody, Td, Thead, Tr } from "@chakra-ui/react";
import { FunctionComponent, default as React } from "react";
import { Link as RouterLink, useLoaderData, useParams } from "react-router-dom";
import { ReportEntry } from "../../../../routers/reports.types";
import Number from "../../Number/Number";
import { StatementLink } from "../Statement/links";
import { ReportLink } from "./links";

type Props = Record<string, never>;

const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

/**
* Statements list component
* @param param0
* @returns
*/
const ReportsIndex: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode => {
const { portfolioId } = useParams();
const theReports = useLoaderData() as number[];
const theReports = useLoaderData() as ReportEntry[];
const years = theReports.reduce((p, v) => {
if (!p.includes(v.year)) p.push(v.year);
return p;
}, [] as number[]);

const Cell = ({ year, month }: { year: number; month: number }): React.ReactNode => {
const report = theReports.find((item) => item.year == year && item.month == month);
const value = report
? report.dividendsSummary.reduce((p, v) => p + v.grossAmountInBase, 0) +
report.interestsSummary.totalAmountInBase +
report.feesSummary.totalAmountInBase
: 0;
return (
<>
{report && (
<Link to={StatementLink.toMonth(portfolioId, year, month)} as={RouterLink}>
<Number value={value} />
</Link>
)}
</>
);
};

return (
<>
Expand All @@ -22,16 +49,30 @@ const ReportsIndex: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode =
<Thead>
<Tr>
<Td>Year</Td>
{months.map((month) => {
return (
<td key={month} align="right">
{month}
</td>
);
})}
</Tr>
</Thead>
<Tbody>
{theReports.map((item) => (
<Tr key={item}>
{years.map((year) => (
<Tr key={year}>
<td>
<Link to={ReportLink.toItem(portfolioId, item)} as={RouterLink}>
{item}
<Link to={ReportLink.toItem(portfolioId, year)} as={RouterLink}>
{year}
</Link>
</td>
{months.map((month, i) => {
return (
<td key={year + "-" + month} align="right">
<Cell year={year} month={i + 1} />
</td>
);
})}
</Tr>
))}
</Tbody>
Expand Down
11 changes: 4 additions & 7 deletions src/app/components/Portfolio/Report/ReportSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { FunctionComponent, default as React } from "react";
import { Link as RouterLink, useLoaderData, useParams } from "react-router-dom";
import { DididendSummary, ReportEntry } from "../../../../routers/reports.types";
import Number from "../../Number/Number";
import StatementsTable from "../Statement/StatementsTable";
import { ReportLink } from "./links";

type Props = Record<string, never>;
Expand All @@ -15,7 +14,7 @@ type Props = Record<string, never>;
*/
const ReportSummary: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode => {
const { portfolioId } = useParams();
const theReport = useLoaderData() as ReportEntry;
const theReport = useLoaderData()[0] as ReportEntry;

return (
<>
Expand All @@ -26,7 +25,6 @@ const ReportSummary: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode
</Link>
<Spacer />
</Box>
{/* <DividendsSummaryTable /> */}
<h2>Dividends</h2>
<VStack align="left">
<HStack alignContent="left">
Expand Down Expand Up @@ -65,8 +63,7 @@ const ReportSummary: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode
<Spacer />
</HStack>
</VStack>
<StatementsTable content={theReport.dividendsDetails} title="Dividends" />
{/* <InterestsTable /> */}
{/* <StatementsTable content={theReport.dividendsDetails} title="Dividends" /> */}
<h2>Interests</h2>
<SimpleGrid columns={2}>
<Box>Gross credit</Box>
Expand All @@ -86,7 +83,7 @@ const ReportSummary: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode
<Number value={theReport.interestsSummary.totalAmountInBase} />
</Box>
</SimpleGrid>
<StatementsTable content={theReport.interestsDetails} title="Interests" />
{/* <StatementsTable content={theReport.interestsDetails} title="Interests" /> */}
<h2>Fees</h2>
<HStack align="left">
<Box>Total</Box>
Expand All @@ -95,7 +92,7 @@ const ReportSummary: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode
</Box>
<Spacer />
</HStack>
<StatementsTable content={theReport.feesDetails} title="Fees" />
{/* <StatementsTable content={theReport.feesDetails} title="Fees" /> */}
</>
);
};
Expand Down
18 changes: 15 additions & 3 deletions src/app/components/Portfolio/Report/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,33 @@ import { ReportEntry } from "../../../../routers/reports.types";
* @param param0
* @returns
*/
export const reportsIndexLoader = ({ params }: LoaderFunctionArgs): Promise<number[]> => {
export const reportsIndexLoader0 = ({ params }: LoaderFunctionArgs): Promise<number[]> => {
const { portfolioId } = params;
return fetch(`/api/portfolio/${portfolioId}/reports/index`)
.then((response) => response.json())
.then((data) => data.reports as number[]);
};

/**
* Fetch all reports
* @param param0
* @returns
*/
export const reportsIndexLoader = ({ params }: LoaderFunctionArgs): Promise<ReportEntry[]> => {
const { portfolioId } = params;
return fetch(`/api/portfolio/${portfolioId}/reports/summary/all`)
.then((response) => response.json())
.then((data) => data.reports as ReportEntry[]);
};

/**
* Fetch a report
* @param param0
* @returns
*/
export const reportSummaryLoader = ({ params }: LoaderFunctionArgs): Promise<ReportEntry> => {
export const reportSummaryLoader = ({ params }: LoaderFunctionArgs): Promise<ReportEntry[]> => {
const { portfolioId, year } = params;
return fetch(`/api/portfolio/${portfolioId}/reports/year/${year}`)
.then((response) => response.json())
.then((data) => data.report as ReportEntry);
.then((data) => data.reports as ReportEntry[]);
};
2 changes: 1 addition & 1 deletion src/app/components/Portfolio/Statement/BaseStatement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const BaseStatement = ({ portfolioId, statement }: Props): React.ReactNode => {
Date:
</Text>
<Text w="200px" textAlign="right">
<Link to={StatementLink.toMonth(portfolioId, new Date(statement.date))} as={RouterLink}>
<Link to={StatementLink.toDate(portfolioId, new Date(statement.date))} as={RouterLink}>
{new Date(statement.date).toLocaleString()}
</Link>
</Text>
Expand Down
5 changes: 4 additions & 1 deletion src/app/components/Portfolio/Statement/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ export const StatementLink = {
toIndex: (portfolioId: number | string): string => `/portfolio/${portfolioId}/statements/summary/ytd/`,
toItem: (portfolioId: number | string, statementId: number | string): string =>
`/portfolio/${portfolioId}/statements/id/${statementId}/`,
toMonth: (portfolioId: number | string, date: Date | string): string => {
toDate: (portfolioId: number | string, date: Date | string): string => {
if (typeof date != "string") date = date.toISOString();
return `/portfolio/${portfolioId}/statements/month/${date.substring(0, 4)}/${date.substring(5, 7)}/`;
},
toMonth: (portfolioId: number | string, year: number | string, month: number | string): string => {
return `/portfolio/${portfolioId}/statements/month/${year}/${month}/`;
},
edit: (portfolioId: number | string, itemId: number | string): string =>
`/portfolio/${portfolioId}/statements/id/${itemId}/edit`,
};
4 changes: 2 additions & 2 deletions src/app/components/Portfolio/Trade/TradeShow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const TradeShow: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode => {
Open date:
</Text>
<Text w="200px" textAlign="right">
<Link to={StatementLink.toMonth(portfolioId, new Date(item.openingDate))} as={RouterLink}>
<Link to={StatementLink.toDate(portfolioId, new Date(item.openingDate))} as={RouterLink}>
{new Date(item.openingDate).toLocaleString()}
</Link>
</Text>
Expand Down Expand Up @@ -66,7 +66,7 @@ const TradeShow: FunctionComponent<Props> = ({ ..._rest }): React.ReactNode => {
</Text>
<Text w="200px" textAlign="right">
{item.closingDate && (
<Link to={StatementLink.toMonth(portfolioId, new Date(item.closingDate))} as={RouterLink}>
<Link to={StatementLink.toDate(portfolioId, new Date(item.closingDate))} as={RouterLink}>
{new Date(item.closingDate).toLocaleString()}
</Link>
)}
Expand Down
39 changes: 34 additions & 5 deletions src/routers/reports.router.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { default as express } from "express";
import { Op } from "sequelize";
import { Balance, Currency, Portfolio } from "../models";
import { LogLevel, default as logger } from "../logger";
import { Balance, Currency, Portfolio, Statement } from "../models";
import { prepareReport } from "./statements.utils";

// const MODULE = "ReportsRouter";
const MODULE = "ReportsRouter";

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unused-vars
const sequelize_logging = (...args: any[]): void => logger.trace(MODULE + ".squelize", ...args);

const router = express.Router({ mergeParams: true });

Expand Down Expand Up @@ -53,16 +57,41 @@ router.get("/year/:year(\\d+)", (req, res): void => {
})
.then((portfolio) => {
if (portfolio) {
return prepareReport(portfolio, parseInt(year), 0);
return prepareReport(portfolio.statements);
} else {
throw Error("portfolio doesn't exist");
}
})
.then((report) => {
res.status(200).json({ report });
.then((reports) => {
res.status(200).json({ reports });
})
.catch((error) => {
console.error(error);
res.status(500).json({ error });
});
});

/**
* Get all monthly reports
*/
router.get("/summary/all", (req, res): void => {
const { portfolioId } = req.params as typeof req.params & parentParams;

Statement.findAll({
where: {
portfolio_id: portfolioId,
date: {
[Op.gte]: new Date(2021, 0, 1),
},
},
})
.then((statements) => prepareReport(statements))
.then((reports) => {
res.status(200).json({ reports });
})
.catch((error) => {
console.error(error);
logger.log(LogLevel.Error, MODULE + ".All", undefined, JSON.stringify(error));
res.status(500).json({ error });
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/routers/reports.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export type FeesSummary = {
* Report entry data transfered between frontend and backend
*/
export type ReportEntry = {
portfolioId: number;
// portfolioId: number;
year: number;
month: number;
dividendsSummary: DididendSummary[];
Expand Down
2 changes: 1 addition & 1 deletion src/routers/statements.router.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import express from "express";
import { Op } from "sequelize";
import logger, { LogLevel } from "../logger";
import { default as logger, LogLevel } from "../logger";
import {
Contract,
DividendStatement,
Expand Down
2 changes: 1 addition & 1 deletion src/routers/statements.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export type DividendStatementEntry = BaseStatement & {
country: string;
};
export type TaxStatementEntry = BaseStatement & { statementType: "Tax"; country: string };
export type InterestStatementEntry = BaseStatement & { statementType: "Interest"; country: string };
export type InterestStatementEntry = BaseStatement & { statementType: "Interest"; country: string | null };
export type WithHoldingStatementEntry = BaseStatement & { statementType: "WithHolding" };
export type FeeStatementEntry = BaseStatement & { statementType: "OtherFee" };
export type CorporateStatementEntry = BaseStatement & { statementType: "CorporateStatement" };
Expand Down
Loading

0 comments on commit 9c7ab00

Please sign in to comment.