77 lines
3.1 KiB
TypeScript
77 lines
3.1 KiB
TypeScript
// lib/calculators/soap.ts
|
||
// Калькулятор мыла для frontend
|
||
|
||
import type { Calculator, CalculatorField, CalculationResult } from '@/types/calculator';
|
||
|
||
const fieldSchema: CalculatorField[] = [
|
||
{ id: 'soapName', name: 'soapName', label: 'Название мыла', type: 'text', required: true },
|
||
{ id: 'weight', name: 'weight', label: 'Вес мыла, г', type: 'number', required: true },
|
||
{ id: 'basePrice', name: 'basePrice', label: 'Цена основы, руб', type: 'number', required: false },
|
||
{ id: 'aromaPrice', name: 'aromaPrice', label: 'Цена отдушки, руб', type: 'number', required: false },
|
||
{ id: 'aromaWeight', name: 'aromaWeight', label: 'Фасовка отдушки, г', type: 'number', required: false },
|
||
{ id: 'pigmentPrice', name: 'pigmentPrice', label: 'Цена пигмента, руб', type: 'number', required: false },
|
||
{ id: 'pigmentWeight', name: 'pigmentWeight', label: 'Фасовка пигмента, г', type: 'number', required: false },
|
||
{ id: 'moldPrice', name: 'moldPrice', label: 'Цена формы, руб', type: 'number', required: false },
|
||
{ id: 'box', name: 'box', label: 'Пакет/коробка, руб', type: 'number', required: false, group: 'packaging' },
|
||
{ id: 'filler', name: 'filler', label: 'Наполнитель, руб', type: 'number', required: false, group: 'packaging' },
|
||
{ id: 'ribbon', name: 'ribbon', label: 'Лента, руб', type: 'number', required: false, group: 'packaging' },
|
||
{ id: 'labelValue', name: 'labelValue', label: 'Наклейка, руб', type: 'number', required: false, group: 'packaging' },
|
||
{ id: 'markup', name: 'markup', label: 'Наценка, %', type: 'number', required: false },
|
||
];
|
||
|
||
function round(val: number): number {
|
||
return Math.round(val * 10) / 10;
|
||
}
|
||
|
||
function calculate(data: Record<string, any>): CalculationResult {
|
||
const {
|
||
weight = 0,
|
||
basePrice = 0,
|
||
aromaPrice = 0,
|
||
aromaWeight = 1,
|
||
pigmentPrice = 0,
|
||
pigmentWeight = 1,
|
||
moldPrice = 0,
|
||
packaging = { box: 0, filler: 0, ribbon: 0, label: 0 },
|
||
} = data;
|
||
|
||
const base = (weight / 1000) * basePrice;
|
||
const aroma = ((weight * 0.01) / aromaWeight) * aromaPrice;
|
||
const pigment = ((weight * 0.005) / pigmentWeight) * pigmentPrice;
|
||
const mold = moldPrice / 100;
|
||
const packagingCost = (packaging.box || 0) + (packaging.filler || 0) + (packaging.ribbon || 0) + (packaging.label || 0);
|
||
const subtotal = base + aroma + pigment + mold + packagingCost;
|
||
const operational = subtotal * 0.05;
|
||
const total = subtotal + operational;
|
||
|
||
return {
|
||
base: round(base),
|
||
aroma: round(aroma),
|
||
pigment: round(pigment),
|
||
mold: round(mold),
|
||
packaging: round(packagingCost),
|
||
operational: round(operational),
|
||
total: round(total),
|
||
};
|
||
}
|
||
|
||
function getRequiredFields(): string[] {
|
||
return fieldSchema.filter((f) => f.required).map((f) => f.name);
|
||
}
|
||
|
||
function getNumericFields(): string[] {
|
||
return fieldSchema.filter((f) => f.type === 'number').map((f) => f.name);
|
||
}
|
||
|
||
const soapCalculator: Calculator = {
|
||
id: 'soap',
|
||
name: 'Мыло',
|
||
fieldSchema,
|
||
calculate,
|
||
getRequiredFields,
|
||
getNumericFields,
|
||
};
|
||
|
||
export default soapCalculator;
|
||
|