Added tax rates, tax records.

This commit is contained in:
Tom Butcher 2025-12-03 23:35:44 +00:00
parent 88952fbde2
commit bfd7d292d5
7 changed files with 161 additions and 31 deletions

View File

@ -6,7 +6,10 @@ const itemSchema = new Schema({
itemType: { type: String, required: true },
item: { type: Schema.Types.ObjectId, refPath: 'itemType', required: true },
quantity: { type: Number, required: true },
price: { type: Number, required: true },
itemCost: { type: Number, required: true },
totalCost: { type: Number, required: true },
totalCostWithTax: { type: Number, required: true },
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
});
const purchaseOrderSchema = new Schema(

View File

@ -14,6 +14,10 @@ const partSchema = new Schema(
margin: { type: Number, required: false },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
file: { type: mongoose.SchemaTypes.ObjectId, ref: 'file', required: false },
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
priceWithTax: { type: Number, required: false },
costWithTax: { type: Number, required: false },
},
{ timestamps: true }
);

View File

@ -19,6 +19,8 @@ const productSchema = new Schema(
amount: { type: Number, required: false },
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
parts: [partSchema],
priceTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: false },
},
{ timestamps: true }
);

View File

@ -0,0 +1,25 @@
import mongoose from 'mongoose';
import { generateId } from '../../utils.js';
const taxRateSchema = new mongoose.Schema(
{
_reference: { type: String, default: () => generateId()() },
name: { required: true, type: String },
rate: { required: true, type: Number },
rateType: { required: true, type: String, enum: ['percentage', 'fixed'] },
active: { required: true, type: Boolean, default: true },
description: { required: false, type: String },
country: { required: false, type: String },
effectiveFrom: { required: false, type: Date },
effectiveTo: { required: false, type: Date },
},
{ timestamps: true }
);
taxRateSchema.virtual('id').get(function () {
return this._id;
});
taxRateSchema.set('toJSON', { virtuals: true });
export const taxRateModel = mongoose.model('taxRate', taxRateSchema);

View File

@ -0,0 +1,28 @@
import mongoose from 'mongoose';
import { generateId } from '../../utils.js';
const { Schema } = mongoose;
const taxRecordSchema = new Schema(
{
_reference: { type: String, default: () => generateId()() },
taxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: true },
transactionType: {
type: String,
required: true,
enum: ['purchaseOrder', 'salesOrder', 'other'],
},
transaction: { type: Schema.Types.ObjectId, refPath: 'transactionType', required: true },
amount: { type: Number, required: true },
taxAmount: { type: Number, required: true },
transactionDate: { required: true, type: Date, default: Date.now },
},
{ timestamps: true }
);
taxRecordSchema.virtual('id').get(function () {
return this._id;
});
taxRecordSchema.set('toJSON', { virtuals: true });
export const taxRecordModel = mongoose.model('taxRecord', taxRecordSchema);

View File

