161 lines
4.7 KiB
TypeScript
161 lines
4.7 KiB
TypeScript
import { z } from 'zod';
|
|
import {
|
|
uuidSchema,
|
|
moneySchema,
|
|
paginationSchema,
|
|
} from '../../../shared/validation/common.schema';
|
|
|
|
// Enums
|
|
export const movementTypeEnum = z.enum([
|
|
'cash_in',
|
|
'cash_out',
|
|
'deposit',
|
|
'withdrawal',
|
|
'adjustment',
|
|
'opening',
|
|
'closing',
|
|
]);
|
|
|
|
export const movementReasonEnum = z.enum([
|
|
'change_fund',
|
|
'petty_cash',
|
|
'bank_deposit',
|
|
'supplier_payment',
|
|
'expense',
|
|
'salary_advance',
|
|
'correction',
|
|
'other',
|
|
]);
|
|
|
|
export const movementStatusEnum = z.enum([
|
|
'pending',
|
|
'approved',
|
|
'rejected',
|
|
'cancelled',
|
|
]);
|
|
|
|
export const closingTypeEnum = z.enum(['shift', 'daily', 'weekly', 'monthly']);
|
|
export const closingStatusEnum = z.enum([
|
|
'in_progress',
|
|
'pending_review',
|
|
'approved',
|
|
'rejected',
|
|
'reconciled',
|
|
]);
|
|
|
|
export const denominationTypeEnum = z.enum(['bill', 'coin']);
|
|
|
|
// ==================== MOVEMENT SCHEMAS ====================
|
|
|
|
// Create movement schema
|
|
export const createMovementSchema = z.object({
|
|
branchId: uuidSchema,
|
|
registerId: uuidSchema,
|
|
sessionId: uuidSchema,
|
|
type: movementTypeEnum,
|
|
reason: movementReasonEnum.optional(),
|
|
amount: moneySchema.positive('Amount must be positive'),
|
|
description: z.string().min(1, 'Description is required').max(500),
|
|
referenceType: z.string().max(50).optional(),
|
|
referenceId: uuidSchema.optional(),
|
|
referenceNumber: z.string().max(50).optional(),
|
|
requiresApproval: z.boolean().optional(),
|
|
recipientName: z.string().max(200).optional(),
|
|
recipientId: uuidSchema.optional(),
|
|
accountId: uuidSchema.optional(),
|
|
bankAccount: z.string().max(50).optional(),
|
|
depositSlipNumber: z.string().max(50).optional(),
|
|
notes: z.string().max(1000).optional(),
|
|
metadata: z.record(z.any()).optional(),
|
|
});
|
|
|
|
// Approve/reject movement schema
|
|
export const movementActionSchema = z.object({
|
|
reason: z.string().max(255).optional(),
|
|
});
|
|
|
|
// List movements query schema
|
|
export const listMovementsQuerySchema = paginationSchema.extend({
|
|
branchId: uuidSchema.optional(),
|
|
sessionId: uuidSchema.optional(),
|
|
registerId: uuidSchema.optional(),
|
|
type: movementTypeEnum.optional(),
|
|
reason: movementReasonEnum.optional(),
|
|
status: movementStatusEnum.optional(),
|
|
startDate: z.coerce.date().optional(),
|
|
endDate: z.coerce.date().optional(),
|
|
});
|
|
|
|
// ==================== CLOSING SCHEMAS ====================
|
|
|
|
// Create closing schema
|
|
export const createClosingSchema = z.object({
|
|
branchId: uuidSchema,
|
|
registerId: uuidSchema.optional(),
|
|
sessionId: uuidSchema.optional(),
|
|
type: closingTypeEnum,
|
|
periodStart: z.coerce.date(),
|
|
periodEnd: z.coerce.date(),
|
|
openingBalance: moneySchema.default(0),
|
|
closingNotes: z.string().max(1000).optional(),
|
|
}).refine(data => data.periodStart <= data.periodEnd, {
|
|
message: 'Period start must be before or equal to period end',
|
|
path: ['periodEnd'],
|
|
});
|
|
|
|
// Denomination count schema
|
|
export const denominationCountSchema = z.object({
|
|
type: denominationTypeEnum,
|
|
denomination: z.number().positive(),
|
|
quantity: z.number().int().min(0),
|
|
});
|
|
|
|
// Submit cash count schema
|
|
export const submitCashCountSchema = z.object({
|
|
denominations: z.array(denominationCountSchema).min(1, 'At least one denomination is required'),
|
|
});
|
|
|
|
// Submit payment counts schema
|
|
export const submitPaymentCountsSchema = z.object({
|
|
cash: moneySchema.optional(),
|
|
card: moneySchema.default(0),
|
|
transfer: moneySchema.default(0),
|
|
other: moneySchema.default(0),
|
|
});
|
|
|
|
// Closing action schema (approve/reject)
|
|
export const closingActionSchema = z.object({
|
|
notes: z.string().max(1000).optional(),
|
|
});
|
|
|
|
// Reject closing schema (requires notes)
|
|
export const rejectClosingSchema = z.object({
|
|
notes: z.string().min(1, 'Rejection reason is required').max(1000),
|
|
});
|
|
|
|
// Reconcile closing schema
|
|
export const reconcileClosingSchema = z.object({
|
|
depositAmount: moneySchema.positive('Deposit amount must be positive'),
|
|
depositReference: z.string().min(1).max(100),
|
|
depositDate: z.coerce.date(),
|
|
});
|
|
|
|
// List closings query schema
|
|
export const listClosingsQuerySchema = paginationSchema.extend({
|
|
branchId: uuidSchema.optional(),
|
|
sessionId: uuidSchema.optional(),
|
|
status: closingStatusEnum.optional(),
|
|
type: closingTypeEnum.optional(),
|
|
startDate: z.coerce.date().optional(),
|
|
endDate: z.coerce.date().optional(),
|
|
});
|
|
|
|
// Types
|
|
export type CreateMovementInput = z.infer<typeof createMovementSchema>;
|
|
export type ListMovementsQuery = z.infer<typeof listMovementsQuerySchema>;
|
|
export type CreateClosingInput = z.infer<typeof createClosingSchema>;
|
|
export type SubmitCashCountInput = z.infer<typeof submitCashCountSchema>;
|
|
export type SubmitPaymentCountsInput = z.infer<typeof submitPaymentCountsSchema>;
|
|
export type ReconcileClosingInput = z.infer<typeof reconcileClosingSchema>;
|
|
export type ListClosingsQuery = z.infer<typeof listClosingsQuerySchema>;
|