Skip to content

Commit aa15541

Browse files
rajoute un truc genre pour avoir l'historique des achat d'une entreprise
1 parent 9a28636 commit aa15541

File tree

3 files changed

+106
-1
lines changed

3 files changed

+106
-1
lines changed

src/app/companies/[companyId]/page.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { ManageMembersDialog } from '@/components/manage-members-dialog';
1616
import { WithdrawCompanyCashDialog } from '@/components/withdraw-company-cash-dialog';
1717
import { ListCompanyButton } from '@/components/list-company-button';
1818
import { ClaimBtcButton } from '@/components/claim-btc-button';
19+
import { format } from 'date-fns';
20+
import { fr } from 'date-fns/locale';
1921

2022

2123
function getInitials(name: string) {
@@ -252,6 +254,54 @@ export default async function CompanyDetailPage({ params }: { params: { companyI
252254
</Card>
253255
</div>
254256

257+
<Card>
258+
<CardHeader>
259+
<CardTitle>Historique des Transactions de l'Entreprise</CardTitle>
260+
<CardDescription>Journal des achats et ventes d'actifs par {company.name}.</CardDescription>
261+
</CardHeader>
262+
<CardContent>
263+
<Table>
264+
<TableHeader>
265+
<TableRow>
266+
<TableHead>Type</TableHead>
267+
<TableHead>Actif</TableHead>
268+
<TableHead className="text-right">Quantité</TableHead>
269+
<TableHead className="text-right">Prix Unitaire</TableHead>
270+
<TableHead className="text-right">Valeur Totale</TableHead>
271+
<TableHead className="text-right">Date</TableHead>
272+
</TableRow>
273+
</TableHeader>
274+
<TableBody>
275+
{company.transactions && company.transactions.length > 0 ? company.transactions.map(tx => (
276+
<TableRow key={tx.id}>
277+
<TableCell>
278+
<Badge variant={tx.type === 'Buy' ? 'destructive' : 'default'} className={tx.type === 'Sell' ? 'bg-green-600' : ''}>
279+
{tx.type === 'Buy' ? 'Achat' : 'Vente'}
280+
</Badge>
281+
</TableCell>
282+
<TableCell>
283+
<div className="font-medium">{tx.name}</div>
284+
<div className="text-sm text-muted-foreground">{tx.ticker}</div>
285+
</TableCell>
286+
<TableCell className="text-right font-mono">{tx.quantity.toLocaleString(undefined, { maximumFractionDigits: 8 })}</TableCell>
287+
<TableCell className="text-right font-mono">${tx.price.toFixed(4)}</TableCell>
288+
<TableCell className={`text-right font-medium ${tx.type === 'Buy' ? 'text-red-500' : 'text-green-500'}`}>
289+
{tx.type === 'Buy' ? '-' : '+'}${tx.value.toFixed(2)}
290+
</TableCell>
291+
<TableCell className="text-right text-sm">{format(tx.createdAt, 'd MMM yyyy, HH:mm', { locale: fr })}</TableCell>
292+
</TableRow>
293+
)) : (
294+
<TableRow>
295+
<TableCell colSpan={6} className="h-24 text-center text-muted-foreground">
296+
Cette entreprise n'a encore effectué aucune transaction.
297+
</TableCell>
298+
</TableRow>
299+
)}
300+
</TableBody>
301+
</Table>
302+
</CardContent>
303+
</Card>
304+
255305
<Card>
256306
<CardHeader className="flex flex-row items-center justify-between">
257307
<div>

src/lib/actions/companies.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { z } from 'zod';
55
import { db } from '@/lib/db';
6-
import { companies, companyMembers, users, companyShares, companyHoldings, assets as assetsSchema, transactions, companyMiningRigs } from '@/lib/db/schema';
6+
import { companies, companyMembers, users, companyShares, companyHoldings, assets as assetsSchema, transactions, companyMiningRigs, companyTransactions } from '@/lib/db/schema';
77
import { getSession } from '../session';
88
import { revalidatePath } from 'next/cache';
99
import { eq, and, desc, or, ilike, notInArray, inArray, sql } from 'drizzle-orm';
@@ -270,6 +270,10 @@ export async function getCompanyById(companyId: number) {
270270
orderBy: (companyHoldings, { desc }) => [desc(companyHoldings.updatedAt)],
271271
},
272272
miningRigs: true,
273+
transactions: {
274+
orderBy: [desc(companyTransactions.createdAt)],
275+
limit: 20,
276+
},
273277
}
274278
});
275279

@@ -311,6 +315,14 @@ export async function getCompanyById(companyId: number) {
311315
return total + (rigData?.price || 0) * ownedRig.quantity;
312316
}, 0);
313317

