feat(POS-003): completed feature
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import type pg from 'pg';
|
||||
import type { PosCashSessionRepository } from '../domain/ports.js';
|
||||
import type { PosCashSession, OpenCashSessionInput, CloseCashSessionInput } from '../domain/cash-session.js';
|
||||
|
||||
interface SessionRow {
|
||||
id: string;
|
||||
terminal_id: string;
|
||||
store_id: string;
|
||||
user_id: string;
|
||||
status: 'OPEN' | 'CLOSED';
|
||||
opened_at: Date;
|
||||
closed_at: Date | null;
|
||||
opening_cash_cents: number;
|
||||
closing_cash_cents: number | null;
|
||||
expected_cash_cents: number | null;
|
||||
actual_cash_cents: number | null;
|
||||
difference_cents: number | null;
|
||||
notes: string | null;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
function toSession(row: SessionRow): PosCashSession {
|
||||
return {
|
||||
id: row.id,
|
||||
terminalId: row.terminal_id,
|
||||
storeId: row.store_id,
|
||||
userId: row.user_id,
|
||||
status: row.status,
|
||||
openedAt: row.opened_at,
|
||||
closedAt: row.closed_at,
|
||||
openingCashCents: row.opening_cash_cents,
|
||||
closingCashCents: row.closing_cash_cents,
|
||||
expectedCashCents: row.expected_cash_cents,
|
||||
actualCashCents: row.actual_cash_cents,
|
||||
differenceCents: row.difference_cents,
|
||||
notes: row.notes,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at,
|
||||
};
|
||||
}
|
||||
|
||||
export class PgCashSessionRepository implements PosCashSessionRepository {
|
||||
constructor(private readonly pool: pg.Pool) {}
|
||||
|
||||
async findById(id: string): Promise<PosCashSession | undefined> {
|
||||
const result = await this.pool.query<SessionRow>(
|
||||
'SELECT * FROM pos_cash_sessions WHERE id = $1',
|
||||
[id],
|
||||
);
|
||||
return result.rows[0] ? toSession(result.rows[0]) : undefined;
|
||||
}
|
||||
|
||||
async findOpenByTerminal(terminalId: string): Promise<PosCashSession | undefined> {
|
||||
const result = await this.pool.query<SessionRow>(
|
||||
"SELECT * FROM pos_cash_sessions WHERE terminal_id = $1 AND status = 'OPEN'",
|
||||
[terminalId],
|
||||
);
|
||||
return result.rows[0] ? toSession(result.rows[0]) : undefined;
|
||||
}
|
||||
|
||||
async open(input: OpenCashSessionInput): Promise<PosCashSession> {
|
||||
// Get store_id from terminal
|
||||
const terminal = await this.pool.query<{ store_id: string }>(
|
||||
'SELECT store_id FROM pos_terminals WHERE id = $1',
|
||||
[input.terminalId],
|
||||
);
|
||||
if (!terminal.rows[0]) throw new Error(`Terminal ${input.terminalId} not found`);
|
||||
const storeId = terminal.rows[0].store_id;
|
||||
|
||||
const result = await this.pool.query<SessionRow>(
|
||||
`INSERT INTO pos_cash_sessions (terminal_id, store_id, user_id, opening_cash_cents)
|
||||
VALUES ($1, $2, $3, $4) RETURNING *`,
|
||||
[input.terminalId, storeId, input.userId, input.openingCashCents],
|
||||
);
|
||||
return toSession(result.rows[0]);
|
||||
}
|
||||
|
||||
async close(input: CloseCashSessionInput): Promise<PosCashSession> {
|
||||
const difference = input.actualCashCents - input.closingCashCents;
|
||||
const result = await this.pool.query<SessionRow>(
|
||||
`UPDATE pos_cash_sessions
|
||||
SET status = 'CLOSED', closed_at = now(),
|
||||
closing_cash_cents = $2, actual_cash_cents = $3,
|
||||
difference_cents = $4, notes = $5, updated_at = now()
|
||||
WHERE id = $1 RETURNING *`,
|
||||
[input.sessionId, input.closingCashCents, input.actualCashCents, difference, input.notes ?? null],
|
||||
);
|
||||
if (!result.rows[0]) throw new Error(`Session ${input.sessionId} not found`);
|
||||
return toSession(result.rows[0]);
|
||||
}
|
||||
|
||||
async listByStore(
|
||||
storeId: string,
|
||||
limit = 50,
|
||||
offset = 0,
|
||||
): Promise<{ sessions: PosCashSession[]; total: number }> {
|
||||
const [countResult, listResult] = await Promise.all([
|
||||
this.pool.query<{ count: string }>(
|
||||
'SELECT COUNT(*) as count FROM pos_cash_sessions WHERE store_id = $1',
|
||||
[storeId],
|
||||
),
|
||||
this.pool.query<SessionRow>(
|
||||
`SELECT * FROM pos_cash_sessions WHERE store_id = $1
|
||||
ORDER BY opened_at DESC LIMIT $2 OFFSET $3`,
|
||||
[storeId, limit, offset],
|
||||
),
|
||||
]);
|
||||
return {
|
||||
sessions: listResult.rows.map(toSession),
|
||||
total: parseInt(countResult.rows[0].count, 10),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user