UNPKG

@accounter/pcn874-generator

Version:
331 lines (330 loc) 12.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.transactionCoreSchema = exports.transactionTransformerSchema = exports.transactionStrictSchema = exports.headerCoreSchema = exports.headerTransformerSchema = exports.headerStrictSchema = void 0; const zod_1 = require("zod"); const types_js_1 = require("./types.js"); const index_js_1 = require("./utils/index.js"); const DIGITS_REGEX = /^\d+$/; const MONTH_REGEX = /^(20\d{2})(?:0[1-9]|1[0-2])$/; const DATE_REGEX = /^(20\d{2})(?:0[1-9]|1[0-2])(?:0[1-9]|[1-2][0-9]|3[0-1])$/; // most strict requirements exports.headerStrictSchema = zod_1.z .object({ licensedDealerId: zod_1.z .string() .length(9, "Dealer's license ID must include 9 digits") .regex(DIGITS_REGEX, 'Only digits are allowed'), reportMonth: zod_1.z.string().length(6).regex(MONTH_REGEX, 'Dates must be in YYYYMM format'), generationDate: zod_1.z .string() .length(8, 'Dates must be in YYYYMMDD format') .regex(DATE_REGEX, 'Dates must be in YYYYMMDD format'), taxableSalesAmount: zod_1.z.number().transform(value => (0, index_js_1.numToSignedString)(value, 11)), taxableSalesVat: zod_1.z.number().transform(value => (0, index_js_1.numToSignedString)(value, 9)), salesRecordCount: zod_1.z .number() .int() .min(0, 'Sales record count must be >= 0') .transform(value => (0, index_js_1.addLeadingZeros)(value, 9)), zeroValOrExemptSalesCount: zod_1.z .number() .int() .transform(value => (0, index_js_1.numToSignedString)(value, 11)), otherInputsVat: zod_1.z.number().transform(value => (0, index_js_1.numToSignedString)(value, 9)), equipmentInputsVat: zod_1.z.number().transform(value => (0, index_js_1.numToSignedString)(value, 9)), inputsCount: zod_1.z .number() .int() .min(0, 'Inputs count must be >= 0') .transform(value => (0, index_js_1.addLeadingZeros)(value, 9)), totalVat: zod_1.z.number().transform(value => (0, index_js_1.numToSignedString)(value, 11)), }) .strict(); // transformations that can be preformed by generator in non-strict mode exports.headerTransformerSchema = zod_1.z .object({ licensedDealerId: zod_1.z.string().transform(id => (0, index_js_1.digitsAdjuster)(id, 9)), reportMonth: zod_1.z.string(), generationDate: zod_1.z .string() .optional() .transform(date => { { if (date) return date; // if not provided - use current date const now = new Date(); const year = now.getUTCFullYear(); const month = `0${now.getUTCMonth() + 1}`.slice(-2); const day = `0${now.getUTCDate()}`.slice(-2); return `${year}${month}${day}`; } }), taxableSalesAmount: zod_1.z.number(), taxableSalesVat: zod_1.z.number(), salesRecordCount: zod_1.z.number().int(), zeroValOrExemptSalesCount: zod_1.z.number().int(), otherInputsVat: zod_1.z.number(), equipmentInputsVat: zod_1.z.number(), inputsCount: zod_1.z.number().int(), totalVat: zod_1.z.number(), }) .strict(); // most basic requirements + obvious transformations exports.headerCoreSchema = zod_1.z.object({ /** * User Licensed Dealer identification Number * 9 digits * מספר עוסק */ licensedDealerId: zod_1.z.string().transform(id => (0, index_js_1.cleanNonDigitChars)(id)), /** * Month for which detailed report is being submitted * YYYYMM * תקופת הדיווח */ reportMonth: zod_1.z.string().length(6).regex(MONTH_REGEX, 'Dates must be in YYYYMM format'), /** * File Generation Date * YYYYMM * if undefined - current date will be inputed * תאריך הגשה */ generationDate: zod_1.z .string() .length(8) .regex(DATE_REGEX, 'Dates must be in YYYYMMDD format') .optional(), /** * Total amount of taxable sales (excluding VAT) * in the reported file * עסקאות חייבות */ taxableSalesAmount: zod_1.z.number(), /** * Total VAT on taxable sales * in the reported file * מע"מ עסקאות חייבות */ taxableSalesVat: zod_1.z.number(), /** * Total number of records for "sales". * Number of sales records - both taxable and zero-rated/ exempt * מס' עסקאות */ salesRecordCount: zod_1.z.number().int(), /** * Total of zero value/exempt sales for period * עסקאות פטורות / אפס */ zeroValOrExemptSalesCount: zod_1.z.number().int(), /** * Total VAT on "other" inputs required during period * תשומות אחרות */ otherInputsVat: zod_1.z.number(), /** * Total VAT on "equipment" inputs required during period * תשומות ציוד */ equipmentInputsVat: zod_1.z.number(), /** * Total number of records for inputs (other and equipment) * מס' תשומות */ inputsCount: zod_1.z.number().int(), /** * Total VAT to pay / receive for period * positive value => pay * negative value => receive * סכום מדווח */ totalVat: zod_1.z.number(), }); // most strict requirements exports.transactionStrictSchema = zod_1.z .object({ entryType: zod_1.z.nativeEnum(types_js_1.EntryType).transform(entryType => entryType.valueOf()[0]), vatId: zod_1.z.string().length(9).regex(DIGITS_REGEX, 'Only digits are allowed'), allocationNumber: zod_1.z.string().length(9).regex(DIGITS_REGEX, 'Only digits are allowed'), invoiceDate: zod_1.z.string().length(8).regex(DATE_REGEX, 'Dates must be in YYYYMMDD format'), refGroup: zod_1.z.string().length(4), refNumber: zod_1.z.string().length(9).regex(DIGITS_REGEX, 'Only digits are allowed'), totalVat: zod_1.z .number() .int() .transform(value => (0, index_js_1.addLeadingZeros)(value, 9)), invoiceSum: zod_1.z .number() .int() .transform(value => (0, index_js_1.numToSignedString)(value, 10)), }) .strict() .refine(transaction => { switch (transaction.entryType) { case types_js_1.EntryType.SALE_ZERO_OR_EXEMPT: { if (transaction.totalVat !== '000000000') { throw new Error(`Transactions of entry type "SALE_ZERO_OR_EXEMPT" VAT should be 0, received "${transaction.totalVat}". Replacing with 0`); } break; } case types_js_1.EntryType.SALE_UNIDENTIFIED_CUSTOMER: { if (transaction.vatId !== '000000000') { throw new Error(`Transactions of entry type "SALE_UNIDENTIFIED_CUSTOMER" should not include vatId, received "${transaction.vatId}".`); } break; } case types_js_1.EntryType.SALE_UNIDENTIFIED_ZERO_OR_EXEMPT: { if (transaction.vatId !== '000000000') { throw new Error(`Transactions of entry type "SALE_UNIDENTIFIED_ZERO_OR_EXEMPT" should not include vatId, received "${transaction.vatId}".`); } if (transaction.totalVat !== '000000000') { throw new Error(`Transactions of entry type "SALE_UNIDENTIFIED_ZERO_OR_EXEMPT" VAT should be 0, received "${transaction.totalVat}". Replacing with 0`); } break; } case types_js_1.EntryType.SALE_EXPORT: { if (transaction.totalVat !== '000000000') { throw new Error(`Transactions of entry type "SALE_EXPORT" should not include totalVat, received "${transaction.totalVat}"`); } break; } case types_js_1.EntryType.INPUT_PETTY_CASH: { if (transaction.vatId !== '000000000') { throw new Error(`Transactions of entry type "INPUT_PETTY_CASH" should not include vatId, received "${transaction.vatId}".`); } if (transaction.refNumber === '000000000') { throw new Error(`On transactions of entry type "INPUT_PETTY_CASH", refNumber should reflect the number of invoices in the entry (hence > 0), received "${transaction.refNumber}"`); } break; } case types_js_1.EntryType.INPUT_IMPORT: { if (transaction.refNumber !== '000000000') { throw new Error(`Transactions of entry type "INPUT_IMPORT" should not include refNumber, received "${transaction.refNumber}".`); } break; } } return transaction; }); // transformations that can be preformed by generator in non-strict mode exports.transactionTransformerSchema = zod_1.z .object({ allocationNumber: zod_1.z .string() .optional() .transform(allocationNumber => (0, index_js_1.digitsAdjuster)(allocationNumber ?? '', 9)), entryType: zod_1.z.nativeEnum(types_js_1.EntryType), invoiceDate: zod_1.z.string(), invoiceSum: zod_1.z.number().int(), refGroup: zod_1.z .string() .optional() .transform(refGroup => (0, index_js_1.digitsAdjuster)(refGroup ?? '', 4)), refNumber: zod_1.z .string() .optional() .transform(refNumber => (0, index_js_1.digitsAdjuster)(refNumber ?? '', 9)), totalVat: zod_1.z.number().int().optional(), vatId: zod_1.z .string() .optional() .transform(id => (0, index_js_1.digitsAdjuster)(id ?? '', 9)), }) .strict() .refine(transaction => { switch (transaction.entryType) { case types_js_1.EntryType.SALE_REGULAR: { if (transaction.invoiceSum <= 5000) { transaction.vatId ??= '000000000'; } break; } case types_js_1.EntryType.SALE_ZERO_OR_EXEMPT: { if (transaction.totalVat && transaction.totalVat !== 0) { transaction.totalVat = 0; } if (transaction.invoiceSum <= 5000) { transaction.vatId ??= '000000000'; } break; } case types_js_1.EntryType.SALE_UNIDENTIFIED_ZERO_OR_EXEMPT: { if (transaction.totalVat && transaction.totalVat !== 0) { transaction.totalVat = 0; } break; } case types_js_1.EntryType.SALE_EXPORT: { transaction.vatId ??= '999999999'; break; } case types_js_1.EntryType.INPUT_SINGLE_DOC_BY_LAW: { transaction.refNumber ??= '000000000'; break; } } return transaction; }); // most basic requirements + obvious transformations exports.transactionCoreSchema = zod_1.z.object({ /** * Entry Type (document type) * סוג רשומה */ entryType: zod_1.z.nativeEnum(types_js_1.EntryType), /** * VAT identification number – of the other side of the transaction. * For transactions entries – the customer * For inputs – the supplier * ספק / רשימון */ vatId: zod_1.z .string() .optional() .transform(id => (id ? (0, index_js_1.cleanNonDigitChars)(id) : undefined)), /** * Short allocation number – last 9 digits of full number. * מספר הקצאה קצר */ allocationNumber: zod_1.z .string() .optional() .transform(allocationNumber => allocationNumber ? (0, index_js_1.cleanNonDigitChars)(allocationNumber) : undefined), /** * Invoice Date/Reference. * YYYYMMDD * תאריך החשבונית */ invoiceDate: zod_1.z.string().length(8).regex(DIGITS_REGEX, 'Only digits are allowed'), /** * Reference group. * Series etc. zeros are possible at this stage * קבוצת אסמכתא */ refGroup: zod_1.z .string() .optional() .transform(refGroup => (refGroup ? (0, index_js_1.cleanNonDigitChars)(refGroup) : undefined)), /** * Reference number. * First 9 positions from the right * מספר אסמכתא */ refNumber: zod_1.z .string() .optional() .transform(refNumber => (refNumber ? (0, index_js_1.cleanNonDigitChars)(refNumber) : undefined)), /** * Total VAT in invoice / total VAT that is allowed (1/4…. 2/3…). * Rounded to the nearest shekel – always a positive value * סכום המע"מ */ totalVat: zod_1.z.number().int().min(0).optional(), /** * Invoice total (excluding VAT) * Always the 100%, always a positive value, rounded to the nearest shekel * סכום */ invoiceSum: zod_1.z.number().int(), });