chore: synchronize local fixes to gitea
This commit is contained in:
47
src/server/models/ApplicationRecord.ts
Normal file
47
src/server/models/ApplicationRecord.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IApplicationRecord extends Document {
|
||||
organizationId?: string;
|
||||
createdBy?: string;
|
||||
projectId: mongoose.Types.ObjectId;
|
||||
coatStage: string;
|
||||
pieceDescription?: string | null;
|
||||
date?: Date | null;
|
||||
operator?: string | null;
|
||||
realWeight?: number | null;
|
||||
volumeUsed?: number | null;
|
||||
areaPainted?: number | null;
|
||||
wetThicknessAvg?: number | null;
|
||||
dryThicknessCalc?: number | null;
|
||||
method?: string | null;
|
||||
diluentUsed?: number | null;
|
||||
notes?: string | null;
|
||||
items?: {
|
||||
partId: mongoose.Types.ObjectId;
|
||||
quantity: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
const ApplicationRecordSchema: Schema = new Schema({
|
||||
organizationId: { type: String, index: true },
|
||||
createdBy: { type: String, index: true },
|
||||
projectId: { type: Schema.Types.ObjectId, ref: 'Project', required: true },
|
||||
coatStage: { type: String, required: true },
|
||||
pieceDescription: { type: String }, // Can be auto-generated or manual name for the Batch
|
||||
date: { type: Date },
|
||||
operator: { type: String },
|
||||
realWeight: { type: Number },
|
||||
volumeUsed: { type: Number },
|
||||
areaPainted: { type: Number },
|
||||
wetThicknessAvg: { type: Number },
|
||||
dryThicknessCalc: { type: Number },
|
||||
method: { type: String },
|
||||
diluentUsed: { type: Number },
|
||||
notes: { type: String },
|
||||
items: [{
|
||||
partId: { type: Schema.Types.ObjectId, ref: 'Part' },
|
||||
quantity: { type: Number, required: true }
|
||||
}]
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.ApplicationRecord || mongoose.model<IApplicationRecord>('ApplicationRecord', ApplicationRecordSchema);
|
||||
22
src/server/models/GeometryType.ts
Normal file
22
src/server/models/GeometryType.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import mongoose, { Document, Schema } from 'mongoose';
|
||||
|
||||
export interface IGeometryType extends Document {
|
||||
name: string;
|
||||
efficiencyLoss: number; // Percentage, e.g., 10 for 10%
|
||||
organizationId: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const GeometryTypeSchema: Schema = new Schema({
|
||||
name: { type: String, required: true },
|
||||
efficiencyLoss: { type: Number, required: true, default: 0 },
|
||||
organizationId: { type: String, required: true, index: true },
|
||||
}, {
|
||||
timestamps: true
|
||||
});
|
||||
|
||||
// Compound index to ensure unique names per organization
|
||||
GeometryTypeSchema.index({ organizationId: 1, name: 1 }, { unique: true });
|
||||
|
||||
export default mongoose.model<IGeometryType>('GeometryType', GeometryTypeSchema);
|
||||
73
src/server/models/Inspection.ts
Normal file
73
src/server/models/Inspection.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IInspection extends Document {
|
||||
organizationId?: string;
|
||||
createdBy?: string; // Clerk User ID
|
||||
projectId: mongoose.Types.ObjectId;
|
||||
type: 'painting' | 'surface_treatment';
|
||||
|
||||
// Common
|
||||
date?: Date | null;
|
||||
inspector?: string | null;
|
||||
appearance?: 'approved' | 'rejected' | 'notes' | null; // Unified status
|
||||
defects?: string | null; // Observations
|
||||
photos?: string[]; // URLs
|
||||
partTemperature?: number | null;
|
||||
weightKg?: number | null;
|
||||
|
||||
// Painting Specific
|
||||
pieceDescription?: string | null;
|
||||
epsPoints?: (number | null)[];
|
||||
adhesionTest?: string | null;
|
||||
|
||||
// Surface Treatment Specific
|
||||
batch?: string | null; // Lote
|
||||
treatmentExecutor?: string | null;
|
||||
treatmentType?: string | null; // Jateamento, Mecânica...
|
||||
cleaningDegree?: string | null; // Sa 2.5, St 3...
|
||||
roughnessReadings?: (number | null)[]; // 5 measurements
|
||||
flashRust?: string | null;
|
||||
temperature?: number | null;
|
||||
relativeHumidity?: number | null;
|
||||
period?: 'morning' | 'afternoon' | 'night' | null;
|
||||
applicationRecordId?: mongoose.Types.ObjectId; // Link to specific painting batch
|
||||
stockItemId?: mongoose.Types.ObjectId; // Link to Stock Item (Paint used)
|
||||
instrumentId?: mongoose.Types.ObjectId; // Link to Instrument used
|
||||
}
|
||||
|
||||
const InspectionSchema: Schema = new Schema({
|
||||
organizationId: { type: String, index: true },
|
||||
createdBy: { type: String, index: true },
|
||||
projectId: { type: Schema.Types.ObjectId, ref: 'Project', required: true },
|
||||
applicationRecordId: { type: Schema.Types.ObjectId, ref: 'ApplicationRecord' },
|
||||
stockItemId: { type: Schema.Types.ObjectId, ref: 'StockItem' },
|
||||
instrumentId: { type: Schema.Types.ObjectId, ref: 'Instrument' },
|
||||
type: { type: String, enum: ['painting', 'surface_treatment'], default: 'painting', index: true },
|
||||
|
||||
// Common
|
||||
date: { type: Date },
|
||||
inspector: { type: String },
|
||||
appearance: { type: String }, // approved, rejected, notes
|
||||
defects: { type: String },
|
||||
photos: [{ type: String }],
|
||||
partTemperature: { type: Number },
|
||||
weightKg: { type: Number },
|
||||
|
||||
// Painting
|
||||
pieceDescription: { type: String },
|
||||
epsPoints: [{ type: Number }],
|
||||
adhesionTest: { type: String },
|
||||
|
||||
// Surface Treatment
|
||||
batch: { type: String },
|
||||
treatmentExecutor: { type: String },
|
||||
treatmentType: { type: String },
|
||||
cleaningDegree: { type: String },
|
||||
roughnessReadings: [{ type: Number }],
|
||||
flashRust: { type: String },
|
||||
temperature: { type: Number },
|
||||
relativeHumidity: { type: Number },
|
||||
period: { type: String },
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.Inspection || mongoose.model<IInspection>('Inspection', InspectionSchema);
|
||||
40
src/server/models/Instrument.ts
Normal file
40
src/server/models/Instrument.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IInstrument extends Document {
|
||||
organizationId: string;
|
||||
name: string;
|
||||
type: string; // Ex: Medidor de Camada, Termo-higrômetro
|
||||
manufacturer?: string;
|
||||
modelName?: string;
|
||||
serialNumber: string;
|
||||
calibrationDate?: Date;
|
||||
calibrationExpirationDate?: Date;
|
||||
certificateUrl?: string; // URL do PDF
|
||||
status: 'active' | 'inactive' | 'maintenance' | 'expired';
|
||||
notes?: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const InstrumentSchema: Schema = new Schema({
|
||||
organizationId: { type: String, required: true, index: true },
|
||||
name: { type: String, required: true },
|
||||
type: { type: String, required: true },
|
||||
manufacturer: { type: String },
|
||||
modelName: { type: String },
|
||||
serialNumber: { type: String, required: true },
|
||||
calibrationDate: { type: Date },
|
||||
calibrationExpirationDate: { type: Date },
|
||||
certificateUrl: { type: String },
|
||||
status: {
|
||||
type: String,
|
||||
enum: ['active', 'inactive', 'maintenance', 'expired'],
|
||||
default: 'active'
|
||||
},
|
||||
notes: { type: String }
|
||||
}, { timestamps: true });
|
||||
|
||||
// Index para evitar duplicidade de número de série dentro da mesma organização
|
||||
InstrumentSchema.index({ organizationId: 1, serialNumber: 1 }, { unique: true });
|
||||
|
||||
export default mongoose.models.Instrument || mongoose.model<IInstrument>('Instrument', InstrumentSchema);
|
||||
63
src/server/models/Message.ts
Normal file
63
src/server/models/Message.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IMessage extends Document {
|
||||
organizationId: string;
|
||||
fromUserId: string; // clerkId do remetente
|
||||
toUserId: string; // clerkId do destinatário
|
||||
message: string;
|
||||
isRead: boolean;
|
||||
readAt?: Date;
|
||||
isArchived: boolean;
|
||||
isDeletedByRecipient: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const MessageSchema: Schema = new Schema(
|
||||
{
|
||||
organizationId: {
|
||||
type: String,
|
||||
required: true,
|
||||
index: true,
|
||||
},
|
||||
fromUserId: {
|
||||
type: String,
|
||||
required: true,
|
||||
index: true,
|
||||
},
|
||||
toUserId: {
|
||||
type: String,
|
||||
required: true,
|
||||
index: true,
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
required: true,
|
||||
maxlength: 255,
|
||||
},
|
||||
isRead: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
readAt: {
|
||||
type: Date,
|
||||
},
|
||||
isArchived: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isDeletedByRecipient: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Compound index for efficient queries
|
||||
MessageSchema.index({ toUserId: 1, isRead: 1 });
|
||||
MessageSchema.index({ fromUserId: 1, toUserId: 1 });
|
||||
|
||||
export default mongoose.model<IMessage>('Message', MessageSchema);
|
||||
32
src/server/models/Notification.ts
Normal file
32
src/server/models/Notification.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export type NotificationType = 'info' | 'warning' | 'error' | 'success';
|
||||
|
||||
export interface INotification extends Document {
|
||||
organizationId: string;
|
||||
recipientId?: string; // Se null, é para todos da organização
|
||||
title: string;
|
||||
message: string;
|
||||
type: NotificationType;
|
||||
isRead: boolean;
|
||||
isArchived: boolean;
|
||||
archivedBy: string[]; // IDs dos usuários que arquivaram (para notificações globais)
|
||||
deletedBy: string[]; // IDs dos usuários que deletaram (para notificações globais)
|
||||
metadata?: any; // Para guardar IDs de projetos, itens, etc.
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
const NotificationSchema: Schema = new Schema({
|
||||
organizationId: { type: String, required: true, index: true },
|
||||
recipientId: { type: String, index: true }, // Opcional
|
||||
title: { type: String, required: true },
|
||||
message: { type: String, required: true },
|
||||
type: { type: String, enum: ['info', 'warning', 'error', 'success'], default: 'info' },
|
||||
isRead: { type: Boolean, default: false },
|
||||
isArchived: { type: Boolean, default: false },
|
||||
archivedBy: [{ type: String }],
|
||||
deletedBy: [{ type: String }],
|
||||
metadata: { type: Schema.Types.Mixed },
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.Notification || mongoose.model<INotification>('Notification', NotificationSchema);
|
||||
17
src/server/models/Organization.ts
Normal file
17
src/server/models/Organization.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IOrganization extends Document {
|
||||
clerkId: string;
|
||||
name?: string;
|
||||
isBanned: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const OrganizationSchema: Schema = new Schema({
|
||||
clerkId: { type: String, required: true, unique: true, index: true },
|
||||
name: { type: String },
|
||||
isBanned: { type: Boolean, default: false },
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.Organization || mongoose.model<IOrganization>('Organization', OrganizationSchema);
|
||||
52
src/server/models/OrganizationMember.ts
Normal file
52
src/server/models/OrganizationMember.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export type OrgRole = 'guest' | 'user' | 'admin';
|
||||
|
||||
export interface IOrganizationMember extends Document {
|
||||
clerkUserId: string;
|
||||
organizationId: string;
|
||||
role: OrgRole;
|
||||
isBanned: boolean;
|
||||
// Denormalized user info for quick access
|
||||
email: string;
|
||||
name: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const OrganizationMemberSchema: Schema = new Schema({
|
||||
clerkUserId: {
|
||||
type: String,
|
||||
required: true,
|
||||
index: true
|
||||
},
|
||||
organizationId: {
|
||||
type: String,
|
||||
required: true,
|
||||
index: true
|
||||
},
|
||||
role: {
|
||||
type: String,
|
||||
enum: ['guest', 'user', 'admin'],
|
||||
default: 'guest'
|
||||
},
|
||||
isBanned: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}, {
|
||||
timestamps: true
|
||||
});
|
||||
|
||||
// Compound index for unique user per organization
|
||||
OrganizationMemberSchema.index({ clerkUserId: 1, organizationId: 1 }, { unique: true });
|
||||
|
||||
export default mongoose.models.OrganizationMember || mongoose.model<IOrganizationMember>('OrganizationMember', OrganizationMemberSchema);
|
||||
54
src/server/models/PaintingScheme.ts
Normal file
54
src/server/models/PaintingScheme.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IPaintingScheme extends Document {
|
||||
projectId: mongoose.Types.ObjectId;
|
||||
name: string;
|
||||
type?: string | null;
|
||||
coat?: string | null;
|
||||
solidsVolume?: number | null;
|
||||
yieldTheoretical?: number | null;
|
||||
epsMin?: number | null;
|
||||
epsMax?: number | null;
|
||||
dilution?: number | null;
|
||||
manufacturer?: string | null;
|
||||
color?: string | null;
|
||||
notes?: string | null;
|
||||
organizationId?: string;
|
||||
// Consumption Planning
|
||||
paintConsumption?: number | null;
|
||||
thinnerConsumption?: number | null;
|
||||
paintId?: mongoose.Types.ObjectId | null; // Ref to TechnicalDataSheet
|
||||
thinnerId?: mongoose.Types.ObjectId | null; // Ref to TechnicalDataSheet
|
||||
preferredStockItemId?: mongoose.Types.ObjectId | null; // Ref to StockItem (Suggested Batch)
|
||||
}
|
||||
|
||||
const PaintingSchemeSchema: Schema = new Schema({
|
||||
organizationId: { type: String, index: true },
|
||||
projectId: { type: Schema.Types.ObjectId, ref: 'Project', required: true },
|
||||
name: { type: String, required: true },
|
||||
type: { type: String },
|
||||
coat: { type: String },
|
||||
solidsVolume: { type: Number },
|
||||
yieldTheoretical: { type: Number },
|
||||
epsMin: { type: Number },
|
||||
epsMax: { type: Number },
|
||||
dilution: { type: Number },
|
||||
manufacturer: { type: String },
|
||||
color: { type: String },
|
||||
notes: { type: String },
|
||||
// Consumption Planning
|
||||
paintConsumption: { type: Number },
|
||||
thinnerConsumption: { type: Number },
|
||||
paintId: { type: Schema.Types.ObjectId, ref: 'TechnicalDataSheet' },
|
||||
thinnerId: { type: Schema.Types.ObjectId, ref: 'TechnicalDataSheet' },
|
||||
preferredStockItemId: { type: Schema.Types.ObjectId, ref: 'StockItem' }
|
||||
}, { strict: false });
|
||||
|
||||
console.log("✅✅✅ PAINTING SCHEME MODEL (WITH CONSUMPTION) LOADED ✅✅✅");
|
||||
|
||||
// Force model recompilation to ensure schema updates are applied
|
||||
if (mongoose.models.PaintingScheme) {
|
||||
delete mongoose.models.PaintingScheme;
|
||||
}
|
||||
|
||||
export default mongoose.model<IPaintingScheme>('PaintingScheme', PaintingSchemeSchema);
|
||||
29
src/server/models/Part.ts
Normal file
29
src/server/models/Part.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IPart extends Document {
|
||||
projectId?: mongoose.Types.ObjectId;
|
||||
description: string;
|
||||
dimensions?: string | null;
|
||||
weight?: number | null;
|
||||
type?: string | null;
|
||||
area?: number | null;
|
||||
complexity?: number | null;
|
||||
quantity: number;
|
||||
notes?: string | null;
|
||||
organizationId?: string;
|
||||
}
|
||||
|
||||
const PartSchema: Schema = new Schema({
|
||||
organizationId: { type: String, index: true },
|
||||
projectId: { type: Schema.Types.ObjectId, ref: 'Project', required: false },
|
||||
description: { type: String, required: true },
|
||||
dimensions: { type: String },
|
||||
weight: { type: Number },
|
||||
type: { type: String },
|
||||
area: { type: Number },
|
||||
complexity: { type: Number },
|
||||
quantity: { type: Number, required: true, default: 1 },
|
||||
notes: { type: String },
|
||||
});
|
||||
|
||||
export default mongoose.models.Part || mongoose.model<IPart>('Part', PartSchema);
|
||||
29
src/server/models/Project.ts
Normal file
29
src/server/models/Project.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IProject extends Document {
|
||||
name: string;
|
||||
client: string;
|
||||
startDate?: Date | null;
|
||||
endDate?: Date | null;
|
||||
technician?: string | null;
|
||||
environment?: string | null;
|
||||
organizationId?: string;
|
||||
weightKg?: number | null;
|
||||
status: 'active' | 'archived';
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const ProjectSchema: Schema = new Schema({
|
||||
name: { type: String, required: true },
|
||||
client: { type: String, required: true },
|
||||
organizationId: { type: String, index: true },
|
||||
startDate: { type: Date },
|
||||
endDate: { type: Date },
|
||||
technician: { type: String },
|
||||
environment: { type: String },
|
||||
weightKg: { type: Number },
|
||||
status: { type: String, enum: ['active', 'archived'], default: 'active', index: true },
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.Project || mongoose.model<IProject>('Project', ProjectSchema);
|
||||
31
src/server/models/StockAuditLog.ts
Normal file
31
src/server/models/StockAuditLog.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IStockAuditLog extends Document {
|
||||
organizationId?: string;
|
||||
stockItemId: mongoose.Types.ObjectId;
|
||||
movementId?: mongoose.Types.ObjectId; // Optional, might be deleted
|
||||
movementNumber?: number;
|
||||
userId: string;
|
||||
userName: string;
|
||||
action: 'CREATE' | 'UPDATE' | 'DELETE';
|
||||
details: string; // Human readable summary
|
||||
oldValues?: Record<string, any>;
|
||||
newValues?: Record<string, any>;
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
const StockAuditLogSchema: Schema = new Schema({
|
||||
organizationId: { type: String, index: true },
|
||||
stockItemId: { type: Schema.Types.ObjectId, ref: 'StockItem', required: true },
|
||||
movementId: { type: Schema.Types.ObjectId, ref: 'StockMovement' },
|
||||
movementNumber: { type: Number },
|
||||
userId: { type: String, required: true },
|
||||
userName: { type: String, required: true },
|
||||
action: { type: String, required: true, enum: ['CREATE', 'UPDATE', 'DELETE'] },
|
||||
details: { type: String, required: true },
|
||||
oldValues: { type: Object },
|
||||
newValues: { type: Object },
|
||||
timestamp: { type: Date, default: Date.now }
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.StockAuditLog || mongoose.model<IStockAuditLog>('StockAuditLog', StockAuditLogSchema);
|
||||
43
src/server/models/StockItem.ts
Normal file
43
src/server/models/StockItem.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IStockItem extends Document {
|
||||
organizationId?: string;
|
||||
createdBy?: string;
|
||||
dataSheetId: mongoose.Types.ObjectId;
|
||||
rrNumber: string; // Registro de Rastreabilidade
|
||||
batchNumber: string; // Lote
|
||||
color?: string;
|
||||
invoiceNumber?: string; // Nota Fiscal
|
||||
receivedBy?: string; // Quem recebeu
|
||||
quantity: number;
|
||||
unit: string;
|
||||
minStock?: number; // Estoque mínimo estipulado
|
||||
expirationDate?: Date;
|
||||
entryDate: Date;
|
||||
notes?: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const StockItemSchema: Schema = new Schema({
|
||||
organizationId: { type: String, index: true },
|
||||
createdBy: { type: String, index: true },
|
||||
dataSheetId: { type: Schema.Types.ObjectId, ref: 'TechnicalDataSheet', required: true },
|
||||
rrNumber: { type: String, required: true },
|
||||
batchNumber: { type: String, required: true },
|
||||
color: { type: String },
|
||||
invoiceNumber: { type: String },
|
||||
receivedBy: { type: String },
|
||||
quantity: { type: Number, required: true, default: 0 },
|
||||
unit: { type: String, required: true },
|
||||
minStock: { type: Number, default: 0 },
|
||||
expirationDate: { type: Date },
|
||||
entryDate: { type: Date, default: Date.now },
|
||||
notes: { type: String }
|
||||
}, { timestamps: true });
|
||||
|
||||
// Compound index to prevent duplicate RR within an organization, if desirable.
|
||||
// For now, indexing RR for fast lookup.
|
||||
StockItemSchema.index({ organizationId: 1, rrNumber: 1 });
|
||||
|
||||
export default mongoose.models.StockItem || mongoose.model<IStockItem>('StockItem', StockItemSchema);
|
||||
34
src/server/models/StockMovement.ts
Normal file
34
src/server/models/StockMovement.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export type MovementType = 'ENTRY' | 'ADJUSTMENT' | 'CONSUMPTION';
|
||||
|
||||
export interface IStockMovement extends Document {
|
||||
organizationId?: string;
|
||||
createdBy?: string;
|
||||
stockItemId: mongoose.Types.ObjectId;
|
||||
movementNumber?: number;
|
||||
type: MovementType;
|
||||
quantity: number; // Positive for entry, negative for exit
|
||||
date: Date;
|
||||
responsible: string; // User who performed the action
|
||||
reason?: string; // For ADJUSTMENT
|
||||
requester?: string; // For CONSUMPTION
|
||||
notes?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
const StockMovementSchema: Schema = new Schema({
|
||||
organizationId: { type: String, index: true },
|
||||
createdBy: { type: String, index: true },
|
||||
stockItemId: { type: Schema.Types.ObjectId, ref: 'StockItem', required: true },
|
||||
movementNumber: { type: Number },
|
||||
type: { type: String, enum: ['ENTRY', 'ADJUSTMENT', 'CONSUMPTION'], required: true },
|
||||
quantity: { type: Number, required: true },
|
||||
date: { type: Date, default: Date.now },
|
||||
responsible: { type: String, required: true },
|
||||
reason: { type: String },
|
||||
requester: { type: String },
|
||||
notes: { type: String }
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.StockMovement || mongoose.model<IStockMovement>('StockMovement', StockMovementSchema);
|
||||
19
src/server/models/StoredFile.ts
Normal file
19
src/server/models/StoredFile.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IStoredFile extends Document {
|
||||
filename: string;
|
||||
contentType: string;
|
||||
data: Buffer;
|
||||
size: number;
|
||||
uploadDate: Date;
|
||||
}
|
||||
|
||||
const StoredFileSchema: Schema = new Schema({
|
||||
filename: { type: String, required: true },
|
||||
contentType: { type: String, required: true },
|
||||
data: { type: Buffer, required: true },
|
||||
size: { type: Number, required: true },
|
||||
uploadDate: { type: Date, default: Date.now }
|
||||
});
|
||||
|
||||
export default mongoose.models.StoredFile || mongoose.model<IStoredFile>('StoredFile', StoredFileSchema);
|
||||
19
src/server/models/SystemSettings.ts
Normal file
19
src/server/models/SystemSettings.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface ISystemSettings extends Document {
|
||||
settingsId: string;
|
||||
appName: string;
|
||||
appSubtitle: string;
|
||||
appLogoUrl?: string;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
const SystemSettingsSchema: Schema = new Schema({
|
||||
settingsId: { type: String, required: true, unique: true, default: 'global' },
|
||||
appName: { type: String, required: true, default: 'GPI' },
|
||||
appSubtitle: { type: String, required: true, default: 'Gestão de Pintura Industrial' },
|
||||
appLogoUrl: { type: String },
|
||||
updatedBy: { type: String } // Email of the dev who updated it
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.SystemSettings || mongoose.model<ISystemSettings>('SystemSettings', SystemSettingsSchema);
|
||||
59
src/server/models/TechnicalDataSheet.ts
Normal file
59
src/server/models/TechnicalDataSheet.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface ITechnicalDataSheet extends Document {
|
||||
name: string;
|
||||
manufacturer?: string;
|
||||
type?: string;
|
||||
fileId?: mongoose.Types.ObjectId;
|
||||
fileUrl: string;
|
||||
uploadDate: Date;
|
||||
solidsVolume?: number;
|
||||
density?: number;
|
||||
mixingRatio?: string;
|
||||
mixingRatioWeight?: string;
|
||||
mixingRatioVolume?: string;
|
||||
wftMin?: number;
|
||||
wftMax?: number;
|
||||
dftMin?: number;
|
||||
dftMax?: number;
|
||||
reducer?: string;
|
||||
yieldTheoretical?: number;
|
||||
dftReference?: number;
|
||||
yieldFactor?: number;
|
||||
dilution?: number;
|
||||
notes?: string;
|
||||
organizationId?: string;
|
||||
manufacturerCode?: string;
|
||||
minStock?: number;
|
||||
typicalApplication?: string;
|
||||
}
|
||||
|
||||
const TechnicalDataSheetSchema: Schema = new Schema({
|
||||
organizationId: { type: String, index: true },
|
||||
name: { type: String, required: true },
|
||||
manufacturer: { type: String },
|
||||
manufacturerCode: { type: String },
|
||||
type: { type: String },
|
||||
minStock: { type: Number },
|
||||
typicalApplication: { type: String },
|
||||
fileId: { type: Schema.Types.ObjectId, ref: 'StoredFile' },
|
||||
fileUrl: { type: String },
|
||||
uploadDate: { type: Date, default: Date.now },
|
||||
solidsVolume: { type: Number },
|
||||
density: { type: Number },
|
||||
mixingRatio: { type: String },
|
||||
mixingRatioWeight: { type: String },
|
||||
mixingRatioVolume: { type: String },
|
||||
wftMin: { type: Number },
|
||||
wftMax: { type: Number },
|
||||
dftMin: { type: Number },
|
||||
dftMax: { type: Number },
|
||||
reducer: { type: String },
|
||||
yieldTheoretical: { type: Number },
|
||||
dftReference: { type: Number },
|
||||
yieldFactor: { type: Number },
|
||||
dilution: { type: Number },
|
||||
notes: { type: String },
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.TechnicalDataSheet || mongoose.model<ITechnicalDataSheet>('TechnicalDataSheet', TechnicalDataSheetSchema);
|
||||
53
src/server/models/User.ts
Normal file
53
src/server/models/User.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export type UserRole = 'guest' | 'user' | 'admin';
|
||||
|
||||
export interface IUser extends Document {
|
||||
clerkId: string;
|
||||
email: string;
|
||||
name: string;
|
||||
role: UserRole;
|
||||
isBanned: boolean;
|
||||
organizationId?: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
lastSeenAt?: Date;
|
||||
}
|
||||
|
||||
const UserSchema: Schema = new Schema({
|
||||
clerkId: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
index: true
|
||||
},
|
||||
organizationId: {
|
||||
type: String,
|
||||
index: true
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
role: {
|
||||
type: String,
|
||||
enum: ['guest', 'user', 'admin'],
|
||||
default: 'guest'
|
||||
},
|
||||
isBanned: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
lastSeenAt: {
|
||||
type: Date,
|
||||
default: Date.now
|
||||
}
|
||||
}, {
|
||||
timestamps: true
|
||||
});
|
||||
|
||||
export default mongoose.models.User || mongoose.model<IUser>('User', UserSchema);
|
||||
53
src/server/models/YieldStudy.ts
Normal file
53
src/server/models/YieldStudy.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import mongoose, { Schema, Document } from 'mongoose';
|
||||
|
||||
export interface IPieceCategory {
|
||||
id: string; // Keep as string for internal mapping if needed, or convert to Sub-document
|
||||
name: string;
|
||||
organizationId?: string;
|
||||
weight: number;
|
||||
area?: number; // Área em m² para cálculo alternativo
|
||||
historicalYield: number;
|
||||
historicalDft: number;
|
||||
efficiency: number;
|
||||
}
|
||||
|
||||
const PieceCategorySchema: Schema = new Schema({
|
||||
name: { type: String, required: true },
|
||||
weight: { type: Number, required: true },
|
||||
area: { type: Number }, // Área em m² (opcional)
|
||||
historicalYield: { type: Number, required: true },
|
||||
historicalDft: { type: Number, required: true },
|
||||
efficiency: { type: Number, required: true },
|
||||
});
|
||||
|
||||
export interface IYieldStudy extends Document {
|
||||
name: string;
|
||||
organizationId?: string;
|
||||
dataSheetId: mongoose.Types.ObjectId;
|
||||
targetDft: number;
|
||||
dilutionPercent: number;
|
||||
categories: IPieceCategory[];
|
||||
totalWeight: number;
|
||||
estimatedPaintVolume: number;
|
||||
estimatedReducerVolume: number;
|
||||
estimatedPaintVolumeByArea?: number; // Cálculo por área (m²)
|
||||
estimatedReducerVolumeByArea?: number; // Cálculo por área (m²)
|
||||
averageComplexity: number;
|
||||
}
|
||||
|
||||
const YieldStudySchema: Schema = new Schema({
|
||||
name: { type: String, required: true },
|
||||
organizationId: { type: String, index: true },
|
||||
dataSheetId: { type: Schema.Types.ObjectId, ref: 'TechnicalDataSheet', required: true },
|
||||
targetDft: { type: Number, required: true },
|
||||
dilutionPercent: { type: Number, default: 0 },
|
||||
categories: [PieceCategorySchema],
|
||||
totalWeight: { type: Number },
|
||||
estimatedPaintVolume: { type: Number },
|
||||
estimatedReducerVolume: { type: Number },
|
||||
estimatedPaintVolumeByArea: { type: Number }, // Cálculo por área
|
||||
estimatedReducerVolumeByArea: { type: Number }, // Cálculo por área
|
||||
averageComplexity: { type: Number },
|
||||
}, { timestamps: true });
|
||||
|
||||
export default mongoose.models.YieldStudy || mongoose.model<IYieldStudy>('YieldStudy', YieldStudySchema);
|
||||
Reference in New Issue
Block a user