@kalbi/zeicheck 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/data/useful-life-table.json +45 -0
- package/dist/chunk-LZZKQ7B2.js +994 -0
- package/dist/chunk-LZZKQ7B2.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +131 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +259 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,994 @@
|
|
|
1
|
+
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/models/types.ts
|
|
4
|
+
function yen(n) {
|
|
5
|
+
return Math.trunc(n);
|
|
6
|
+
}
|
|
7
|
+
var FormType = /* @__PURE__ */ ((FormType3) => {
|
|
8
|
+
FormType3["ABA"] = "ABA";
|
|
9
|
+
FormType3["ABB"] = "ABB";
|
|
10
|
+
FormType3["VCA"] = "VCA";
|
|
11
|
+
return FormType3;
|
|
12
|
+
})(FormType || {});
|
|
13
|
+
|
|
14
|
+
// src/parser/xtx-reader.ts
|
|
15
|
+
import { readFile } from "fs/promises";
|
|
16
|
+
import { XMLParser } from "fast-xml-parser";
|
|
17
|
+
var parser = new XMLParser({
|
|
18
|
+
ignoreAttributes: false,
|
|
19
|
+
attributeNamePrefix: "@_",
|
|
20
|
+
isArray: (_name, jpath) => {
|
|
21
|
+
return jpath === "DataRoot.FormData" || /\.FormData\.Field$/.test(jpath);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
function parseXml(xml) {
|
|
25
|
+
const result = parser.parse(xml);
|
|
26
|
+
const root = result.DataRoot;
|
|
27
|
+
if (!root) {
|
|
28
|
+
throw new Error("Invalid xtx: missing DataRoot element");
|
|
29
|
+
}
|
|
30
|
+
const formDataArray = root.FormData ?? [];
|
|
31
|
+
const forms = formDataArray.map((fd) => {
|
|
32
|
+
const fields = /* @__PURE__ */ new Map();
|
|
33
|
+
const xmlFields = fd.Field ?? [];
|
|
34
|
+
for (const field of xmlFields) {
|
|
35
|
+
const value = field["#text"] != null ? String(field["#text"]) : "";
|
|
36
|
+
fields.set(field["@_id"], value);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
formType: fd["@_id"],
|
|
40
|
+
fields
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
return { forms, rawXml: xml };
|
|
44
|
+
}
|
|
45
|
+
function readXtxString(xml) {
|
|
46
|
+
return parseXml(xml);
|
|
47
|
+
}
|
|
48
|
+
async function readXtxFile(filePath) {
|
|
49
|
+
const xml = await readFile(filePath, "utf-8");
|
|
50
|
+
return parseXml(xml);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/parser/form-detector.ts
|
|
54
|
+
var knownForms = /* @__PURE__ */ new Map([
|
|
55
|
+
["ABA", "ABA" /* ABA */],
|
|
56
|
+
["ABB", "ABB" /* ABB */],
|
|
57
|
+
["VCA", "VCA" /* VCA */]
|
|
58
|
+
]);
|
|
59
|
+
function detectForms(parsed) {
|
|
60
|
+
const detected = [];
|
|
61
|
+
for (const form of parsed.forms) {
|
|
62
|
+
const formType = knownForms.get(form.formType);
|
|
63
|
+
if (formType !== void 0) {
|
|
64
|
+
detected.push(formType);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return detected;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/parser/normalizer.ts
|
|
71
|
+
function yenField(fields, code) {
|
|
72
|
+
const raw = fields.get(code);
|
|
73
|
+
return yen(raw ? Number(raw) : 0);
|
|
74
|
+
}
|
|
75
|
+
function accountBalance(fields, openingCode, closingCode) {
|
|
76
|
+
return {
|
|
77
|
+
opening: yenField(fields, openingCode),
|
|
78
|
+
closing: yenField(fields, closingCode)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function getFormFields(parsed, formType) {
|
|
82
|
+
const form = parsed.forms.find((f) => f.formType === formType);
|
|
83
|
+
return form?.fields ?? /* @__PURE__ */ new Map();
|
|
84
|
+
}
|
|
85
|
+
function buildIncomeStatement(vca) {
|
|
86
|
+
return {
|
|
87
|
+
revenue: yenField(vca, "ITA_VCA0010"),
|
|
88
|
+
cogs: {
|
|
89
|
+
openingInventory: yenField(vca, "ITA_VCA0020"),
|
|
90
|
+
purchases: yenField(vca, "ITA_VCA0030"),
|
|
91
|
+
closingInventory: yenField(vca, "ITA_VCA0040"),
|
|
92
|
+
total: yenField(vca, "ITA_VCA0050")
|
|
93
|
+
},
|
|
94
|
+
grossProfit: yenField(vca, "ITA_VCA0060"),
|
|
95
|
+
expenses: {
|
|
96
|
+
taxes: yenField(vca, "ITA_VCA0100"),
|
|
97
|
+
insurance: yenField(vca, "ITA_VCA0110"),
|
|
98
|
+
repairs: yenField(vca, "ITA_VCA0120"),
|
|
99
|
+
depreciation: yenField(vca, "ITA_VCA0130"),
|
|
100
|
+
welfare: yenField(vca, "ITA_VCA0140"),
|
|
101
|
+
salaries: yenField(vca, "ITA_VCA0150"),
|
|
102
|
+
outsourcing: yenField(vca, "ITA_VCA0160"),
|
|
103
|
+
interest: yenField(vca, "ITA_VCA0170"),
|
|
104
|
+
rent: yenField(vca, "ITA_VCA0180"),
|
|
105
|
+
retirement: yenField(vca, "ITA_VCA0190"),
|
|
106
|
+
utilities: yenField(vca, "ITA_VCA0200"),
|
|
107
|
+
travel: yenField(vca, "ITA_VCA0210"),
|
|
108
|
+
communication: yenField(vca, "ITA_VCA0220"),
|
|
109
|
+
advertising: yenField(vca, "ITA_VCA0230"),
|
|
110
|
+
entertainment: yenField(vca, "ITA_VCA0240"),
|
|
111
|
+
consumables: yenField(vca, "ITA_VCA0250"),
|
|
112
|
+
miscellaneous: yenField(vca, "ITA_VCA0260"),
|
|
113
|
+
otherExpenses: yenField(vca, "ITA_VCA0270")
|
|
114
|
+
},
|
|
115
|
+
totalExpenses: yenField(vca, "ITA_VCA0280"),
|
|
116
|
+
operatingIncome: yenField(vca, "ITA_VCA0290")
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function buildBalanceSheet(vca) {
|
|
120
|
+
return {
|
|
121
|
+
// Assets
|
|
122
|
+
cash: accountBalance(vca, "ITA_VCA1010", "ITA_VCA1210"),
|
|
123
|
+
deposits: accountBalance(vca, "ITA_VCA1020", "ITA_VCA1220"),
|
|
124
|
+
accountsReceivable: accountBalance(vca, "ITA_VCA1030", "ITA_VCA1230"),
|
|
125
|
+
inventory: accountBalance(vca, "ITA_VCA1040", "ITA_VCA1240"),
|
|
126
|
+
otherCurrentAssets: accountBalance(vca, "ITA_VCA1050", "ITA_VCA1250"),
|
|
127
|
+
buildings: accountBalance(vca, "ITA_VCA1060", "ITA_VCA1260"),
|
|
128
|
+
buildingImprovements: accountBalance(vca, "ITA_VCA1070", "ITA_VCA1270"),
|
|
129
|
+
machinery: accountBalance(vca, "ITA_VCA1080", "ITA_VCA1280"),
|
|
130
|
+
vehicles: accountBalance(vca, "ITA_VCA1090", "ITA_VCA1290"),
|
|
131
|
+
tools: accountBalance(vca, "ITA_VCA1100", "ITA_VCA1300"),
|
|
132
|
+
land: accountBalance(vca, "ITA_VCA1110", "ITA_VCA1310"),
|
|
133
|
+
otherFixedAssets: accountBalance(vca, "ITA_VCA1120", "ITA_VCA1320"),
|
|
134
|
+
accumulatedDepreciation: accountBalance(vca, "ITA_VCA1130", "ITA_VCA1330"),
|
|
135
|
+
assetsTotal: accountBalance(vca, "ITA_VCA1140", "ITA_VCA1340"),
|
|
136
|
+
// Liabilities
|
|
137
|
+
accountsPayable: accountBalance(vca, "ITA_VCA1410", "ITA_VCA1510"),
|
|
138
|
+
borrowings: accountBalance(vca, "ITA_VCA1420", "ITA_VCA1520"),
|
|
139
|
+
otherCurrentLiabilities: accountBalance(vca, "ITA_VCA1430", "ITA_VCA1530"),
|
|
140
|
+
liabilitiesTotal: accountBalance(vca, "ITA_VCA1440", "ITA_VCA1540"),
|
|
141
|
+
// Equity
|
|
142
|
+
ownerEquity: accountBalance(vca, "ITA_VCA1610", "ITA_VCA1710"),
|
|
143
|
+
ownerDrawings: accountBalance(vca, "ITA_VCA1620", "ITA_VCA1720"),
|
|
144
|
+
ownerContributions: accountBalance(vca, "ITA_VCA1630", "ITA_VCA1730"),
|
|
145
|
+
retainedEarnings: yenField(vca, "ITA_VCA1640"),
|
|
146
|
+
equityTotal: accountBalance(vca, "ITA_VCA1650", "ITA_VCA1750")
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function buildTaxFormA(aba) {
|
|
150
|
+
return {
|
|
151
|
+
businessIncome: yenField(aba, "ITA_ABA0010"),
|
|
152
|
+
realEstateIncome: yenField(aba, "ITA_ABA0020"),
|
|
153
|
+
otherIncome: yenField(aba, "ITA_ABA0030"),
|
|
154
|
+
businessProfit: yenField(aba, "ITA_ABA0110"),
|
|
155
|
+
realEstateProfit: yenField(aba, "ITA_ABA0120"),
|
|
156
|
+
totalIncome: yenField(aba, "ITA_ABA0130"),
|
|
157
|
+
totalDeductions: yenField(aba, "ITA_ABA0280"),
|
|
158
|
+
blueReturnDeduction: yenField(aba, "ITA_ABA0290"),
|
|
159
|
+
taxableIncome: yenField(aba, "ITA_ABA0310"),
|
|
160
|
+
incomeTax: yenField(aba, "ITA_ABA0320"),
|
|
161
|
+
taxDue: yenField(aba, "ITA_ABA0360")
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function buildTaxFormB(abb) {
|
|
165
|
+
return {
|
|
166
|
+
incomeDetails: [
|
|
167
|
+
{
|
|
168
|
+
type: abb.get("ITA_ABB0010") ?? "",
|
|
169
|
+
payer: abb.get("ITA_ABB0020") ?? "",
|
|
170
|
+
amount: yenField(abb, "ITA_ABB0030"),
|
|
171
|
+
withheld: yenField(abb, "ITA_ABB0040")
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
socialInsurance: yenField(abb, "ITA_ABB0110"),
|
|
175
|
+
smallBusinessMutualAid: yenField(abb, "ITA_ABB0120"),
|
|
176
|
+
lifeInsurance: yenField(abb, "ITA_ABB0130"),
|
|
177
|
+
earthquakeInsurance: yenField(abb, "ITA_ABB0140"),
|
|
178
|
+
spouseDeduction: yenField(abb, "ITA_ABB0210"),
|
|
179
|
+
dependentDeduction: yenField(abb, "ITA_ABB0220"),
|
|
180
|
+
basicDeduction: yenField(abb, "ITA_ABB0230")
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function buildDefaultFiscalYear() {
|
|
184
|
+
return {
|
|
185
|
+
nengo: 5,
|
|
186
|
+
year: 2023,
|
|
187
|
+
startDate: "2023-01-01",
|
|
188
|
+
endDate: "2023-12-31"
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function buildEmptyDepreciationSchedule() {
|
|
192
|
+
return {
|
|
193
|
+
assets: [],
|
|
194
|
+
totalDepreciation: yen(0),
|
|
195
|
+
totalBusinessDepreciation: yen(0)
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function normalize(parsed) {
|
|
199
|
+
const vca = getFormFields(parsed, "VCA");
|
|
200
|
+
const aba = getFormFields(parsed, "ABA");
|
|
201
|
+
const abb = getFormFields(parsed, "ABB");
|
|
202
|
+
const formTypes = detectForms(parsed);
|
|
203
|
+
return {
|
|
204
|
+
fiscalYear: buildDefaultFiscalYear(),
|
|
205
|
+
incomeStatement: buildIncomeStatement(vca),
|
|
206
|
+
balanceSheet: buildBalanceSheet(vca),
|
|
207
|
+
taxFormA: buildTaxFormA(aba),
|
|
208
|
+
taxFormB: buildTaxFormB(abb),
|
|
209
|
+
depreciationSchedule: buildEmptyDepreciationSchedule(),
|
|
210
|
+
metadata: {
|
|
211
|
+
filePath: "",
|
|
212
|
+
formTypes
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/parser/index.ts
|
|
218
|
+
async function parseXtxFile(filePath) {
|
|
219
|
+
const parsed = await readXtxFile(filePath);
|
|
220
|
+
const taxReturn = normalize(parsed);
|
|
221
|
+
return {
|
|
222
|
+
...taxReturn,
|
|
223
|
+
metadata: { ...taxReturn.metadata, filePath }
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function parseXtxString(xml) {
|
|
227
|
+
const parsed = readXtxString(xml);
|
|
228
|
+
return normalize(parsed);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/rules/rule-runner.ts
|
|
232
|
+
var severityOrder = {
|
|
233
|
+
error: 0,
|
|
234
|
+
warning: 1,
|
|
235
|
+
info: 2,
|
|
236
|
+
off: 3
|
|
237
|
+
};
|
|
238
|
+
function runRules(rules, ctx) {
|
|
239
|
+
const diagnostics = [];
|
|
240
|
+
for (const rule of rules) {
|
|
241
|
+
const configEntry = ctx.config.rules[rule.meta.id];
|
|
242
|
+
const severity = Array.isArray(configEntry) ? configEntry[0] : configEntry ?? rule.meta.severity;
|
|
243
|
+
if (severity === "off") continue;
|
|
244
|
+
const results = rule.check(ctx);
|
|
245
|
+
for (const diag of results) {
|
|
246
|
+
diagnostics.push({ ...diag, severity });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
diagnostics.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
|
|
250
|
+
return diagnostics;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/utils/monetary.ts
|
|
254
|
+
function formatYen(a) {
|
|
255
|
+
return a.toLocaleString("ja-JP");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/rules/balance-sheet/bs-equation.ts
|
|
259
|
+
var bsEquationRule = {
|
|
260
|
+
meta: {
|
|
261
|
+
id: "balance-sheet/equation",
|
|
262
|
+
name: "Balance Sheet Equation",
|
|
263
|
+
description: "\u8CC7\u7523\u5408\u8A08 = \u8CA0\u50B5\u5408\u8A08 + \u8CC7\u672C\u5408\u8A08 \u3092\u691C\u8A3C\u3059\u308B",
|
|
264
|
+
severity: "error"
|
|
265
|
+
},
|
|
266
|
+
check(ctx) {
|
|
267
|
+
const bs = ctx.taxReturn.balanceSheet;
|
|
268
|
+
const diagnostics = [];
|
|
269
|
+
const closingAssets = bs.assetsTotal.closing;
|
|
270
|
+
const closingLiabilities = bs.liabilitiesTotal.closing;
|
|
271
|
+
const closingEquity = bs.equityTotal.closing;
|
|
272
|
+
if (closingAssets !== closingLiabilities + closingEquity) {
|
|
273
|
+
diagnostics.push({
|
|
274
|
+
ruleId: "balance-sheet/equation",
|
|
275
|
+
severity: "error",
|
|
276
|
+
message: `\u671F\u672B\u6B8B\u9AD8: \u8CC7\u7523\u5408\u8A08(${formatYen(closingAssets)}) \u2260 \u8CA0\u50B5\u5408\u8A08(${formatYen(closingLiabilities)}) + \u8CC7\u672C\u5408\u8A08(${formatYen(closingEquity)})`
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
const openingAssets = bs.assetsTotal.opening;
|
|
280
|
+
const openingLiabilities = bs.liabilitiesTotal.opening;
|
|
281
|
+
const openingEquity = bs.equityTotal.opening;
|
|
282
|
+
if (openingAssets !== openingLiabilities + openingEquity) {
|
|
283
|
+
diagnostics.push({
|
|
284
|
+
ruleId: "balance-sheet/equation",
|
|
285
|
+
severity: "error",
|
|
286
|
+
message: `\u671F\u9996\u6B8B\u9AD8: \u8CC7\u7523\u5408\u8A08(${formatYen(openingAssets)}) \u2260 \u8CA0\u50B5\u5408\u8A08(${formatYen(openingLiabilities)}) + \u8CC7\u672C\u5408\u8A08(${formatYen(openingEquity)})`
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return diagnostics;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// src/rules/income-statement/pl-arithmetic-chain.ts
|
|
294
|
+
var plArithmeticChainRule = {
|
|
295
|
+
meta: {
|
|
296
|
+
id: "income-statement/pl-chain",
|
|
297
|
+
name: "P/L Arithmetic Chain",
|
|
298
|
+
description: "\u640D\u76CA\u8A08\u7B97\u66F8\u306E\u8A08\u7B97\u9023\u9396\u3092\u691C\u8A3C\u3059\u308B",
|
|
299
|
+
severity: "error"
|
|
300
|
+
},
|
|
301
|
+
check(ctx) {
|
|
302
|
+
const pl = ctx.taxReturn.incomeStatement;
|
|
303
|
+
const diagnostics = [];
|
|
304
|
+
const expectedGross = pl.revenue - pl.cogs.total;
|
|
305
|
+
if (pl.grossProfit !== expectedGross) {
|
|
306
|
+
diagnostics.push({
|
|
307
|
+
ruleId: "income-statement/pl-chain",
|
|
308
|
+
severity: "error",
|
|
309
|
+
message: `\u58F2\u4E0A\u7DCF\u5229\u76CA(${formatYen(pl.grossProfit)}) \u2260 \u58F2\u4E0A(${formatYen(pl.revenue)}) - \u58F2\u4E0A\u539F\u4FA1(${formatYen(pl.cogs.total)})`
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
const expectedOperating = pl.grossProfit - pl.totalExpenses;
|
|
313
|
+
if (pl.operatingIncome !== expectedOperating) {
|
|
314
|
+
diagnostics.push({
|
|
315
|
+
ruleId: "income-statement/pl-chain",
|
|
316
|
+
severity: "error",
|
|
317
|
+
message: `\u6240\u5F97\u91D1\u984D(${formatYen(pl.operatingIncome)}) \u2260 \u58F2\u4E0A\u7DCF\u5229\u76CA(${formatYen(pl.grossProfit)}) - \u7D4C\u8CBB\u5408\u8A08(${formatYen(pl.totalExpenses)})`
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return diagnostics;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// src/rules/income-statement/cogs-calculation.ts
|
|
325
|
+
var cogsCalculationRule = {
|
|
326
|
+
meta: {
|
|
327
|
+
id: "income-statement/cogs",
|
|
328
|
+
name: "COGS Calculation",
|
|
329
|
+
description: "\u58F2\u4E0A\u539F\u4FA1\u306E\u8A08\u7B97\u3092\u691C\u8A3C\u3059\u308B",
|
|
330
|
+
severity: "error"
|
|
331
|
+
},
|
|
332
|
+
check(ctx) {
|
|
333
|
+
const cogs = ctx.taxReturn.incomeStatement.cogs;
|
|
334
|
+
if (cogs.openingInventory === 0 && cogs.purchases === 0 && cogs.closingInventory === 0 && cogs.total === 0) {
|
|
335
|
+
return [];
|
|
336
|
+
}
|
|
337
|
+
const expected = cogs.openingInventory + cogs.purchases - cogs.closingInventory;
|
|
338
|
+
if (cogs.total !== expected) {
|
|
339
|
+
return [
|
|
340
|
+
{
|
|
341
|
+
ruleId: "income-statement/cogs",
|
|
342
|
+
severity: "error",
|
|
343
|
+
message: `\u58F2\u4E0A\u539F\u4FA1\u5408\u8A08(${formatYen(cogs.total)}) \u2260 \u671F\u9996\u68DA\u5378\u9AD8(${formatYen(cogs.openingInventory)}) + \u4ED5\u5165\u91D1\u984D(${formatYen(cogs.purchases)}) - \u671F\u672B\u68DA\u5378\u9AD8(${formatYen(cogs.closingInventory)})`
|
|
344
|
+
}
|
|
345
|
+
];
|
|
346
|
+
}
|
|
347
|
+
return [];
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// src/rules/income-statement/expense-total.ts
|
|
352
|
+
var expenseTotalRule = {
|
|
353
|
+
meta: {
|
|
354
|
+
id: "income-statement/expense-total",
|
|
355
|
+
name: "Expense Total",
|
|
356
|
+
description: "\u7D4C\u8CBB\u5408\u8A08\u304C\u5404\u7D4C\u8CBB\u9805\u76EE\u306E\u5408\u8A08\u3068\u4E00\u81F4\u3059\u308B\u304B\u691C\u8A3C\u3059\u308B",
|
|
357
|
+
severity: "error"
|
|
358
|
+
},
|
|
359
|
+
check(ctx) {
|
|
360
|
+
const exp = ctx.taxReturn.incomeStatement.expenses;
|
|
361
|
+
const computed = exp.salaries + exp.outsourcing + exp.retirement + exp.rent + exp.interest + exp.taxes + exp.insurance + exp.repairs + exp.consumables + exp.depreciation + exp.welfare + exp.utilities + exp.travel + exp.communication + exp.advertising + exp.entertainment + exp.miscellaneous + exp.otherExpenses;
|
|
362
|
+
const totalExpenses = ctx.taxReturn.incomeStatement.totalExpenses;
|
|
363
|
+
if (totalExpenses !== computed) {
|
|
364
|
+
return [
|
|
365
|
+
{
|
|
366
|
+
ruleId: "income-statement/expense-total",
|
|
367
|
+
severity: "error",
|
|
368
|
+
message: `\u7D4C\u8CBB\u5408\u8A08(${formatYen(totalExpenses)}) \u2260 \u5404\u7D4C\u8CBB\u9805\u76EE\u306E\u5408\u8A08(${formatYen(computed)})`
|
|
369
|
+
}
|
|
370
|
+
];
|
|
371
|
+
}
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
// src/rules/cross-statement/bs-pl-bridge.ts
|
|
377
|
+
var bsPlBridgeRule = {
|
|
378
|
+
meta: {
|
|
379
|
+
id: "cross-statement/bs-pl-bridge",
|
|
380
|
+
name: "BS-PL Bridge",
|
|
381
|
+
description: "\u8CB8\u501F\u5BFE\u7167\u8868\u306E\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u524D\u306E\u6240\u5F97\u91D1\u984D\u3068\u640D\u76CA\u8A08\u7B97\u66F8\u306E\u6240\u5F97\u91D1\u984D\u306E\u4E00\u81F4\u3092\u691C\u8A3C\u3059\u308B",
|
|
382
|
+
severity: "error"
|
|
383
|
+
},
|
|
384
|
+
check(ctx) {
|
|
385
|
+
const bsRetained = ctx.taxReturn.balanceSheet.retainedEarnings;
|
|
386
|
+
const plOperating = ctx.taxReturn.incomeStatement.operatingIncome;
|
|
387
|
+
if (bsRetained !== plOperating) {
|
|
388
|
+
return [
|
|
389
|
+
{
|
|
390
|
+
ruleId: "cross-statement/bs-pl-bridge",
|
|
391
|
+
severity: "error",
|
|
392
|
+
message: `\u640D\u76CA\u8A08\u7B97\u66F8\u306E\u6240\u5F97\u91D1\u984D(${formatYen(plOperating)}) \u2260 \u8CB8\u501F\u5BFE\u7167\u8868\u306E\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u524D\u306E\u6240\u5F97\u91D1\u984D(${formatYen(bsRetained)})`
|
|
393
|
+
}
|
|
394
|
+
];
|
|
395
|
+
}
|
|
396
|
+
return [];
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
// src/rules/balance-sheet/opening-owner-equity.ts
|
|
401
|
+
var openingOwnerEquityRule = {
|
|
402
|
+
meta: {
|
|
403
|
+
id: "balance-sheet/opening-owner-equity",
|
|
404
|
+
name: "\u4E8B\u696D\u4E3B\u8CB8\u501F \u671F\u9996\u6B8B\u9AD8\u30BC\u30ED",
|
|
405
|
+
description: "\u4E8B\u696D\u4E3B\u8CB8\u3068\u4E8B\u696D\u4E3B\u501F\u306F\u6BCE\u671F\u9996\u306B\u5143\u5165\u91D1\u3078\u632F\u66FF\u3055\u308C\u308B\u305F\u3081\u3001\u671F\u9996\u6B8B\u9AD8\u306F0\u5186\u3067\u3042\u308B\u3079\u304D\u3067\u3059\u3002",
|
|
406
|
+
severity: "error"
|
|
407
|
+
},
|
|
408
|
+
check(ctx) {
|
|
409
|
+
const diagnostics = [];
|
|
410
|
+
const bs = ctx.taxReturn.balanceSheet;
|
|
411
|
+
if (bs.ownerDrawings.opening !== 0) {
|
|
412
|
+
diagnostics.push({
|
|
413
|
+
ruleId: this.meta.id,
|
|
414
|
+
severity: this.meta.severity,
|
|
415
|
+
message: `\u4E8B\u696D\u4E3B\u8CB8\u306E\u671F\u9996\u6B8B\u9AD8\u304C0\u3067\u306F\u3042\u308A\u307E\u305B\u3093: ${formatYen(bs.ownerDrawings.opening)}`
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
if (bs.ownerContributions.opening !== 0) {
|
|
419
|
+
diagnostics.push({
|
|
420
|
+
ruleId: this.meta.id,
|
|
421
|
+
severity: this.meta.severity,
|
|
422
|
+
message: `\u4E8B\u696D\u4E3B\u501F\u306E\u671F\u9996\u6B8B\u9AD8\u304C0\u3067\u306F\u3042\u308A\u307E\u305B\u3093: ${formatYen(bs.ownerContributions.opening)}`
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
return diagnostics;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// src/rules/balance-sheet/motoire-kin-formula.ts
|
|
430
|
+
var motoireKinFormulaRule = {
|
|
431
|
+
meta: {
|
|
432
|
+
id: "balance-sheet/motoire-kin-formula",
|
|
433
|
+
name: "\u5143\u5165\u91D1\u7E70\u8D8A\u8A08\u7B97",
|
|
434
|
+
description: "\u5143\u5165\u91D1(\u5F53\u671F) = \u5143\u5165\u91D1(\u524D\u671F) + \u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u524D\u6240\u5F97(\u524D\u671F) + \u4E8B\u696D\u4E3B\u501F(\u524D\u671F\u672B) - \u4E8B\u696D\u4E3B\u8CB8(\u524D\u671F\u672B) \u3067\u3042\u308B\u3079\u304D\u3067\u3059\u3002\u524D\u5E74\u30C7\u30FC\u30BF\u304C\u5FC5\u8981\u3067\u3059\u3002",
|
|
435
|
+
severity: "error"
|
|
436
|
+
},
|
|
437
|
+
check(ctx) {
|
|
438
|
+
if (!ctx.priorYear) return [];
|
|
439
|
+
const priorBs = ctx.priorYear.balanceSheet;
|
|
440
|
+
const currentBs = ctx.taxReturn.balanceSheet;
|
|
441
|
+
const expected = yen(
|
|
442
|
+
priorBs.ownerEquity.opening + priorBs.retainedEarnings + priorBs.ownerContributions.closing - priorBs.ownerDrawings.closing
|
|
443
|
+
);
|
|
444
|
+
const actual = currentBs.ownerEquity.opening;
|
|
445
|
+
if (actual !== expected) {
|
|
446
|
+
return [
|
|
447
|
+
{
|
|
448
|
+
ruleId: this.meta.id,
|
|
449
|
+
severity: this.meta.severity,
|
|
450
|
+
message: `\u5143\u5165\u91D1\u306E\u671F\u9996\u6B8B\u9AD8(${formatYen(actual)}) \u2260 \u7E70\u8D8A\u8A08\u7B97\u984D(${formatYen(expected)})`,
|
|
451
|
+
details: `\u8A08\u7B97\u5F0F: \u5143\u5165\u91D1(\u524D\u671F\u9996)(${formatYen(priorBs.ownerEquity.opening)}) + \u6240\u5F97(\u524D\u671F)(${formatYen(priorBs.retainedEarnings)}) + \u4E8B\u696D\u4E3B\u501F(\u524D\u671F\u672B)(${formatYen(priorBs.ownerContributions.closing)}) - \u4E8B\u696D\u4E3B\u8CB8(\u524D\u671F\u672B)(${formatYen(priorBs.ownerDrawings.closing)})`
|
|
452
|
+
}
|
|
453
|
+
];
|
|
454
|
+
}
|
|
455
|
+
return [];
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// src/rules/balance-sheet/non-negative-cash.ts
|
|
460
|
+
var nonNegativeCashRule = {
|
|
461
|
+
meta: {
|
|
462
|
+
id: "balance-sheet/non-negative-cash",
|
|
463
|
+
name: "\u73FE\u91D1\u6B8B\u9AD8\u306E\u975E\u8CA0\u30C1\u30A7\u30C3\u30AF",
|
|
464
|
+
description: "\u73FE\u91D1\u6B8B\u9AD8\u306F0\u4EE5\u4E0A\u3067\u3042\u308B\u3079\u304D\u3067\u3059\u3002\u30DE\u30A4\u30CA\u30B9\u6B8B\u9AD8\u306F\u8A18\u5E33\u30DF\u30B9\u306E\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002",
|
|
465
|
+
severity: "warning"
|
|
466
|
+
},
|
|
467
|
+
check(ctx) {
|
|
468
|
+
const diagnostics = [];
|
|
469
|
+
const bs = ctx.taxReturn.balanceSheet;
|
|
470
|
+
if (bs.cash.opening < 0) {
|
|
471
|
+
diagnostics.push({
|
|
472
|
+
ruleId: this.meta.id,
|
|
473
|
+
severity: this.meta.severity,
|
|
474
|
+
message: `\u73FE\u91D1\u306E\u671F\u9996\u6B8B\u9AD8\u304C\u30DE\u30A4\u30CA\u30B9\u3067\u3059: ${formatYen(bs.cash.opening)}`
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
if (bs.cash.closing < 0) {
|
|
478
|
+
diagnostics.push({
|
|
479
|
+
ruleId: this.meta.id,
|
|
480
|
+
severity: this.meta.severity,
|
|
481
|
+
message: `\u73FE\u91D1\u306E\u671F\u672B\u6B8B\u9AD8\u304C\u30DE\u30A4\u30CA\u30B9\u3067\u3059: ${formatYen(bs.cash.closing)}`
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
return diagnostics;
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// src/rules/deductions/blue-deduction-cap.ts
|
|
489
|
+
var blueDeductionCapRule = {
|
|
490
|
+
meta: {
|
|
491
|
+
id: "deductions/blue-deduction-cap",
|
|
492
|
+
name: "\u9752\u8272\u63A7\u9664\u4E0A\u9650\u30C1\u30A7\u30C3\u30AF",
|
|
493
|
+
description: "\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u984D\u306F\u3001\u63A7\u9664\u524D\u306E\u6240\u5F97\u91D1\u984D\u3092\u8D85\u3048\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002\u6240\u5F97\u3092\u8D85\u3048\u308B\u5834\u5408\u306F\u6240\u5F97\u91D1\u984D\u304C\u4E0A\u9650\u3068\u306A\u308A\u307E\u3059\u3002",
|
|
494
|
+
severity: "warning"
|
|
495
|
+
},
|
|
496
|
+
check(ctx) {
|
|
497
|
+
const deduction = ctx.taxReturn.taxFormA.blueReturnDeduction;
|
|
498
|
+
const income = ctx.taxReturn.incomeStatement.operatingIncome;
|
|
499
|
+
if (deduction > income) {
|
|
500
|
+
return [
|
|
501
|
+
{
|
|
502
|
+
ruleId: this.meta.id,
|
|
503
|
+
severity: this.meta.severity,
|
|
504
|
+
message: `\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u984D(${formatYen(deduction)}) > \u63A7\u9664\u524D\u6240\u5F97(${formatYen(income)})`,
|
|
505
|
+
details: "\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u984D\u306F\u63A7\u9664\u524D\u6240\u5F97\u91D1\u984D\u304C\u4E0A\u9650\u3067\u3059\u3002\u6240\u5F97\u304C\u5C11\u306A\u3044\u5834\u5408\u306F\u6240\u5F97\u91D1\u984D\u307E\u3067\u3057\u304B\u63A7\u9664\u3067\u304D\u307E\u305B\u3093\u3002"
|
|
506
|
+
}
|
|
507
|
+
];
|
|
508
|
+
}
|
|
509
|
+
return [];
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
// src/rules/deductions/blue-deduction-eligibility.ts
|
|
514
|
+
var blueDeductionEligibilityRule = {
|
|
515
|
+
meta: {
|
|
516
|
+
id: "deductions/blue-deduction-eligibility",
|
|
517
|
+
name: "\u9752\u8272\u63A7\u966465\u4E07\u5186\u9069\u7528\u8981\u4EF6",
|
|
518
|
+
description: "65\u4E07\u5186\u306E\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u306B\u306Fe-Tax\u306B\u3088\u308B\u7533\u544A\u307E\u305F\u306F\u96FB\u5B50\u5E33\u7C3F\u4FDD\u5B58\u304C\u5FC5\u8981\u3067\u3059\uFF08\u4EE4\u548C2\u5E74\u5206\u4EE5\u964D\uFF09\u3002\u8981\u4EF6\u3092\u6E80\u305F\u3055\u306A\u3044\u5834\u5408\u306F55\u4E07\u5186\u304C\u4E0A\u9650\u3067\u3059\u3002",
|
|
519
|
+
severity: "info"
|
|
520
|
+
},
|
|
521
|
+
check(ctx) {
|
|
522
|
+
const deduction = ctx.taxReturn.taxFormA.blueReturnDeduction;
|
|
523
|
+
const limit55 = yen(55e4);
|
|
524
|
+
const limit65 = yen(65e4);
|
|
525
|
+
if (deduction > limit55 && deduction <= limit65) {
|
|
526
|
+
return [
|
|
527
|
+
{
|
|
528
|
+
ruleId: this.meta.id,
|
|
529
|
+
severity: this.meta.severity,
|
|
530
|
+
message: `\u9752\u8272\u7533\u544A\u7279\u5225\u63A7\u9664\u984D\u304C${formatYen(limit65)}\u3067\u3059\u3002e-Tax\u7533\u544A\u307E\u305F\u306F\u96FB\u5B50\u5E33\u7C3F\u4FDD\u5B58\u306E\u8981\u4EF6\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`,
|
|
531
|
+
details: "\u4EE4\u548C2\u5E74\u5206\u4EE5\u964D\u300165\u4E07\u5186\u63A7\u9664\u306B\u306Fe-Tax\u306B\u3088\u308B\u78BA\u5B9A\u7533\u544A\u306E\u9001\u4FE1\u3001\u307E\u305F\u306F\u96FB\u5B50\u5E33\u7C3F\u4FDD\u5B58\u6CD5\u306B\u57FA\u3065\u304F\u96FB\u5B50\u5E33\u7C3F\u306E\u5099\u4ED8\u3051\u304A\u3088\u3073\u4FDD\u5B58\u304C\u5FC5\u8981\u3067\u3059\u3002\u8981\u4EF6\u3092\u6E80\u305F\u3055\u306A\u3044\u5834\u5408\u306F55\u4E07\u5186\u304C\u4E0A\u9650\u3068\u306A\u308A\u307E\u3059\u3002"
|
|
532
|
+
}
|
|
533
|
+
];
|
|
534
|
+
}
|
|
535
|
+
return [];
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
// src/rules/depreciation/useful-life-rates.ts
|
|
540
|
+
var COMMON_USEFUL_LIVES = {
|
|
541
|
+
\u30D1\u30BD\u30B3\u30F3: [4],
|
|
542
|
+
\u30B5\u30FC\u30D0\u30FC: [5],
|
|
543
|
+
\u666E\u901A\u81EA\u52D5\u8ECA: [6],
|
|
544
|
+
\u8EFD\u81EA\u52D5\u8ECA: [4],
|
|
545
|
+
\u6728\u9020\u5EFA\u7269: [22],
|
|
546
|
+
\u9244\u7B4B\u30B3\u30F3\u30AF\u30EA\u30FC\u30C8\u5EFA\u7269: [47],
|
|
547
|
+
\u91D1\u5C5E\u88FD\u5BB6\u5177: [15]
|
|
548
|
+
};
|
|
549
|
+
var usefulLifeRatesRule = {
|
|
550
|
+
meta: {
|
|
551
|
+
id: "depreciation/useful-life-rates",
|
|
552
|
+
name: "\u6CD5\u5B9A\u8010\u7528\u5E74\u6570\u30C1\u30A7\u30C3\u30AF",
|
|
553
|
+
description: "\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306E\u8010\u7528\u5E74\u6570\u304C\u6CD5\u5B9A\u8010\u7528\u5E74\u6570\u30C6\u30FC\u30D6\u30EB\u3068\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059\u3002",
|
|
554
|
+
severity: "warning"
|
|
555
|
+
},
|
|
556
|
+
check(ctx) {
|
|
557
|
+
const diagnostics = [];
|
|
558
|
+
const assets = ctx.taxReturn.depreciationSchedule.assets;
|
|
559
|
+
for (const asset of assets) {
|
|
560
|
+
for (const [keyword, validLives] of Object.entries(COMMON_USEFUL_LIVES)) {
|
|
561
|
+
if (asset.name.includes(keyword) && !validLives.includes(asset.usefulLife)) {
|
|
562
|
+
diagnostics.push({
|
|
563
|
+
ruleId: this.meta.id,
|
|
564
|
+
severity: this.meta.severity,
|
|
565
|
+
message: `\u300C${asset.name}\u300D\u306E\u8010\u7528\u5E74\u6570(${asset.usefulLife}\u5E74)\u304C\u6CD5\u5B9A\u8010\u7528\u5E74\u6570(${validLives.join("/")}\u5E74)\u3068\u7570\u306A\u308A\u307E\u3059`
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return diagnostics;
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
// src/rules/depreciation/small-asset-threshold.ts
|
|
575
|
+
var smallAssetThresholdRule = {
|
|
576
|
+
meta: {
|
|
577
|
+
id: "depreciation/small-asset-threshold",
|
|
578
|
+
name: "\u5C11\u984D\u8CC7\u7523\u306E\u511F\u5374\u65B9\u6CD5\u30C1\u30A7\u30C3\u30AF",
|
|
579
|
+
description: "\u53D6\u5F97\u4FA1\u984D10\u4E07\u5186\u4EE5\u4E0B\u306F\u5168\u984D\u7D4C\u8CBB\u300110\u4E07\u5186\u8D8530\u4E07\u5186\u4EE5\u4E0B\u306F\u5C11\u984D\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306E\u7279\u4F8B\uFF08\u9752\u8272\u7533\u544A\u8005\uFF09\u304C\u9069\u7528\u53EF\u80FD\u3067\u3059\u3002",
|
|
580
|
+
severity: "warning"
|
|
581
|
+
},
|
|
582
|
+
check(ctx) {
|
|
583
|
+
const diagnostics = [];
|
|
584
|
+
const assets = ctx.taxReturn.depreciationSchedule.assets;
|
|
585
|
+
const threshold10 = yen(1e5);
|
|
586
|
+
const threshold30 = yen(3e5);
|
|
587
|
+
for (const asset of assets) {
|
|
588
|
+
if (asset.acquisitionCost <= threshold10 && asset.usefulLife > 1) {
|
|
589
|
+
diagnostics.push({
|
|
590
|
+
ruleId: this.meta.id,
|
|
591
|
+
severity: this.meta.severity,
|
|
592
|
+
message: `\u300C${asset.name}\u300D(\u53D6\u5F97\u4FA1\u984D${formatYen(asset.acquisitionCost)})\u306F10\u4E07\u5186\u4EE5\u4E0B\u306E\u305F\u3081\u3001\u5168\u984D\u7D4C\u8CBB\u8A08\u4E0A\u304C\u53EF\u80FD\u3067\u3059`
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
if (asset.acquisitionCost > threshold10 && asset.acquisitionCost <= threshold30 && asset.depreciationMethod !== "\u4E00\u62EC\u511F\u5374") {
|
|
596
|
+
diagnostics.push({
|
|
597
|
+
ruleId: this.meta.id,
|
|
598
|
+
severity: this.meta.severity,
|
|
599
|
+
message: `\u300C${asset.name}\u300D(\u53D6\u5F97\u4FA1\u984D${formatYen(asset.acquisitionCost)})\u306F30\u4E07\u5186\u4EE5\u4E0B\u306E\u305F\u3081\u3001\u5C11\u984D\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306E\u7279\u4F8B\uFF08\u4E00\u62EC\u7D4C\u8CBB\u8A08\u4E0A\uFF09\u304C\u9069\u7528\u53EF\u80FD\u3067\u3059`,
|
|
600
|
+
details: "\u9752\u8272\u7533\u544A\u8005\u306F\u53D6\u5F97\u4FA1\u984D30\u4E07\u5186\u672A\u6E80\u306E\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306B\u3064\u3044\u3066\u3001\u5E74\u9593\u5408\u8A08300\u4E07\u5186\u307E\u3067\u5168\u984D\u7D4C\u8CBB\u306B\u8A08\u4E0A\u3067\u304D\u307E\u3059\u3002"
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return diagnostics;
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
// src/rules/cross-statement/decision-to-return.ts
|
|
609
|
+
var decisionToReturnRule = {
|
|
610
|
+
meta: {
|
|
611
|
+
id: "cross-statement/decision-to-return",
|
|
612
|
+
name: "\u6C7A\u7B97\u66F8\u2192\u7533\u544A\u66F8 \u8EE2\u8A18\u4E00\u81F4",
|
|
613
|
+
description: "\u9752\u8272\u7533\u544A\u6C7A\u7B97\u66F8\u306E\u58F2\u4E0A\u91D1\u984D\u30FB\u6240\u5F97\u91D1\u984D\u304C\u7533\u544A\u66F8\u7B2C\u4E00\u8868\u306B\u6B63\u3057\u304F\u8EE2\u8A18\u3055\u308C\u3066\u3044\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059\u3002",
|
|
614
|
+
severity: "error"
|
|
615
|
+
},
|
|
616
|
+
check(ctx) {
|
|
617
|
+
const diagnostics = [];
|
|
618
|
+
const pl = ctx.taxReturn.incomeStatement;
|
|
619
|
+
const form = ctx.taxReturn.taxFormA;
|
|
620
|
+
if (pl.revenue !== form.businessIncome) {
|
|
621
|
+
diagnostics.push({
|
|
622
|
+
ruleId: this.meta.id,
|
|
623
|
+
severity: this.meta.severity,
|
|
624
|
+
message: `\u6C7A\u7B97\u66F8\u306E\u58F2\u4E0A\u91D1\u984D(${formatYen(pl.revenue)}) \u2260 \u7533\u544A\u66F8\u306E\u55B6\u696D\u7B49\u53CE\u5165(${formatYen(form.businessIncome)})`
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
const expectedProfit = yen(pl.operatingIncome - form.blueReturnDeduction);
|
|
628
|
+
if (form.businessProfit !== expectedProfit) {
|
|
629
|
+
diagnostics.push({
|
|
630
|
+
ruleId: this.meta.id,
|
|
631
|
+
severity: this.meta.severity,
|
|
632
|
+
message: `\u7533\u544A\u66F8\u306E\u55B6\u696D\u7B49\u6240\u5F97(${formatYen(form.businessProfit)}) \u2260 \u6C7A\u7B97\u66F8\u6240\u5F97(${formatYen(pl.operatingIncome)}) - \u9752\u8272\u63A7\u9664(${formatYen(form.blueReturnDeduction)})`,
|
|
633
|
+
details: `\u671F\u5F85\u5024: ${formatYen(expectedProfit)}`
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
return diagnostics;
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
// src/rules/cross-statement/depreciation-sum.ts
|
|
641
|
+
var depreciationSumRule = {
|
|
642
|
+
meta: {
|
|
643
|
+
id: "cross-statement/depreciation-sum",
|
|
644
|
+
name: "\u6E1B\u4FA1\u511F\u5374\u8CBB\u5408\u8A08\u306E\u4E00\u81F4",
|
|
645
|
+
description: "\u6E1B\u4FA1\u511F\u5374\u660E\u7D30\u306E\u5FC5\u8981\u7D4C\u8CBB\u7B97\u5165\u984D\u5408\u8A08\u304C\u640D\u76CA\u8A08\u7B97\u66F8\u306E\u6E1B\u4FA1\u511F\u5374\u8CBB\u3068\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059\u3002",
|
|
646
|
+
severity: "error"
|
|
647
|
+
},
|
|
648
|
+
check(ctx) {
|
|
649
|
+
const scheduleTotal = ctx.taxReturn.depreciationSchedule.totalBusinessDepreciation;
|
|
650
|
+
const plDepreciation = ctx.taxReturn.incomeStatement.expenses.depreciation;
|
|
651
|
+
if (scheduleTotal === 0 && plDepreciation === 0) return [];
|
|
652
|
+
if (scheduleTotal !== plDepreciation) {
|
|
653
|
+
return [
|
|
654
|
+
{
|
|
655
|
+
ruleId: this.meta.id,
|
|
656
|
+
severity: this.meta.severity,
|
|
657
|
+
message: `\u6E1B\u4FA1\u511F\u5374\u660E\u7D30\u306E\u5408\u8A08(${formatYen(scheduleTotal)}) \u2260 P/L\u6E1B\u4FA1\u511F\u5374\u8CBB(${formatYen(plDepreciation)})`
|
|
658
|
+
}
|
|
659
|
+
];
|
|
660
|
+
}
|
|
661
|
+
return [];
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
// src/rules/continuity/opening-closing-match.ts
|
|
666
|
+
var ACCOUNT_NAMES = {
|
|
667
|
+
cash: "\u73FE\u91D1",
|
|
668
|
+
deposits: "\u9810\u91D1",
|
|
669
|
+
accountsReceivable: "\u58F2\u639B\u91D1",
|
|
670
|
+
inventory: "\u68DA\u5378\u8CC7\u7523",
|
|
671
|
+
buildings: "\u5EFA\u7269",
|
|
672
|
+
vehicles: "\u8ECA\u4E21\u904B\u642C\u5177",
|
|
673
|
+
tools: "\u5DE5\u5177\u5668\u5177\u5099\u54C1",
|
|
674
|
+
land: "\u571F\u5730",
|
|
675
|
+
accountsPayable: "\u8CB7\u639B\u91D1",
|
|
676
|
+
borrowings: "\u501F\u5165\u91D1",
|
|
677
|
+
ownerEquity: "\u5143\u5165\u91D1"
|
|
678
|
+
};
|
|
679
|
+
var openingClosingMatchRule = {
|
|
680
|
+
meta: {
|
|
681
|
+
id: "continuity/opening-closing-match",
|
|
682
|
+
name: "\u671F\u9996=\u524D\u671F\u672B \u4E00\u81F4\u30C1\u30A7\u30C3\u30AF",
|
|
683
|
+
description: "\u5F53\u671F\u306E\u671F\u9996\u6B8B\u9AD8\u304C\u524D\u671F\u306E\u671F\u672B\u6B8B\u9AD8\u3068\u4E00\u81F4\u3059\u308B\u304B\u78BA\u8A8D\u3057\u307E\u3059\u3002\u524D\u5E74\u30C7\u30FC\u30BF\u304C\u5FC5\u8981\u3067\u3059\u3002",
|
|
684
|
+
severity: "error"
|
|
685
|
+
},
|
|
686
|
+
check(ctx) {
|
|
687
|
+
if (!ctx.priorYear) return [];
|
|
688
|
+
const diagnostics = [];
|
|
689
|
+
const currentBs = ctx.taxReturn.balanceSheet;
|
|
690
|
+
const priorBs = ctx.priorYear.balanceSheet;
|
|
691
|
+
for (const [key, label] of Object.entries(ACCOUNT_NAMES)) {
|
|
692
|
+
const current = currentBs[key];
|
|
693
|
+
const prior = priorBs[key];
|
|
694
|
+
if (current && prior && typeof current === "object" && "opening" in current && "closing" in prior && current.opening !== prior.closing) {
|
|
695
|
+
diagnostics.push({
|
|
696
|
+
ruleId: this.meta.id,
|
|
697
|
+
severity: this.meta.severity,
|
|
698
|
+
message: `${label}: \u5F53\u671F\u9996(${formatYen(current.opening)}) \u2260 \u524D\u671F\u672B(${formatYen(prior.closing)})`
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return diagnostics;
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
// src/rules/continuity/year-over-year-change.ts
|
|
707
|
+
var FIELDS_TO_CHECK = [
|
|
708
|
+
{ key: "revenue", label: "\u58F2\u4E0A" },
|
|
709
|
+
{ key: "totalExpenses", label: "\u7D4C\u8CBB\u5408\u8A08" },
|
|
710
|
+
{ key: "operatingIncome", label: "\u6240\u5F97\u91D1\u984D" }
|
|
711
|
+
];
|
|
712
|
+
var yearOverYearChangeRule = {
|
|
713
|
+
meta: {
|
|
714
|
+
id: "continuity/year-over-year-change",
|
|
715
|
+
name: "\u524D\u5E74\u6BD4\u5909\u52D5\u30C1\u30A7\u30C3\u30AF",
|
|
716
|
+
description: "\u58F2\u4E0A\u30FB\u7D4C\u8CBB\u30FB\u6240\u5F97\u304C\u524D\u5E74\u6BD4\u3067200%\u8D85\u306E\u5897\u52A0\u307E\u305F\u306F80%\u8D85\u306E\u6E1B\u5C11\u304C\u3042\u308B\u5834\u5408\u306B\u8B66\u544A\u3057\u307E\u3059\u3002\u524D\u5E74\u30C7\u30FC\u30BF\u304C\u5FC5\u8981\u3067\u3059\u3002",
|
|
717
|
+
severity: "warning"
|
|
718
|
+
},
|
|
719
|
+
check(ctx) {
|
|
720
|
+
if (!ctx.priorYear) return [];
|
|
721
|
+
const diagnostics = [];
|
|
722
|
+
const currentPl = ctx.taxReturn.incomeStatement;
|
|
723
|
+
const priorPl = ctx.priorYear.incomeStatement;
|
|
724
|
+
for (const { key, label } of FIELDS_TO_CHECK) {
|
|
725
|
+
const current = currentPl[key];
|
|
726
|
+
const prior = priorPl[key];
|
|
727
|
+
if (prior === 0) continue;
|
|
728
|
+
const ratio = current / prior;
|
|
729
|
+
if (ratio > 3) {
|
|
730
|
+
diagnostics.push({
|
|
731
|
+
ruleId: this.meta.id,
|
|
732
|
+
severity: this.meta.severity,
|
|
733
|
+
message: `${label}\u304C\u524D\u5E74\u6BD4${Math.round(ratio * 100)}%\u3067\u3059\uFF08${formatYen(prior)} \u2192 ${formatYen(current)}\uFF09`,
|
|
734
|
+
details: "200%\u3092\u8D85\u3048\u308B\u5927\u5E45\u306A\u5897\u52A0\u304C\u3042\u308A\u307E\u3059\u3002\u8A18\u5E33\u5185\u5BB9\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u3002"
|
|
735
|
+
});
|
|
736
|
+
} else if (ratio < 0.2) {
|
|
737
|
+
diagnostics.push({
|
|
738
|
+
ruleId: this.meta.id,
|
|
739
|
+
severity: this.meta.severity,
|
|
740
|
+
message: `${label}\u304C\u524D\u5E74\u6BD4${Math.round(ratio * 100)}%\u3067\u3059\uFF08${formatYen(prior)} \u2192 ${formatYen(current)}\uFF09`,
|
|
741
|
+
details: "80%\u3092\u8D85\u3048\u308B\u5927\u5E45\u306A\u6E1B\u5C11\u304C\u3042\u308A\u307E\u3059\u3002\u8A18\u5E33\u5185\u5BB9\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u3002"
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
return diagnostics;
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
// src/rules/home-office/reasonable-ratio.ts
|
|
750
|
+
var DEFAULT_MAX_RATIO = 0.9;
|
|
751
|
+
var reasonableRatioRule = {
|
|
752
|
+
meta: {
|
|
753
|
+
id: "home-office/reasonable-ratio",
|
|
754
|
+
name: "\u5BB6\u4E8B\u6309\u5206\u7387\u306E\u59A5\u5F53\u6027",
|
|
755
|
+
description: "\u6E1B\u4FA1\u511F\u5374\u8CC7\u7523\u306E\u4E8B\u696D\u5C02\u7528\u5272\u5408\uFF08\u5BB6\u4E8B\u6309\u5206\u7387\uFF09\u304C\u59A5\u5F53\u306A\u7BC4\u56F2\u5185\u304B\u30C1\u30A7\u30C3\u30AF\u3057\u307E\u3059\u3002\u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u4E0A\u9650\u306F90%\u3067\u3059\u3002",
|
|
756
|
+
severity: "warning"
|
|
757
|
+
},
|
|
758
|
+
check(ctx) {
|
|
759
|
+
const diagnostics = [];
|
|
760
|
+
const assets = ctx.taxReturn.depreciationSchedule.assets;
|
|
761
|
+
const ruleConfig = ctx.config.rules[this.meta.id];
|
|
762
|
+
let maxRatio = DEFAULT_MAX_RATIO;
|
|
763
|
+
if (Array.isArray(ruleConfig) && typeof ruleConfig[1]?.maxRatio === "number") {
|
|
764
|
+
maxRatio = ruleConfig[1].maxRatio;
|
|
765
|
+
}
|
|
766
|
+
for (const asset of assets) {
|
|
767
|
+
if (asset.businessUseRatio > maxRatio) {
|
|
768
|
+
diagnostics.push({
|
|
769
|
+
ruleId: this.meta.id,
|
|
770
|
+
severity: this.meta.severity,
|
|
771
|
+
message: `\u300C${asset.name}\u300D\u306E\u4E8B\u696D\u5C02\u7528\u5272\u5408(${Math.round(asset.businessUseRatio * 100)}%)\u304C\u4E0A\u9650(${Math.round(maxRatio * 100)}%)\u3092\u8D85\u3048\u3066\u3044\u307E\u3059`,
|
|
772
|
+
details: "\u5BB6\u4E8B\u6309\u5206\u7387\u304C\u9AD8\u3059\u304E\u308B\u5834\u5408\u3001\u7A0E\u52D9\u8ABF\u67FB\u3067\u5426\u8A8D\u3055\u308C\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u5B9F\u614B\u306B\u5373\u3057\u305F\u5272\u5408\u3092\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return diagnostics;
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
// src/rules/index.ts
|
|
781
|
+
var ruleRegistry = /* @__PURE__ */ new Map();
|
|
782
|
+
function registerRule(rule) {
|
|
783
|
+
ruleRegistry.set(rule.meta.id, rule);
|
|
784
|
+
}
|
|
785
|
+
function getAllRules() {
|
|
786
|
+
return [...ruleRegistry.values()];
|
|
787
|
+
}
|
|
788
|
+
function getRule(id) {
|
|
789
|
+
return ruleRegistry.get(id);
|
|
790
|
+
}
|
|
791
|
+
registerRule(bsEquationRule);
|
|
792
|
+
registerRule(openingOwnerEquityRule);
|
|
793
|
+
registerRule(motoireKinFormulaRule);
|
|
794
|
+
registerRule(nonNegativeCashRule);
|
|
795
|
+
registerRule(plArithmeticChainRule);
|
|
796
|
+
registerRule(cogsCalculationRule);
|
|
797
|
+
registerRule(expenseTotalRule);
|
|
798
|
+
registerRule(bsPlBridgeRule);
|
|
799
|
+
registerRule(decisionToReturnRule);
|
|
800
|
+
registerRule(depreciationSumRule);
|
|
801
|
+
registerRule(blueDeductionCapRule);
|
|
802
|
+
registerRule(blueDeductionEligibilityRule);
|
|
803
|
+
registerRule(usefulLifeRatesRule);
|
|
804
|
+
registerRule(smallAssetThresholdRule);
|
|
805
|
+
registerRule(openingClosingMatchRule);
|
|
806
|
+
registerRule(yearOverYearChangeRule);
|
|
807
|
+
registerRule(reasonableRatioRule);
|
|
808
|
+
|
|
809
|
+
// src/config/index.ts
|
|
810
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
811
|
+
import { resolve } from "path";
|
|
812
|
+
|
|
813
|
+
// src/utils/errors.ts
|
|
814
|
+
var ConfigError = class extends Error {
|
|
815
|
+
constructor(message, configPath) {
|
|
816
|
+
super(message);
|
|
817
|
+
this.configPath = configPath;
|
|
818
|
+
this.name = "ConfigError";
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
// src/config/defaults.ts
|
|
823
|
+
var defaultConfig = {
|
|
824
|
+
rules: {},
|
|
825
|
+
format: "stylish",
|
|
826
|
+
warningsAsErrors: false
|
|
827
|
+
};
|
|
828
|
+
|
|
829
|
+
// src/config/schema.ts
|
|
830
|
+
import { z } from "zod";
|
|
831
|
+
var severitySchema = z.enum(["error", "warning", "info", "off"]);
|
|
832
|
+
var ruleValueSchema = z.union([
|
|
833
|
+
severitySchema,
|
|
834
|
+
z.tuple([severitySchema, z.record(z.unknown())])
|
|
835
|
+
]);
|
|
836
|
+
var configSchema = z.object({
|
|
837
|
+
rules: z.record(ruleValueSchema).default({}),
|
|
838
|
+
priorYearFile: z.string().optional(),
|
|
839
|
+
format: z.enum(["stylish", "json"]).default("stylish"),
|
|
840
|
+
warningsAsErrors: z.boolean().default(false)
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
// src/config/index.ts
|
|
844
|
+
async function loadConfig(configPath) {
|
|
845
|
+
if (!configPath) {
|
|
846
|
+
const defaultPath = resolve(process.cwd(), ".zeicheckrc.json");
|
|
847
|
+
try {
|
|
848
|
+
return await readConfigFile(defaultPath);
|
|
849
|
+
} catch {
|
|
850
|
+
return defaultConfig;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return readConfigFile(configPath);
|
|
854
|
+
}
|
|
855
|
+
async function readConfigFile(filePath) {
|
|
856
|
+
let raw;
|
|
857
|
+
try {
|
|
858
|
+
raw = await readFile2(filePath, "utf-8");
|
|
859
|
+
} catch {
|
|
860
|
+
throw new ConfigError(`\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${filePath}`, filePath);
|
|
861
|
+
}
|
|
862
|
+
let parsed;
|
|
863
|
+
try {
|
|
864
|
+
parsed = JSON.parse(raw);
|
|
865
|
+
} catch {
|
|
866
|
+
throw new ConfigError(
|
|
867
|
+
`\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306EJSON\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${filePath}`,
|
|
868
|
+
filePath
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
const result = configSchema.safeParse(parsed);
|
|
872
|
+
if (!result.success) {
|
|
873
|
+
const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
874
|
+
throw new ConfigError(
|
|
875
|
+
`\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306E\u30D0\u30EA\u30C7\u30FC\u30B7\u30E7\u30F3\u306B\u5931\u6557\u3057\u307E\u3057\u305F:
|
|
876
|
+
${issues}`,
|
|
877
|
+
filePath
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
return result.data;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// src/cli/formatter/stylish.ts
|
|
884
|
+
import pc from "picocolors";
|
|
885
|
+
function colorSeverity(severity) {
|
|
886
|
+
switch (severity) {
|
|
887
|
+
case "error":
|
|
888
|
+
return pc.red(severity);
|
|
889
|
+
case "warning":
|
|
890
|
+
return pc.yellow(severity);
|
|
891
|
+
case "info":
|
|
892
|
+
return pc.blue(severity);
|
|
893
|
+
default:
|
|
894
|
+
return severity;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
function padRight(str, len) {
|
|
898
|
+
return str + " ".repeat(Math.max(0, len - str.length));
|
|
899
|
+
}
|
|
900
|
+
var stylishFormatter = {
|
|
901
|
+
format(input) {
|
|
902
|
+
const { filePath, diagnostics } = input;
|
|
903
|
+
let errorCount = 0;
|
|
904
|
+
let warningCount = 0;
|
|
905
|
+
let infoCount = 0;
|
|
906
|
+
for (const d of diagnostics) {
|
|
907
|
+
if (d.severity === "error") errorCount++;
|
|
908
|
+
else if (d.severity === "warning") warningCount++;
|
|
909
|
+
else if (d.severity === "info") infoCount++;
|
|
910
|
+
}
|
|
911
|
+
if (diagnostics.length === 0) {
|
|
912
|
+
return { output: "", errorCount: 0, warningCount: 0, infoCount: 0 };
|
|
913
|
+
}
|
|
914
|
+
const lines = [];
|
|
915
|
+
lines.push("");
|
|
916
|
+
lines.push(pc.underline(filePath));
|
|
917
|
+
lines.push("");
|
|
918
|
+
const maxRuleIdLen = Math.max(
|
|
919
|
+
...diagnostics.map((d) => d.ruleId.length)
|
|
920
|
+
);
|
|
921
|
+
const maxSeverityLen = 7;
|
|
922
|
+
for (const diag of diagnostics) {
|
|
923
|
+
const ruleId = padRight(diag.ruleId, maxRuleIdLen);
|
|
924
|
+
const severity = padRight(diag.severity, maxSeverityLen);
|
|
925
|
+
lines.push(
|
|
926
|
+
` ${ruleId} ${colorSeverity(diag.severity)}${" ".repeat(maxSeverityLen - diag.severity.length)} ${diag.message}`
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
lines.push("");
|
|
930
|
+
const total = diagnostics.length;
|
|
931
|
+
const summary = `${pc.bold(errorCount > 0 ? pc.red(`\u2716 ${total} \u4EF6\u306E\u554F\u984C`) : `\u2716 ${total} \u4EF6\u306E\u554F\u984C`)} (${errorCount} errors, ${warningCount} warnings)`;
|
|
932
|
+
lines.push(summary);
|
|
933
|
+
return {
|
|
934
|
+
output: lines.join("\n"),
|
|
935
|
+
errorCount,
|
|
936
|
+
warningCount,
|
|
937
|
+
infoCount
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
// src/cli/formatter/json.ts
|
|
943
|
+
var jsonFormatter = {
|
|
944
|
+
format(input) {
|
|
945
|
+
const { filePath, diagnostics } = input;
|
|
946
|
+
let errorCount = 0;
|
|
947
|
+
let warningCount = 0;
|
|
948
|
+
let infoCount = 0;
|
|
949
|
+
for (const d of diagnostics) {
|
|
950
|
+
if (d.severity === "error") errorCount++;
|
|
951
|
+
else if (d.severity === "warning") warningCount++;
|
|
952
|
+
else if (d.severity === "info") infoCount++;
|
|
953
|
+
}
|
|
954
|
+
const output = JSON.stringify(
|
|
955
|
+
{
|
|
956
|
+
filePath,
|
|
957
|
+
diagnostics,
|
|
958
|
+
summary: {
|
|
959
|
+
total: diagnostics.length,
|
|
960
|
+
errors: errorCount,
|
|
961
|
+
warnings: warningCount,
|
|
962
|
+
info: infoCount
|
|
963
|
+
}
|
|
964
|
+
},
|
|
965
|
+
null,
|
|
966
|
+
2
|
|
967
|
+
);
|
|
968
|
+
return { output, errorCount, warningCount, infoCount };
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
// src/cli/formatter/index.ts
|
|
973
|
+
function getFormatter(name) {
|
|
974
|
+
switch (name) {
|
|
975
|
+
case "json":
|
|
976
|
+
return jsonFormatter;
|
|
977
|
+
case "stylish":
|
|
978
|
+
default:
|
|
979
|
+
return stylishFormatter;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
export {
|
|
984
|
+
yen,
|
|
985
|
+
FormType,
|
|
986
|
+
parseXtxFile,
|
|
987
|
+
parseXtxString,
|
|
988
|
+
runRules,
|
|
989
|
+
getAllRules,
|
|
990
|
+
getRule,
|
|
991
|
+
loadConfig,
|
|
992
|
+
getFormatter
|
|
993
|
+
};
|
|
994
|
+
//# sourceMappingURL=chunk-LZZKQ7B2.js.map
|