All files / src/domains/mdm/infrastructure/schemas unit-of-measure.schema.ts

0% Statements 0/57
0% Branches 0/10
100% Functions 0/0
0% Lines 0/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102                                                                                                                                                                                                           
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document, Schema as MongooseSchema } from 'mongoose';
 
// ════════════════════════════════════════════════════════════════
// UNIT CATEGORY  (Length, Mass, Volume, Area, Time, etc.)
// ════════════════════════════════════════════════════════════════
 
@Schema({ collection: 'mdm_unit_categories', timestamps: true })
export class UnitCategory extends Document {
  @Prop({ required: true, unique: true }) categoryCode!: string; // LENGTH, MASS, VOLUME, TIME, CURRENCY, COUNT
  @Prop({ required: true }) categoryName!: string;
  @Prop() description?: string;
  @Prop({ default: false }) systemManaged!: boolean;
  @Prop({ default: true }) active!: boolean;
}
export const UnitCategorySchema = SchemaFactory.createForClass(UnitCategory);
UnitCategorySchema.index({ categoryCode: 1 }, { unique: true });
 
// ════════════════════════════════════════════════════════════════
// UNIT OF MEASURE
// ════════════════════════════════════════════════════════════════
 
@Schema({ collection: 'mdm_units_of_measure', timestamps: true })
export class UnitOfMeasure extends Document {
  @Prop({ required: true }) unitCode!: string; // KG, LB, M, FT, PCS, HR, DAY, BOX
  @Prop({ required: true }) unitName!: string; // Kilogram
  @Prop() unitSymbol?: string; // kg
  @Prop() pluralName?: string; // Kilograms
  @Prop({ required: true }) categoryCode!: string; // MASS
  @Prop({ default: false }) isBaseUnit!: boolean; // SI base unit for its category
  @Prop() baseUnitCode?: string; // if not base: what is the base
  // Conversion to base unit: value = inputValue * conversionFactor + offset
  @Prop() conversionFactor?: string; // e.g. "0.001" (g → kg)
  @Prop({ default: '0' }) conversionOffset!: string; // for °C ↔ °F
  @Prop({
    enum: ['metric', 'imperial', 'us_customary', 'custom'],
    default: 'metric',
  })
  system!: string;
  @Prop({ type: [String], default: [] }) countryCodes!: string[]; // preferred in these countries
  @Prop({ type: MongooseSchema.Types.ObjectId })
  tenantId?: MongooseSchema.Types.ObjectId; // null = global
  @Prop({ default: false }) systemManaged!: boolean;
  @Prop({ default: true }) active!: boolean;
}
export const UnitOfMeasureSchema = SchemaFactory.createForClass(UnitOfMeasure);
UnitOfMeasureSchema.index(
  { unitCode: 1, tenantId: 1 },
  { unique: true, sparse: true },
);
UnitOfMeasureSchema.index({ categoryCode: 1, active: 1 });
UnitOfMeasureSchema.index({ isBaseUnit: 1, categoryCode: 1 });
 
// ════════════════════════════════════════════════════════════════
// UNIT CONVERSION TABLE (pre-computed conversions)
// ════════════════════════════════════════════════════════════════
 
@Schema({ collection: 'mdm_unit_conversions', timestamps: true })
export class UnitConversion extends Document {
  @Prop({ required: true }) fromUnitCode!: string;
  @Prop({ required: true }) toUnitCode!: string;
  @Prop({ required: true }) categoryCode!: string;
  // conversion: toValue = fromValue * multiplier + offset
  @Prop({ required: true }) multiplier!: string;
  @Prop({ default: '0' }) offset!: string;
  @Prop({ default: 6 }) precision!: number; // decimal places to round to
  @Prop({ default: false }) isExact!: boolean; // mathematically exact or approximate
  @Prop({ default: true }) active!: boolean;
}
export const UnitConversionSchema =
  SchemaFactory.createForClass(UnitConversion);
UnitConversionSchema.index(
  { fromUnitCode: 1, toUnitCode: 1 },
  { unique: true },
);
UnitConversionSchema.index({ categoryCode: 1 });
 
// ════════════════════════════════════════════════════════════════
// UNIT ROUNDING RULE
// ════════════════════════════════════════════════════════════════
 
@Schema({ collection: 'mdm_unit_rounding_rules', timestamps: true })
export class UnitRoundingRule extends Document {
  @Prop({ required: true }) unitCode!: string;
  @Prop({ required: true, default: 2 }) decimalPlaces!: number;
  @Prop({
    required: true,
    enum: ['half_up', 'half_down', 'half_even', 'ceiling', 'floor'],
    default: 'half_up',
  })
  roundingMode!: string;
  @Prop() incrementStep?: string; // e.g. 0.5 for half-unit rounding
  @Prop({ type: MongooseSchema.Types.ObjectId })
  tenantId?: MongooseSchema.Types.ObjectId;
}
export const UnitRoundingRuleSchema =
  SchemaFactory.createForClass(UnitRoundingRule);
UnitRoundingRuleSchema.index(
  { unitCode: 1, tenantId: 1 },
  { unique: true, sparse: true },
);