@ -0,0 +1,94 @@
import { jobModel } from './production/job.schema.js';
import { subJobModel } from './production/subjob.schema.js';
import { printerModel } from './production/printer.schema.js';
import { filamentModel } from './management/filament.schema.js';
import { gcodeFileModel } from './production/gcodefile.schema.js';
import { partModel } from './management/part.schema.js';
import { productModel } from './management/product.schema.js';
import { vendorModel } from './management/vendor.schema.js';
import { filamentStockModel } from './inventory/filamentstock.schema.js';
import { purchaseOrderModel } from './inventory/purchaseorder.schema.js';
import { stockEventModel } from './inventory/stockevent.schema.js';
import { stockAuditModel } from './inventory/stockaudit.schema.js';
import { partStockModel } from './inventory/partstock.schema.js';
import { auditLogModel } from './management/auditlog.schema.js';
import { userModel } from './management/user.schema.js';
import { noteTypeModel } from './management/notetype.schema.js';
import { noteModel } from './misc/note.schema.js';
import { documentSizeModel } from './management/documentsize.schema.js';
import { documentTemplateModel } from './management/documenttemplate.schema.js';
import { hostModel } from './management/host.schema.js';
import { documentPrinterModel } from './management/documentprinter.schema.js';
import { documentJobModel } from './management/documentjob.schema.js';
import { fileModel } from './management/file.schema.js';
import { courierServiceModel } from './management/courierservice.schema.js';
import { courierModel } from './management/courier.schema.js';
import { taxRateModel } from './management/taxrates.schema.js';
import { taxRecordModel } from './management/taxrecord.schema.js';
// Map prefixes to models and id fields
export const models = {
PRN: { model: printerModel, idField: '_id', type: 'printer', referenceField: '_reference' },
FIL: { model: filamentModel, idField: '_id', type: 'filament', referenceField: '_reference' },
GCF: { model: gcodeFileModel, idField: '_id', type: 'gcodeFile', referenceField: '_reference' },
JOB: { model: jobModel, idField: '_id', type: 'job', referenceField: '_reference' },
PRT: { model: partModel, idField: '_id', type: 'part', referenceField: '_reference' },
PRD: { model: productModel, idField: '_id', type: 'product', referenceField: '_reference' },
VEN: { model: vendorModel, idField: '_id', type: 'vendor', referenceField: '_reference' },
SJB: { model: subJobModel, idField: '_id', type: 'subJob', referenceField: '_reference' },
FLS: {
model: filamentStockModel,
idField: '_id',
type: 'filamentStock',
referenceField: '_reference',
},
SEV: { model: stockEventModel, idField: '_id', type: 'stockEvent', referenceField: '_reference' },
SAU: { model: stockAuditModel, idField: '_id', type: 'stockAudit', referenceField: '_reference' },
PTS: { model: partStockModel, idField: '_id', type: 'partStock', referenceField: '_reference' },
PDS: { model: null, idField: '_id', type: 'productStock', referenceField: '_reference' }, // No productStockModel found
ADL: { model: auditLogModel, idField: '_id', type: 'auditLog', referenceField: '_reference' },
USR: { model: userModel, idField: '_id', type: 'user', referenceField: '_reference' },
NTY: { model: noteTypeModel, idField: '_id', type: 'noteType', referenceField: '_reference' },
NTE: { model: noteModel, idField: '_id', type: 'note', referenceField: '_reference' },
DSZ: {
model: documentSizeModel,
idField: '_id',
type: 'documentSize',
referenceField: '_reference',
},
DTP: {
model: documentTemplateModel,
idField: '_id',
type: 'documentTemplate',
referenceField: '_reference',
},
DPR: {
model: documentPrinterModel,
idField: '_id',
type: 'documentPrinter',
referenceField: '_reference',
},
DJB: {
model: documentJobModel,
idField: '_id',
type: 'documentJob',
referenceField: '_reference',
},
HST: { model: hostModel, idField: '_id', type: 'host', referenceField: '_reference' },
FLE: { model: fileModel, idField: '_id', type: 'file', referenceField: '_reference' },
POR: {
model: purchaseOrderModel,
idField: '_id',
type: 'purchaseOrder',
referenceField: '_reference',
},
COS: {
model: courierServiceModel,
idField: '_id',
type: 'courierService',
referenceField: '_reference',
},
COR: { model: courierModel, idField: '_id', type: 'courier', referenceField: '_reference' },
TXR: { model: taxRateModel, idField: '_id', type: 'taxRate', referenceField: '_reference' },
TXD: { model: taxRecordModel, idField: '_id', type: 'taxRecord', referenceField: '_reference' },
};

View File

@ -3,42 +3,16 @@ import { hostModel } from './database/schemas/management/host.schema.js';
import crypto from 'crypto';
import { nanoid } from 'nanoid';
import canonicalize from 'canonical-json';
import { models } from './database/schemas/models.js';
import { loadConfig } from './config.js';
import { userModel } from './database/schemas/management/user.schema.js';
import { documentSizeModel } from './database/schemas/management/documentsize.schema.js';
import { documentJobModel } from './database/schemas/management/documentjob.schema.js';
import { documentTemplateModel } from './database/schemas/management/documenttemplate.schema.js';
import { documentPrinterModel } from './database/schemas/management/documentprinter.schema.js';
import { printerModel } from './database/schemas/production/printer.schema.js';
import { subJobModel } from './database/schemas/production/subjob.schema.js';
import { jobModel } from './database/schemas/production/job.schema.js';
import { filamentStockModel } from './database/schemas/inventory/filamentstock.schema.js';
import { fileModel } from './database/schemas/management/file.schema.js';
import { gcodeFileModel } from './database/schemas/production/gcodefile.schema.js';
import { stockEventModel } from './database/schemas/inventory/stockevent.schema.js';
import { filamentModel } from './database/schemas/management/filament.schema.js';
const config = loadConfig();
const authCodeLength = 64;
const modelList = [
hostModel,
userModel,
documentSizeModel,
documentJobModel,
documentTemplateModel,
documentPrinterModel,
printerModel,
jobModel,
subJobModel,
fileModel,
gcodeFileModel,
filamentStockModel,
stockEventModel,
filamentModel
];
const modelList = Object.values(models)
.map(model => model.model)
.filter(model => model != null);
export async function generateHostOTP(id) {
const otp = crypto.randomInt(0, 1000000).toString().padStart(6, '0'); // 0 to 999999