318+
const formattedTransactions = company.transactions.map(tx => ({
319+
...tx,
320+
quantity: parseFloat(tx.quantity),
321+
price: parseFloat(tx.price),
322+
value: parseFloat(tx.value),
323+
createdAt: new Date(tx.createdAt),
324+
}));
325+
314326
return {
315327
...company,
316328
cash: parseFloat(company.cash),
@@ -319,6 +331,7 @@ export async function getCompanyById(companyId: number) {
319331
marketCap: marketCap,
320332
miningRigsValue: miningRigsValue,
321333
unclaimedBtc: finalUnclaimedBtc,
334+
transactions: formattedTransactions,
322335
shares: company.shares.map(s => ({...s, quantity: parseFloat(s.quantity), avgCost: parseFloat(s.avgCost)})),
323336
holdings: company.holdings.map(h => ({
324337
...h,
@@ -793,6 +806,17 @@ export async function buyAssetForCompany(companyId: number, ticker: string, quan
793806
avgCost: asset.price,
794807
});
795808
}
809+
810+
await tx.insert(companyTransactions).values({
811+
companyId: companyId,
812+
type: 'Buy',
813+
ticker: asset.ticker,
814+
name: asset.name,
815+
quantity: quantity.toString(),
816+
price: asset.price,
817+
value: tradeValue.toString(),
818+
});
819+
796820
return { success: `L'entreprise a acheté ${quantity} de ${ticker}.` };
797821
});
798822

@@ -833,6 +857,17 @@ export async function sellAssetForCompany(companyId: number, holdingId: number,
833857
} else {
834858
await tx.delete(companyHoldings).where(eq(companyHoldings.id, holdingId));
835859
}
860+
861+
await tx.insert(companyTransactions).values({
862+
companyId: companyId,
863+
type: 'Sell',
864+
ticker: asset.ticker,
865+
name: asset.name,
866+
quantity: quantity.toString(),
867+
price: asset.price,
868+
value: tradeValue.toString(),
869+
});
870+
836871
return { success: `L'entreprise a vendu ${quantity} de ${asset.ticker}.` };
837872
});
838873

src/lib/db/schema.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ export const companiesRelations = relations(companies, ({ one, many }) => ({
208208
shares: many(companyShares),
209209
holdings: many(companyHoldings),
210210
miningRigs: many(companyMiningRigs),
211+
transactions: many(companyTransactions),
211212
}));
212213

213214
export const companyMembers = pgTable('company_members', {
@@ -297,6 +298,25 @@ export const companyMiningRigsRelations = relations(companyMiningRigs, ({ one })
297298
}),
298299
}));
299300

301+
export const companyTransactions = pgTable('company_transactions', {
302+
id: serial('id').primaryKey(),
303+
companyId: integer('company_id').notNull().references(() => companies.id, { onDelete: 'cascade' }),
304+
type: varchar('type', { length: 4 }).notNull(), // 'Buy' or 'Sell'
305+
ticker: varchar('ticker', { length: 10 }).notNull(),
306+
name: varchar('name', { length: 256 }).notNull(),
307+
quantity: numeric('quantity', { precision: 18, scale: 8 }).notNull(),
308+
price: numeric('price', { precision: 18, scale: 8 }).notNull(),
309+
value: numeric('value', { precision: 18, scale: 2 }).notNull(),
310+
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
311+
});
312+
313+
export const companyTransactionsRelations = relations(companyTransactions, ({ one }) => ({
314+
company: one(companies, {
315+
fields: [companyTransactions.companyId],
316+
references: [companies.id],
317+
}),
318+
}));
319+
300320

301321
export const automaticOrders = pgTable('automatic_orders', {
302322
id: serial('id').primaryKey(),

0 commit comments

Comments
 (0)