170 lines
4.5 KiB
TypeScript
170 lines
4.5 KiB
TypeScript
import {
|
|
Entity,
|
|
PrimaryGeneratedColumn,
|
|
Column,
|
|
CreateDateColumn,
|
|
UpdateDateColumn,
|
|
OneToMany,
|
|
Index,
|
|
} from 'typeorm';
|
|
import { StockAdjustmentLine } from './stock-adjustment-line.entity';
|
|
|
|
export enum AdjustmentStatus {
|
|
DRAFT = 'draft',
|
|
PENDING_APPROVAL = 'pending_approval',
|
|
APPROVED = 'approved',
|
|
POSTED = 'posted',
|
|
REJECTED = 'rejected',
|
|
CANCELLED = 'cancelled',
|
|
}
|
|
|
|
export enum AdjustmentType {
|
|
INVENTORY_COUNT = 'inventory_count',
|
|
DAMAGE = 'damage',
|
|
THEFT = 'theft',
|
|
EXPIRY = 'expiry',
|
|
CORRECTION = 'correction',
|
|
INITIAL_STOCK = 'initial_stock',
|
|
PRODUCTION = 'production',
|
|
OTHER = 'other',
|
|
}
|
|
|
|
@Entity('stock_adjustments', { schema: 'retail' })
|
|
@Index(['tenantId', 'branchId', 'status'])
|
|
@Index(['tenantId', 'adjustmentDate'])
|
|
@Index(['tenantId', 'number'], { unique: true })
|
|
export class StockAdjustment {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id: string;
|
|
|
|
@Column({ name: 'tenant_id', type: 'uuid' })
|
|
@Index()
|
|
tenantId: string;
|
|
|
|
@Column({ name: 'branch_id', type: 'uuid' })
|
|
branchId: string;
|
|
|
|
@Column({ name: 'warehouse_id', type: 'uuid' })
|
|
warehouseId: string;
|
|
|
|
@Column({ name: 'location_id', type: 'uuid', nullable: true })
|
|
locationId: string;
|
|
|
|
@Column({ length: 30, unique: true })
|
|
number: string;
|
|
|
|
@Column({
|
|
type: 'enum',
|
|
enum: AdjustmentType,
|
|
default: AdjustmentType.INVENTORY_COUNT,
|
|
})
|
|
type: AdjustmentType;
|
|
|
|
@Column({
|
|
type: 'enum',
|
|
enum: AdjustmentStatus,
|
|
default: AdjustmentStatus.DRAFT,
|
|
})
|
|
status: AdjustmentStatus;
|
|
|
|
@Column({ name: 'adjustment_date', type: 'date' })
|
|
adjustmentDate: Date;
|
|
|
|
// Count info (for inventory counts)
|
|
@Column({ name: 'is_full_count', type: 'boolean', default: false })
|
|
isFullCount: boolean;
|
|
|
|
@Column({ name: 'count_category_id', type: 'uuid', nullable: true })
|
|
countCategoryId: string;
|
|
|
|
// Summary
|
|
@Column({ name: 'lines_count', type: 'int', default: 0 })
|
|
linesCount: number;
|
|
|
|
@Column({ name: 'total_increase_qty', type: 'decimal', precision: 15, scale: 4, default: 0 })
|
|
totalIncreaseQty: number;
|
|
|
|
@Column({ name: 'total_decrease_qty', type: 'decimal', precision: 15, scale: 4, default: 0 })
|
|
totalDecreaseQty: number;
|
|
|
|
@Column({ name: 'total_increase_value', type: 'decimal', precision: 15, scale: 2, default: 0 })
|
|
totalIncreaseValue: number;
|
|
|
|
@Column({ name: 'total_decrease_value', type: 'decimal', precision: 15, scale: 2, default: 0 })
|
|
totalDecreaseValue: number;
|
|
|
|
@Column({ name: 'net_adjustment_value', type: 'decimal', precision: 15, scale: 2, default: 0 })
|
|
netAdjustmentValue: number;
|
|
|
|
// Financial account (for accounting integration)
|
|
@Column({ name: 'account_id', type: 'uuid', nullable: true })
|
|
accountId: string;
|
|
|
|
@Column({ name: 'counterpart_account_id', type: 'uuid', nullable: true })
|
|
counterpartAccountId: string;
|
|
|
|
// Approval workflow
|
|
@Column({ name: 'requires_approval', type: 'boolean', default: true })
|
|
requiresApproval: boolean;
|
|
|
|
@Column({ name: 'approval_threshold', type: 'decimal', precision: 15, scale: 2, nullable: true })
|
|
approvalThreshold: number;
|
|
|
|
// Users
|
|
@Column({ name: 'created_by', type: 'uuid' })
|
|
createdBy: string;
|
|
|
|
@Column({ name: 'approved_by', type: 'uuid', nullable: true })
|
|
approvedBy: string;
|
|
|
|
@Column({ name: 'approved_at', type: 'timestamp with time zone', nullable: true })
|
|
approvedAt: Date;
|
|
|
|
@Column({ name: 'posted_by', type: 'uuid', nullable: true })
|
|
postedBy: string;
|
|
|
|
@Column({ name: 'posted_at', type: 'timestamp with time zone', nullable: true })
|
|
postedAt: Date;
|
|
|
|
@Column({ name: 'rejected_by', type: 'uuid', nullable: true })
|
|
rejectedBy: string;
|
|
|
|
@Column({ name: 'rejected_at', type: 'timestamp with time zone', nullable: true })
|
|
rejectedAt: Date;
|
|
|
|
@Column({ name: 'rejection_reason', length: 255, nullable: true })
|
|
rejectionReason: string;
|
|
|
|
// Reason/Description
|
|
@Column({ type: 'text' })
|
|
reason: string;
|
|
|
|
// Reference
|
|
@Column({ name: 'reference_type', length: 50, nullable: true })
|
|
referenceType: string;
|
|
|
|
@Column({ name: 'reference_id', type: 'uuid', nullable: true })
|
|
referenceId: string;
|
|
|
|
@Column({ name: 'reference_number', length: 50, nullable: true })
|
|
referenceNumber: string;
|
|
|
|
// Notes
|
|
@Column({ type: 'text', nullable: true })
|
|
notes: string;
|
|
|
|
// Metadata
|
|
@Column({ type: 'jsonb', nullable: true })
|
|
metadata: Record<string, any>;
|
|
|
|
@CreateDateColumn({ name: 'created_at' })
|
|
createdAt: Date;
|
|
|
|
@UpdateDateColumn({ name: 'updated_at' })
|
|
updatedAt: Date;
|
|
|
|
// Relations
|
|
@OneToMany(() => StockAdjustmentLine, (line) => line.adjustment)
|
|
lines: StockAdjustmentLine[];
|
|
}
|