@things-factory/asset 0.0.0-stage → 10.1.230
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/dist-client/components/asset-documents.d.ts +22 -0
- package/dist-client/components/asset-documents.js +190 -0
- package/dist-client/components/asset-documents.js.map +1 -0
- package/dist-client/grid.d.ts +13 -0
- package/dist-client/grid.js +56 -0
- package/dist-client/grid.js.map +1 -0
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/asset-list.d.ts +53 -0
- package/dist-client/pages/asset-list.js +171 -0
- package/dist-client/pages/asset-list.js.map +1 -0
- package/dist-client/pages/asset-reconciliation.d.ts +25 -0
- package/dist-client/pages/asset-reconciliation.js +165 -0
- package/dist-client/pages/asset-reconciliation.js.map +1 -0
- package/dist-client/pages/investee-page.d.ts +47 -0
- package/dist-client/pages/investee-page.js +322 -0
- package/dist-client/pages/investee-page.js.map +1 -0
- package/dist-client/pages/investment-list.d.ts +51 -0
- package/dist-client/pages/investment-list.js +134 -0
- package/dist-client/pages/investment-list.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +18 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-client/words.d.ts +25 -0
- package/dist-client/words.js +23 -0
- package/dist-client/words.js.map +1 -0
- package/dist-server/attachment-reader.d.ts +3 -0
- package/dist-server/attachment-reader.js +20 -0
- package/dist-server/attachment-reader.js.map +1 -0
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +11 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/role-tasks.d.ts +2 -0
- package/dist-server/role-tasks.js +13 -0
- package/dist-server/role-tasks.js.map +1 -0
- package/dist-server/service/asset/asset-mutation.d.ts +5 -0
- package/dist-server/service/asset/asset-mutation.js +31 -0
- package/dist-server/service/asset/asset-mutation.js.map +1 -0
- package/dist-server/service/asset/asset-query.d.ts +19 -0
- package/dist-server/service/asset/asset-query.js +108 -0
- package/dist-server/service/asset/asset-query.js.map +1 -0
- package/dist-server/service/asset/asset-rules.d.ts +87 -0
- package/dist-server/service/asset/asset-rules.js +148 -0
- package/dist-server/service/asset/asset-rules.js.map +1 -0
- package/dist-server/service/asset/asset-service.d.ts +23 -0
- package/dist-server/service/asset/asset-service.js +84 -0
- package/dist-server/service/asset/asset-service.js.map +1 -0
- package/dist-server/service/asset/asset-type.d.ts +48 -0
- package/dist-server/service/asset/asset-type.js +182 -0
- package/dist-server/service/asset/asset-type.js.map +1 -0
- package/dist-server/service/asset/asset.d.ts +38 -0
- package/dist-server/service/asset/asset.js +159 -0
- package/dist-server/service/asset/asset.js.map +1 -0
- package/dist-server/service/asset/index.d.ts +6 -0
- package/dist-server/service/asset/index.js +10 -0
- package/dist-server/service/asset/index.js.map +1 -0
- package/dist-server/service/asset-document/asset-document-resolver.d.ts +32 -0
- package/dist-server/service/asset-document/asset-document-resolver.js +94 -0
- package/dist-server/service/asset-document/asset-document-resolver.js.map +1 -0
- package/dist-server/service/asset-document/asset-document-service.d.ts +34 -0
- package/dist-server/service/asset-document/asset-document-service.js +79 -0
- package/dist-server/service/asset-document/asset-document-service.js.map +1 -0
- package/dist-server/service/asset-document/index.d.ts +4 -0
- package/dist-server/service/asset-document/index.js +8 -0
- package/dist-server/service/asset-document/index.js.map +1 -0
- package/dist-server/service/checks.d.ts +12 -0
- package/dist-server/service/checks.js +27 -0
- package/dist-server/service/checks.js.map +1 -0
- package/dist-server/service/index.d.ts +18 -0
- package/dist-server/service/index.js +40 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/investment/index.d.ts +11 -0
- package/dist-server/service/investment/index.js +15 -0
- package/dist-server/service/investment/index.js.map +1 -0
- package/dist-server/service/investment/investee.d.ts +33 -0
- package/dist-server/service/investment/investee.js +135 -0
- package/dist-server/service/investment/investee.js.map +1 -0
- package/dist-server/service/investment/investment-board-seat.d.ts +25 -0
- package/dist-server/service/investment/investment-board-seat.js +98 -0
- package/dist-server/service/investment/investment-board-seat.js.map +1 -0
- package/dist-server/service/investment/investment-filing.d.ts +29 -0
- package/dist-server/service/investment/investment-filing.js +113 -0
- package/dist-server/service/investment/investment-filing.js.map +1 -0
- package/dist-server/service/investment/investment-holding.d.ts +31 -0
- package/dist-server/service/investment/investment-holding.js +127 -0
- package/dist-server/service/investment/investment-holding.js.map +1 -0
- package/dist-server/service/investment/investment-mutation.d.ts +15 -0
- package/dist-server/service/investment/investment-mutation.js +112 -0
- package/dist-server/service/investment/investment-mutation.js.map +1 -0
- package/dist-server/service/investment/investment-query.d.ts +33 -0
- package/dist-server/service/investment/investment-query.js +192 -0
- package/dist-server/service/investment/investment-query.js.map +1 -0
- package/dist-server/service/investment/investment-report.d.ts +37 -0
- package/dist-server/service/investment/investment-report.js +152 -0
- package/dist-server/service/investment/investment-report.js.map +1 -0
- package/dist-server/service/investment/investment-request.d.ts +31 -0
- package/dist-server/service/investment/investment-request.js +123 -0
- package/dist-server/service/investment/investment-request.js.map +1 -0
- package/dist-server/service/investment/investment-rules.d.ts +81 -0
- package/dist-server/service/investment/investment-rules.js +121 -0
- package/dist-server/service/investment/investment-rules.js.map +1 -0
- package/dist-server/service/investment/investment-service.d.ts +34 -0
- package/dist-server/service/investment/investment-service.js +280 -0
- package/dist-server/service/investment/investment-service.js.map +1 -0
- package/dist-server/service/investment/investment-type.d.ts +85 -0
- package/dist-server/service/investment/investment-type.js +324 -0
- package/dist-server/service/investment/investment-type.js.map +1 -0
- package/dist-server/service/patches.d.ts +24 -0
- package/dist-server/service/patches.js +63 -0
- package/dist-server/service/patches.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +49 -4
- package/things-factory.config.js +11 -0
- package/translations/en.json +188 -0
- package/translations/es.json +188 -0
- package/translations/ja.json +188 -0
- package/translations/ko.json +188 -0
- package/translations/ms.json +188 -0
- package/translations/zh.json +188 -0
- package/README.md +0 -3
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* The work this module names, for the seats applications build (ADR-0139 decision 11, ADR-0175 decision 2).
|
|
4
|
+
*
|
|
5
|
+
* Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ROLE_TASKS = void 0;
|
|
9
|
+
exports.ROLE_TASKS = [
|
|
10
|
+
{ id: 'asset.reading', grants: [{ category: 'asset', axes: ['query'] }] },
|
|
11
|
+
{ id: 'asset.keeping', grants: [{ category: 'asset', axes: ['query', 'mutation'] }] }
|
|
12
|
+
];
|
|
13
|
+
//# sourceMappingURL=role-tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-tasks.js","sourceRoot":"","sources":["../server/role-tasks.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAIU,QAAA,UAAU,GAAe;IACpC,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;IACzE,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;CACtF,CAAA","sourcesContent":["/*\n * The work this module names, for the seats applications build (ADR-0139 decision 11, ADR-0175 decision 2).\n *\n * Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.\n */\n\nimport type { RoleTask } from '@things-factory/auth-base'\n\nexport const ROLE_TASKS: RoleTask[] = [\n { id: 'asset.reading', grants: [{ category: 'asset', axes: ['query'] }] },\n { id: 'asset.keeping', grants: [{ category: 'asset', axes: ['query', 'mutation'] }] }\n]\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AssetMutation = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const shell_1 = require("@things-factory/shell");
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const asset_1 = require("./asset");
|
|
8
|
+
const asset_service_1 = require("./asset-service");
|
|
9
|
+
const asset_type_1 = require("./asset-type");
|
|
10
|
+
let AssetMutation = class AssetMutation {
|
|
11
|
+
updateMultipleAsset(patches, context) {
|
|
12
|
+
const { tx, domain, user } = context.state;
|
|
13
|
+
return (0, asset_service_1.saveAssets)(tx, domain, user, patches);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
exports.AssetMutation = AssetMutation;
|
|
17
|
+
tslib_1.__decorate([
|
|
18
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
19
|
+
(0, type_graphql_1.Directive)('@privilege(category: "asset", privilege: "mutation", domainOwnerGranted: true)'),
|
|
20
|
+
(0, type_graphql_1.Mutation)(type => [asset_1.Asset], { description: 'To save the asset register grid - new, changed and deleted rows together' }),
|
|
21
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [asset_type_1.AssetPatch])),
|
|
22
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
23
|
+
tslib_1.__metadata("design:type", Function),
|
|
24
|
+
tslib_1.__metadata("design:paramtypes", [Array, Object]),
|
|
25
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
26
|
+
], AssetMutation.prototype, "updateMultipleAsset", null);
|
|
27
|
+
exports.AssetMutation = AssetMutation = tslib_1.__decorate([
|
|
28
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
|
|
29
|
+
(0, type_graphql_1.Resolver)(asset_1.Asset)
|
|
30
|
+
], AssetMutation);
|
|
31
|
+
//# sourceMappingURL=asset-mutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-mutation.js","sourceRoot":"","sources":["../../../server/service/asset/asset-mutation.ts"],"names":[],"mappings":";;;;AAAA,iDAAqD;AACrD,+CAAqF;AAErF,mCAA+B;AAC/B,mDAA4C;AAC5C,6CAAyC;AAIlC,IAAM,aAAa,GAAnB,MAAM,aAAa;IAIxB,mBAAmB,CAAuC,OAAqB,EAAS,OAAwB;QAC9G,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,OAAO,IAAA,0BAAU,EAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;CACF,CAAA;AARY,sCAAa;AAIxB;IAHC,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,gFAAgF,CAAC;IAC3F,IAAA,uBAAQ,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,aAAK,CAAC,EAAE,EAAE,WAAW,EAAE,0EAA0E,EAAE,CAAC;IAClG,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,CAAC,CAAA;IAAyB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;wDAGtF;wBAPU,aAAa;IAFzB,IAAA,4BAAa,EAAC,qBAAa,CAAC;IAC5B,IAAA,uBAAQ,EAAC,aAAK,CAAC;GACH,aAAa,CAQzB","sourcesContent":["import { SpeakRefusals } from '@things-factory/shell'\nimport { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { Asset } from './asset'\nimport { saveAssets } from './asset-service'\nimport { AssetPatch } from './asset-type'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(Asset)\nexport class AssetMutation {\n @Directive('@transaction')\n @Directive('@privilege(category: \"asset\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(type => [Asset], { description: 'To save the asset register grid - new, changed and deleted rows together' })\n updateMultipleAsset(@Arg('patches', type => [AssetPatch]) patches: AssetPatch[], @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return saveAssets(tx, domain, user, patches)\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { User } from '@things-factory/auth-base';
|
|
2
|
+
import { Domain, ListParam } from '@things-factory/shell';
|
|
3
|
+
import { Asset } from './asset';
|
|
4
|
+
import { AssetList, AssetYear } from './asset-type';
|
|
5
|
+
export declare class AssetQuery {
|
|
6
|
+
asset(id: string, context: ResolverContext): Promise<Asset>;
|
|
7
|
+
assets(params: ListParam, context: ResolverContext): Promise<AssetList>;
|
|
8
|
+
assetReconciliation(fiscalYear: number, context: ResolverContext): Promise<{
|
|
9
|
+
fiscalYear: number;
|
|
10
|
+
filed: boolean;
|
|
11
|
+
rows: (import("./asset-rules").ReconciliationRow & {
|
|
12
|
+
differs: boolean;
|
|
13
|
+
})[];
|
|
14
|
+
}>;
|
|
15
|
+
year(asset: Asset, fiscalYear?: number): AssetYear;
|
|
16
|
+
domain(row: Asset): Domain | Promise<Domain>;
|
|
17
|
+
creator(row: Asset): User | Promise<User>;
|
|
18
|
+
updater(row: Asset): User | Promise<User>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AssetQuery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
|
+
const type_graphql_1 = require("type-graphql");
|
|
8
|
+
const asset_document_service_1 = require("../asset-document/asset-document-service");
|
|
9
|
+
const asset_1 = require("./asset");
|
|
10
|
+
const asset_rules_1 = require("./asset-rules");
|
|
11
|
+
const asset_service_1 = require("./asset-service");
|
|
12
|
+
const asset_type_1 = require("./asset-type");
|
|
13
|
+
let AssetQuery = class AssetQuery {
|
|
14
|
+
asset(id, context) {
|
|
15
|
+
return (0, shell_1.getRepository)(asset_1.Asset).findOne({ where: { id, domain: { id: context.state.domain.id } } });
|
|
16
|
+
}
|
|
17
|
+
async assets(params, context) {
|
|
18
|
+
const { domain } = context.state;
|
|
19
|
+
const query = (0, shell_1.getQueryBuilderFromListParams)({
|
|
20
|
+
domain,
|
|
21
|
+
params,
|
|
22
|
+
repository: (0, shell_1.getRepository)(asset_1.Asset),
|
|
23
|
+
searchables: ['name', 'location', 'keeper', 'source', 'project', 'description']
|
|
24
|
+
});
|
|
25
|
+
const [items, total] = await query.getManyAndCount();
|
|
26
|
+
const counts = await (0, asset_document_service_1.documentCounts)((0, shell_1.getRepository)(asset_1.Asset).manager, domain, 'Asset', items.map(one => one.id));
|
|
27
|
+
for (const one of items)
|
|
28
|
+
one.documents = counts.get(one.id) ?? 0;
|
|
29
|
+
return { items, total };
|
|
30
|
+
}
|
|
31
|
+
assetReconciliation(fiscalYear, context) {
|
|
32
|
+
return (0, asset_service_1.assetReconciliation)((0, shell_1.getRepository)(asset_1.Asset).manager, context.state.domain, fiscalYear);
|
|
33
|
+
}
|
|
34
|
+
year(asset, fiscalYear) {
|
|
35
|
+
return (0, asset_rules_1.depreciationOf)(asset, fiscalYear ?? new Date().getFullYear());
|
|
36
|
+
}
|
|
37
|
+
domain(row) {
|
|
38
|
+
return row.domain ?? (row.domainId ? (0, shell_1.getRepository)(shell_1.Domain).findOneBy({ id: row.domainId }) : undefined);
|
|
39
|
+
}
|
|
40
|
+
creator(row) {
|
|
41
|
+
return row.creator ?? (row.creatorId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: row.creatorId }) : undefined);
|
|
42
|
+
}
|
|
43
|
+
updater(row) {
|
|
44
|
+
return row.updater ?? (row.updaterId ? (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: row.updaterId }) : undefined);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
exports.AssetQuery = AssetQuery;
|
|
48
|
+
tslib_1.__decorate([
|
|
49
|
+
(0, type_graphql_1.Directive)('@privilege(category: "asset", privilege: "query", domainOwnerGranted: true)'),
|
|
50
|
+
(0, type_graphql_1.Query)(type => asset_1.Asset, { nullable: true, description: 'To fetch an asset' }),
|
|
51
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
52
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
53
|
+
tslib_1.__metadata("design:type", Function),
|
|
54
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
55
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
56
|
+
], AssetQuery.prototype, "asset", null);
|
|
57
|
+
tslib_1.__decorate([
|
|
58
|
+
(0, type_graphql_1.Directive)('@privilege(category: "asset", privilege: "query", domainOwnerGranted: true)'),
|
|
59
|
+
(0, type_graphql_1.Query)(type => asset_type_1.AssetList, { description: 'To fetch a page of the asset register' }),
|
|
60
|
+
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
61
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
62
|
+
tslib_1.__metadata("design:type", Function),
|
|
63
|
+
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
64
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
65
|
+
], AssetQuery.prototype, "assets", null);
|
|
66
|
+
tslib_1.__decorate([
|
|
67
|
+
(0, type_graphql_1.Directive)('@privilege(category: "asset", privilege: "query", domainOwnerGranted: true)'),
|
|
68
|
+
(0, type_graphql_1.Query)(type => asset_type_1.AssetReconciliation, { description: 'The register beside the filed balance sheet of a fiscal year' }),
|
|
69
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('fiscalYear', type => type_graphql_1.Int)),
|
|
70
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
71
|
+
tslib_1.__metadata("design:type", Function),
|
|
72
|
+
tslib_1.__metadata("design:paramtypes", [Number, Object]),
|
|
73
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
74
|
+
], AssetQuery.prototype, "assetReconciliation", null);
|
|
75
|
+
tslib_1.__decorate([
|
|
76
|
+
(0, type_graphql_1.FieldResolver)(type => asset_type_1.AssetYear, { description: "The asset's depreciation for a fiscal year - this year when not given" }),
|
|
77
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
78
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('fiscalYear', type => type_graphql_1.Int, { nullable: true })),
|
|
79
|
+
tslib_1.__metadata("design:type", Function),
|
|
80
|
+
tslib_1.__metadata("design:paramtypes", [asset_1.Asset, Number]),
|
|
81
|
+
tslib_1.__metadata("design:returntype", asset_type_1.AssetYear)
|
|
82
|
+
], AssetQuery.prototype, "year", null);
|
|
83
|
+
tslib_1.__decorate([
|
|
84
|
+
(0, type_graphql_1.FieldResolver)(type => shell_1.Domain, { nullable: true }),
|
|
85
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
86
|
+
tslib_1.__metadata("design:type", Function),
|
|
87
|
+
tslib_1.__metadata("design:paramtypes", [asset_1.Asset]),
|
|
88
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
89
|
+
], AssetQuery.prototype, "domain", null);
|
|
90
|
+
tslib_1.__decorate([
|
|
91
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
|
|
92
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
93
|
+
tslib_1.__metadata("design:type", Function),
|
|
94
|
+
tslib_1.__metadata("design:paramtypes", [asset_1.Asset]),
|
|
95
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
96
|
+
], AssetQuery.prototype, "creator", null);
|
|
97
|
+
tslib_1.__decorate([
|
|
98
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
|
|
99
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
100
|
+
tslib_1.__metadata("design:type", Function),
|
|
101
|
+
tslib_1.__metadata("design:paramtypes", [asset_1.Asset]),
|
|
102
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
103
|
+
], AssetQuery.prototype, "updater", null);
|
|
104
|
+
exports.AssetQuery = AssetQuery = tslib_1.__decorate([
|
|
105
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
|
|
106
|
+
(0, type_graphql_1.Resolver)(asset_1.Asset)
|
|
107
|
+
], AssetQuery);
|
|
108
|
+
//# sourceMappingURL=asset-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-query.js","sourceRoot":"","sources":["../../../server/service/asset/asset-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Int, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\n\nimport { documentCounts } from '../asset-document/asset-document-service'\nimport { Asset } from './asset'\nimport { depreciationOf } from './asset-rules'\nimport { assetReconciliation } from './asset-service'\nimport { AssetList, AssetReconciliation, AssetYear } from './asset-type'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(Asset)\nexport class AssetQuery {\n @Directive('@privilege(category: \"asset\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => Asset, { nullable: true, description: 'To fetch an asset' })\n asset(@Arg('id') id: string, @Ctx() context: ResolverContext) {\n return getRepository(Asset).findOne({ where: { id, domain: { id: context.state.domain.id } } })\n }\n\n @Directive('@privilege(category: \"asset\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => AssetList, { description: 'To fetch a page of the asset register' })\n async assets(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<AssetList> {\n const { domain } = context.state\n const query = getQueryBuilderFromListParams({\n domain,\n params,\n repository: getRepository(Asset),\n searchables: ['name', 'location', 'keeper', 'source', 'project', 'description']\n })\n const [items, total] = await query.getManyAndCount()\n const counts = await documentCounts(getRepository(Asset).manager, domain, 'Asset', items.map(one => one.id))\n for (const one of items) one.documents = counts.get(one.id) ?? 0\n return { items, total }\n }\n\n @Directive('@privilege(category: \"asset\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(type => AssetReconciliation, { description: 'The register beside the filed balance sheet of a fiscal year' })\n assetReconciliation(@Arg('fiscalYear', type => Int) fiscalYear: number, @Ctx() context: ResolverContext) {\n return assetReconciliation(getRepository(Asset).manager, context.state.domain, fiscalYear)\n }\n\n @FieldResolver(type => AssetYear, { description: \"The asset's depreciation for a fiscal year - this year when not given\" })\n year(@Root() asset: Asset, @Arg('fiscalYear', type => Int, { nullable: true }) fiscalYear?: number): AssetYear {\n return depreciationOf(asset, fiscalYear ?? new Date().getFullYear())\n }\n\n @FieldResolver(type => Domain, { nullable: true })\n domain(@Root() row: Asset) {\n return row.domain ?? (row.domainId ? getRepository(Domain).findOneBy({ id: row.domainId }) : undefined)\n }\n\n @FieldResolver(type => User, { nullable: true })\n creator(@Root() row: Asset) {\n return row.creator ?? (row.creatorId ? getRepository(User).findOneBy({ id: row.creatorId }) : undefined)\n }\n\n @FieldResolver(type => User, { nullable: true })\n updater(@Root() row: Asset) {\n return row.updater ?? (row.updaterId ? getRepository(User).findOneBy({ id: row.updaterId }) : undefined)\n }\n}\n"]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export declare enum AssetKind {
|
|
2
|
+
LAND = "LAND",
|
|
3
|
+
BUILDING = "BUILDING",
|
|
4
|
+
MACHINERY = "MACHINERY",
|
|
5
|
+
VEHICLE = "VEHICLE",
|
|
6
|
+
FURNITURE = "FURNITURE",
|
|
7
|
+
FACILITY = "FACILITY",
|
|
8
|
+
DEVELOPMENT_COST = "DEVELOPMENT_COST",
|
|
9
|
+
SOFTWARE = "SOFTWARE",
|
|
10
|
+
OTHER_INTANGIBLE = "OTHER_INTANGIBLE"
|
|
11
|
+
}
|
|
12
|
+
export declare enum AssetStatus {
|
|
13
|
+
IN_USE = "IN_USE",
|
|
14
|
+
DISPOSED = "DISPOSED",
|
|
15
|
+
SCRAPPED = "SCRAPPED"
|
|
16
|
+
}
|
|
17
|
+
export declare enum DepreciationMethod {
|
|
18
|
+
STRAIGHT_LINE = "STRAIGHT_LINE",
|
|
19
|
+
DECLINING_BALANCE = "DECLINING_BALANCE",
|
|
20
|
+
NONE = "NONE"
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The line of the standard balance sheet (표준재무제표) each kind is filed under, as accounting reads it
|
|
24
|
+
* (`FinancialStatementLine.code`). An asset may name another; a kind without one names its own.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_STATEMENT_CODE: Record<AssetKind, string | null>;
|
|
27
|
+
/** Land is not depreciated; everything else straight line unless written. */
|
|
28
|
+
export declare const defaultMethodOf: (kind: AssetKind | string) => DepreciationMethod.STRAIGHT_LINE | DepreciationMethod.NONE;
|
|
29
|
+
export declare const DATE: RegExp;
|
|
30
|
+
/** What depreciation reads of an asset. */
|
|
31
|
+
export type Depreciable = {
|
|
32
|
+
cost: number;
|
|
33
|
+
residualValue?: number | null;
|
|
34
|
+
method: DepreciationMethod | string;
|
|
35
|
+
usefulLifeYears?: number | null;
|
|
36
|
+
declineRate?: number | null;
|
|
37
|
+
acquiredOn: string;
|
|
38
|
+
depreciationStartOn?: string | null;
|
|
39
|
+
status?: AssetStatus | string;
|
|
40
|
+
disposedOn?: string | null;
|
|
41
|
+
};
|
|
42
|
+
export type YearDepreciation = {
|
|
43
|
+
fiscalYear: number;
|
|
44
|
+
expense: number;
|
|
45
|
+
accumulated: number;
|
|
46
|
+
bookValue: number;
|
|
47
|
+
};
|
|
48
|
+
/** Whether the asset is on the balance sheet at the end of the year: acquired by then, not yet disposed of or scrapped. */
|
|
49
|
+
export declare function heldAtYearEnd(asset: Pick<Depreciable, 'acquiredOn' | 'status' | 'disposedOn'>, fiscalYear: number): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* The depreciation of an asset for a fiscal year (January to December) - computed, never stored (decision 4).
|
|
52
|
+
*
|
|
53
|
+
* Month by month from the month it starts, through the month it is disposed of. Straight line spreads cost less residual
|
|
54
|
+
* value over the useful life; declining balance takes the rate of the book value each year, the first and the last year
|
|
55
|
+
* in proportion to their months, and never below the residual value. The useful life and the rate are what the books
|
|
56
|
+
* use - this neither looks them up nor checks them against the tax law.
|
|
57
|
+
*/
|
|
58
|
+
export declare function depreciationOf(asset: Depreciable, fiscalYear: number): YearDepreciation;
|
|
59
|
+
/** A line of the filed balance sheet, as accounting keeps it. */
|
|
60
|
+
export type StatementLine = {
|
|
61
|
+
code: string;
|
|
62
|
+
name: string;
|
|
63
|
+
amount: number;
|
|
64
|
+
contra?: boolean;
|
|
65
|
+
rank: number;
|
|
66
|
+
};
|
|
67
|
+
export type ReconciliationRow = {
|
|
68
|
+
code: string;
|
|
69
|
+
name: string;
|
|
70
|
+
assets: number;
|
|
71
|
+
registerCost: number;
|
|
72
|
+
registerAccumulated: number;
|
|
73
|
+
statementCost: number | null;
|
|
74
|
+
statementAccumulated: number | null;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The register beside the filed balance sheet, line by line (decision 5). A line's accumulated depreciation is the contra
|
|
78
|
+
* line of the next code (122 machinery, 123 its accumulated depreciation) - the filed order can put it elsewhere. The lines are the kinds' own and whatever an asset names; a line the books carry and the register
|
|
79
|
+
* does not is shown too - that is the difference to look at. Nothing is changed: a difference is the accountant's to
|
|
80
|
+
* explain.
|
|
81
|
+
*/
|
|
82
|
+
export declare function reconcile(assets: (Depreciable & {
|
|
83
|
+
statementCode?: string | null;
|
|
84
|
+
kind: AssetKind | string;
|
|
85
|
+
})[], lines: StatementLine[] | null, fiscalYear: number): ReconciliationRow[];
|
|
86
|
+
/** Whether a row of the reconciliation differs - the register and the books do not say the same. */
|
|
87
|
+
export declare const differs: (row: ReconciliationRow) => boolean;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.differs = exports.DATE = exports.defaultMethodOf = exports.DEFAULT_STATEMENT_CODE = exports.DepreciationMethod = exports.AssetStatus = exports.AssetKind = void 0;
|
|
4
|
+
exports.heldAtYearEnd = heldAtYearEnd;
|
|
5
|
+
exports.depreciationOf = depreciationOf;
|
|
6
|
+
exports.reconcile = reconcile;
|
|
7
|
+
const type_graphql_1 = require("type-graphql");
|
|
8
|
+
/*
|
|
9
|
+
* The asset register's rules (ADR-0175 decisions 3-5) - apart from the entity, so the screens' words and the tests read
|
|
10
|
+
* them without a type-graphql class. Pure.
|
|
11
|
+
*/
|
|
12
|
+
var AssetKind;
|
|
13
|
+
(function (AssetKind) {
|
|
14
|
+
AssetKind["LAND"] = "LAND";
|
|
15
|
+
AssetKind["BUILDING"] = "BUILDING";
|
|
16
|
+
AssetKind["MACHINERY"] = "MACHINERY";
|
|
17
|
+
AssetKind["VEHICLE"] = "VEHICLE";
|
|
18
|
+
AssetKind["FURNITURE"] = "FURNITURE";
|
|
19
|
+
AssetKind["FACILITY"] = "FACILITY";
|
|
20
|
+
AssetKind["DEVELOPMENT_COST"] = "DEVELOPMENT_COST";
|
|
21
|
+
AssetKind["SOFTWARE"] = "SOFTWARE";
|
|
22
|
+
AssetKind["OTHER_INTANGIBLE"] = "OTHER_INTANGIBLE";
|
|
23
|
+
})(AssetKind || (exports.AssetKind = AssetKind = {}));
|
|
24
|
+
(0, type_graphql_1.registerEnumType)(AssetKind, { name: 'AssetKind', description: 'What an asset is - land, a building, machinery, a vehicle, furniture, a facility, development cost, software or another intangible' });
|
|
25
|
+
var AssetStatus;
|
|
26
|
+
(function (AssetStatus) {
|
|
27
|
+
AssetStatus["IN_USE"] = "IN_USE";
|
|
28
|
+
AssetStatus["DISPOSED"] = "DISPOSED";
|
|
29
|
+
AssetStatus["SCRAPPED"] = "SCRAPPED";
|
|
30
|
+
})(AssetStatus || (exports.AssetStatus = AssetStatus = {}));
|
|
31
|
+
(0, type_graphql_1.registerEnumType)(AssetStatus, { name: 'AssetStatus', description: 'Whether an asset is in use, disposed of (sold) or scrapped' });
|
|
32
|
+
var DepreciationMethod;
|
|
33
|
+
(function (DepreciationMethod) {
|
|
34
|
+
DepreciationMethod["STRAIGHT_LINE"] = "STRAIGHT_LINE";
|
|
35
|
+
DepreciationMethod["DECLINING_BALANCE"] = "DECLINING_BALANCE";
|
|
36
|
+
DepreciationMethod["NONE"] = "NONE";
|
|
37
|
+
})(DepreciationMethod || (exports.DepreciationMethod = DepreciationMethod = {}));
|
|
38
|
+
(0, type_graphql_1.registerEnumType)(DepreciationMethod, { name: 'DepreciationMethod', description: 'How an asset is depreciated - straight line, declining balance, or not at all (land)' });
|
|
39
|
+
/**
|
|
40
|
+
* The line of the standard balance sheet (표준재무제표) each kind is filed under, as accounting reads it
|
|
41
|
+
* (`FinancialStatementLine.code`). An asset may name another; a kind without one names its own.
|
|
42
|
+
*/
|
|
43
|
+
exports.DEFAULT_STATEMENT_CODE = {
|
|
44
|
+
[AssetKind.LAND]: '111',
|
|
45
|
+
[AssetKind.BUILDING]: '114',
|
|
46
|
+
[AssetKind.MACHINERY]: '122',
|
|
47
|
+
[AssetKind.VEHICLE]: '134',
|
|
48
|
+
[AssetKind.FURNITURE]: '149',
|
|
49
|
+
[AssetKind.FACILITY]: '149',
|
|
50
|
+
[AssetKind.DEVELOPMENT_COST]: '184',
|
|
51
|
+
[AssetKind.SOFTWARE]: '186',
|
|
52
|
+
[AssetKind.OTHER_INTANGIBLE]: null
|
|
53
|
+
};
|
|
54
|
+
/** Land is not depreciated; everything else straight line unless written. */
|
|
55
|
+
const defaultMethodOf = (kind) => (kind === AssetKind.LAND ? DepreciationMethod.NONE : DepreciationMethod.STRAIGHT_LINE);
|
|
56
|
+
exports.defaultMethodOf = defaultMethodOf;
|
|
57
|
+
exports.DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
58
|
+
const monthOf = (date) => Number(date.slice(0, 4)) * 12 + Number(date.slice(5, 7)) - 1;
|
|
59
|
+
/** Whether the asset is on the balance sheet at the end of the year: acquired by then, not yet disposed of or scrapped. */
|
|
60
|
+
function heldAtYearEnd(asset, fiscalYear) {
|
|
61
|
+
const end = `${fiscalYear}-12-31`;
|
|
62
|
+
if (asset.acquiredOn > end)
|
|
63
|
+
return false;
|
|
64
|
+
return !(asset.status && asset.status !== AssetStatus.IN_USE && asset.disposedOn && asset.disposedOn <= end);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The depreciation of an asset for a fiscal year (January to December) - computed, never stored (decision 4).
|
|
68
|
+
*
|
|
69
|
+
* Month by month from the month it starts, through the month it is disposed of. Straight line spreads cost less residual
|
|
70
|
+
* value over the useful life; declining balance takes the rate of the book value each year, the first and the last year
|
|
71
|
+
* in proportion to their months, and never below the residual value. The useful life and the rate are what the books
|
|
72
|
+
* use - this neither looks them up nor checks them against the tax law.
|
|
73
|
+
*/
|
|
74
|
+
function depreciationOf(asset, fiscalYear) {
|
|
75
|
+
const cost = Number(asset.cost) || 0;
|
|
76
|
+
const residual = Math.min(Number(asset.residualValue) || 0, cost);
|
|
77
|
+
const base = cost - residual;
|
|
78
|
+
const accumulatedAt = (year) => {
|
|
79
|
+
const start = monthOf(asset.depreciationStartOn || asset.acquiredOn);
|
|
80
|
+
const disposed = asset.status && asset.status !== AssetStatus.IN_USE && asset.disposedOn ? monthOf(asset.disposedOn) : Infinity;
|
|
81
|
+
const last = Math.min(year * 12 + 11, disposed);
|
|
82
|
+
if (last < start || base <= 0)
|
|
83
|
+
return 0;
|
|
84
|
+
if (asset.method === DepreciationMethod.STRAIGHT_LINE) {
|
|
85
|
+
const life = Math.round((Number(asset.usefulLifeYears) || 0) * 12);
|
|
86
|
+
if (life <= 0)
|
|
87
|
+
return 0;
|
|
88
|
+
const months = Math.min(last - start + 1, life);
|
|
89
|
+
return months === life ? base : Math.round((base * months) / life);
|
|
90
|
+
}
|
|
91
|
+
if (asset.method === DepreciationMethod.DECLINING_BALANCE) {
|
|
92
|
+
const rate = Number(asset.declineRate) || 0;
|
|
93
|
+
if (rate <= 0 || rate >= 1)
|
|
94
|
+
return 0;
|
|
95
|
+
let book = cost;
|
|
96
|
+
for (let y = Math.floor(start / 12); y <= year; y++) {
|
|
97
|
+
const months = Math.min(last, y * 12 + 11) - Math.max(start, y * 12) + 1;
|
|
98
|
+
if (months <= 0)
|
|
99
|
+
continue;
|
|
100
|
+
book = Math.max(residual, book - Math.round((book * rate * months) / 12));
|
|
101
|
+
}
|
|
102
|
+
return cost - book;
|
|
103
|
+
}
|
|
104
|
+
return 0;
|
|
105
|
+
};
|
|
106
|
+
const accumulated = accumulatedAt(fiscalYear);
|
|
107
|
+
const before = accumulatedAt(fiscalYear - 1);
|
|
108
|
+
return { fiscalYear, expense: accumulated - before, accumulated, bookValue: cost - accumulated };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The register beside the filed balance sheet, line by line (decision 5). A line's accumulated depreciation is the contra
|
|
112
|
+
* line of the next code (122 machinery, 123 its accumulated depreciation) - the filed order can put it elsewhere. The lines are the kinds' own and whatever an asset names; a line the books carry and the register
|
|
113
|
+
* does not is shown too - that is the difference to look at. Nothing is changed: a difference is the accountant's to
|
|
114
|
+
* explain.
|
|
115
|
+
*/
|
|
116
|
+
function reconcile(assets, lines, fiscalYear) {
|
|
117
|
+
const ordered = [...(lines ?? [])].sort((a, b) => a.rank - b.rank);
|
|
118
|
+
const lineOf = (code) => ordered.findIndex(one => one.code === code && !one.contra);
|
|
119
|
+
const codes = new Set(Object.values(exports.DEFAULT_STATEMENT_CODE).filter((code) => !!code && lineOf(code) >= 0 && !!ordered[lineOf(code)].amount));
|
|
120
|
+
const held = assets.filter(one => heldAtYearEnd(one, fiscalYear));
|
|
121
|
+
for (const asset of held) {
|
|
122
|
+
const code = asset.statementCode || exports.DEFAULT_STATEMENT_CODE[asset.kind];
|
|
123
|
+
if (code)
|
|
124
|
+
codes.add(code);
|
|
125
|
+
}
|
|
126
|
+
return [...codes]
|
|
127
|
+
.map(code => {
|
|
128
|
+
const at = lineOf(code);
|
|
129
|
+
const line = at >= 0 ? ordered[at] : undefined;
|
|
130
|
+
const contraCode = String(Number(code) + 1).padStart(code.length, '0');
|
|
131
|
+
const next = ordered.find(one => one.contra && one.code === contraCode);
|
|
132
|
+
const mine = held.filter(one => (one.statementCode || exports.DEFAULT_STATEMENT_CODE[one.kind]) === code);
|
|
133
|
+
return {
|
|
134
|
+
code,
|
|
135
|
+
name: line?.name ?? '',
|
|
136
|
+
assets: mine.length,
|
|
137
|
+
registerCost: mine.reduce((sum, one) => sum + (Number(one.cost) || 0), 0),
|
|
138
|
+
registerAccumulated: mine.reduce((sum, one) => sum + depreciationOf(one, fiscalYear).accumulated, 0),
|
|
139
|
+
statementCost: lines ? Number(line?.amount ?? 0) : null,
|
|
140
|
+
statementAccumulated: lines ? Number(next?.amount ?? 0) : null
|
|
141
|
+
};
|
|
142
|
+
})
|
|
143
|
+
.sort((a, b) => a.code.localeCompare(b.code));
|
|
144
|
+
}
|
|
145
|
+
/** Whether a row of the reconciliation differs - the register and the books do not say the same. */
|
|
146
|
+
const differs = (row) => row.statementCost !== null && (Math.round(row.registerCost) !== Math.round(row.statementCost) || Math.round(row.registerAccumulated) !== Math.round(row.statementAccumulated ?? 0));
|
|
147
|
+
exports.differs = differs;
|
|
148
|
+
//# sourceMappingURL=asset-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-rules.js","sourceRoot":"","sources":["../../../server/service/asset/asset-rules.ts"],"names":[],"mappings":"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","sourcesContent":["import { registerEnumType } from 'type-graphql'\n\n/*\n * The asset register's rules (ADR-0175 decisions 3-5) - apart from the entity, so the screens' words and the tests read\n * them without a type-graphql class. Pure.\n */\n\nexport enum AssetKind {\n LAND = 'LAND',\n BUILDING = 'BUILDING',\n MACHINERY = 'MACHINERY',\n VEHICLE = 'VEHICLE',\n FURNITURE = 'FURNITURE',\n FACILITY = 'FACILITY',\n DEVELOPMENT_COST = 'DEVELOPMENT_COST',\n SOFTWARE = 'SOFTWARE',\n OTHER_INTANGIBLE = 'OTHER_INTANGIBLE'\n}\nregisterEnumType(AssetKind, { name: 'AssetKind', description: 'What an asset is - land, a building, machinery, a vehicle, furniture, a facility, development cost, software or another intangible' })\n\nexport enum AssetStatus {\n IN_USE = 'IN_USE',\n DISPOSED = 'DISPOSED',\n SCRAPPED = 'SCRAPPED'\n}\nregisterEnumType(AssetStatus, { name: 'AssetStatus', description: 'Whether an asset is in use, disposed of (sold) or scrapped' })\n\nexport enum DepreciationMethod {\n STRAIGHT_LINE = 'STRAIGHT_LINE',\n DECLINING_BALANCE = 'DECLINING_BALANCE',\n NONE = 'NONE'\n}\nregisterEnumType(DepreciationMethod, { name: 'DepreciationMethod', description: 'How an asset is depreciated - straight line, declining balance, or not at all (land)' })\n\n/**\n * The line of the standard balance sheet (표준재무제표) each kind is filed under, as accounting reads it\n * (`FinancialStatementLine.code`). An asset may name another; a kind without one names its own.\n */\nexport const DEFAULT_STATEMENT_CODE: Record<AssetKind, string | null> = {\n [AssetKind.LAND]: '111',\n [AssetKind.BUILDING]: '114',\n [AssetKind.MACHINERY]: '122',\n [AssetKind.VEHICLE]: '134',\n [AssetKind.FURNITURE]: '149',\n [AssetKind.FACILITY]: '149',\n [AssetKind.DEVELOPMENT_COST]: '184',\n [AssetKind.SOFTWARE]: '186',\n [AssetKind.OTHER_INTANGIBLE]: null\n}\n\n/** Land is not depreciated; everything else straight line unless written. */\nexport const defaultMethodOf = (kind: AssetKind | string) => (kind === AssetKind.LAND ? DepreciationMethod.NONE : DepreciationMethod.STRAIGHT_LINE)\n\nexport const DATE = /^\\d{4}-\\d{2}-\\d{2}$/\n\nconst monthOf = (date: string) => Number(date.slice(0, 4)) * 12 + Number(date.slice(5, 7)) - 1\n\n/** What depreciation reads of an asset. */\nexport type Depreciable = {\n cost: number\n residualValue?: number | null\n method: DepreciationMethod | string\n usefulLifeYears?: number | null\n declineRate?: number | null\n acquiredOn: string\n depreciationStartOn?: string | null\n status?: AssetStatus | string\n disposedOn?: string | null\n}\n\nexport type YearDepreciation = { fiscalYear: number; expense: number; accumulated: number; bookValue: number }\n\n/** Whether the asset is on the balance sheet at the end of the year: acquired by then, not yet disposed of or scrapped. */\nexport function heldAtYearEnd(asset: Pick<Depreciable, 'acquiredOn' | 'status' | 'disposedOn'>, fiscalYear: number): boolean {\n const end = `${fiscalYear}-12-31`\n if (asset.acquiredOn > end) return false\n return !(asset.status && asset.status !== AssetStatus.IN_USE && asset.disposedOn && asset.disposedOn <= end)\n}\n\n/**\n * The depreciation of an asset for a fiscal year (January to December) - computed, never stored (decision 4).\n *\n * Month by month from the month it starts, through the month it is disposed of. Straight line spreads cost less residual\n * value over the useful life; declining balance takes the rate of the book value each year, the first and the last year\n * in proportion to their months, and never below the residual value. The useful life and the rate are what the books\n * use - this neither looks them up nor checks them against the tax law.\n */\nexport function depreciationOf(asset: Depreciable, fiscalYear: number): YearDepreciation {\n const cost = Number(asset.cost) || 0\n const residual = Math.min(Number(asset.residualValue) || 0, cost)\n const base = cost - residual\n const accumulatedAt = (year: number): number => {\n const start = monthOf(asset.depreciationStartOn || asset.acquiredOn)\n const disposed = asset.status && asset.status !== AssetStatus.IN_USE && asset.disposedOn ? monthOf(asset.disposedOn) : Infinity\n const last = Math.min(year * 12 + 11, disposed)\n if (last < start || base <= 0) return 0\n if (asset.method === DepreciationMethod.STRAIGHT_LINE) {\n const life = Math.round((Number(asset.usefulLifeYears) || 0) * 12)\n if (life <= 0) return 0\n const months = Math.min(last - start + 1, life)\n return months === life ? base : Math.round((base * months) / life)\n }\n if (asset.method === DepreciationMethod.DECLINING_BALANCE) {\n const rate = Number(asset.declineRate) || 0\n if (rate <= 0 || rate >= 1) return 0\n let book = cost\n for (let y = Math.floor(start / 12); y <= year; y++) {\n const months = Math.min(last, y * 12 + 11) - Math.max(start, y * 12) + 1\n if (months <= 0) continue\n book = Math.max(residual, book - Math.round((book * rate * months) / 12))\n }\n return cost - book\n }\n return 0\n }\n const accumulated = accumulatedAt(fiscalYear)\n const before = accumulatedAt(fiscalYear - 1)\n return { fiscalYear, expense: accumulated - before, accumulated, bookValue: cost - accumulated }\n}\n\n/** A line of the filed balance sheet, as accounting keeps it. */\nexport type StatementLine = { code: string; name: string; amount: number; contra?: boolean; rank: number }\n\nexport type ReconciliationRow = {\n code: string\n name: string\n assets: number\n registerCost: number\n registerAccumulated: number\n statementCost: number | null\n statementAccumulated: number | null\n}\n\n/**\n * The register beside the filed balance sheet, line by line (decision 5). A line's accumulated depreciation is the contra\n * line of the next code (122 machinery, 123 its accumulated depreciation) - the filed order can put it elsewhere. The lines are the kinds' own and whatever an asset names; a line the books carry and the register\n * does not is shown too - that is the difference to look at. Nothing is changed: a difference is the accountant's to\n * explain.\n */\nexport function reconcile(\n assets: (Depreciable & { statementCode?: string | null; kind: AssetKind | string })[],\n lines: StatementLine[] | null,\n fiscalYear: number\n): ReconciliationRow[] {\n const ordered = [...(lines ?? [])].sort((a, b) => a.rank - b.rank)\n const lineOf = (code: string) => ordered.findIndex(one => one.code === code && !one.contra)\n const codes = new Set<string>(Object.values(DEFAULT_STATEMENT_CODE).filter((code): code is string => !!code && lineOf(code) >= 0 && !!ordered[lineOf(code)].amount))\n const held = assets.filter(one => heldAtYearEnd(one, fiscalYear))\n for (const asset of held) {\n const code = asset.statementCode || DEFAULT_STATEMENT_CODE[asset.kind as AssetKind]\n if (code) codes.add(code)\n }\n return [...codes]\n .map(code => {\n const at = lineOf(code)\n const line = at >= 0 ? ordered[at] : undefined\n const contraCode = String(Number(code) + 1).padStart(code.length, '0')\n const next = ordered.find(one => one.contra && one.code === contraCode)\n const mine = held.filter(one => (one.statementCode || DEFAULT_STATEMENT_CODE[one.kind as AssetKind]) === code)\n return {\n code,\n name: line?.name ?? '',\n assets: mine.length,\n registerCost: mine.reduce((sum, one) => sum + (Number(one.cost) || 0), 0),\n registerAccumulated: mine.reduce((sum, one) => sum + depreciationOf(one, fiscalYear).accumulated, 0),\n statementCost: lines ? Number(line?.amount ?? 0) : null,\n statementAccumulated: lines ? Number(next?.amount ?? 0) : null\n }\n })\n .sort((a, b) => a.code.localeCompare(b.code))\n}\n\n/** Whether a row of the reconciliation differs - the register and the books do not say the same. */\nexport const differs = (row: ReconciliationRow) =>\n row.statementCost !== null && (Math.round(row.registerCost) !== Math.round(row.statementCost) || Math.round(row.registerAccumulated) !== Math.round(row.statementAccumulated ?? 0))\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Domain } from '@things-factory/shell';
|
|
2
|
+
import { EntityManager } from 'typeorm';
|
|
3
|
+
import { Patch } from '../patches';
|
|
4
|
+
import { Asset } from './asset';
|
|
5
|
+
import { ReconciliationRow } from './asset-rules';
|
|
6
|
+
/** Apply the register grid's rows. */
|
|
7
|
+
export declare function saveAssets(tx: EntityManager, domain: Domain, user: any, patches: Patch[]): Promise<Asset[]>;
|
|
8
|
+
/** The filed balance sheet's lines of a year - null when none is filed. */
|
|
9
|
+
export declare function balanceSheetLines(tx: EntityManager, domain: Domain, fiscalYear: number): Promise<{
|
|
10
|
+
code: string;
|
|
11
|
+
name: string;
|
|
12
|
+
amount: number;
|
|
13
|
+
contra: boolean;
|
|
14
|
+
rank: number;
|
|
15
|
+
}[]>;
|
|
16
|
+
/** The register beside the filed balance sheet of a year (decision 5). */
|
|
17
|
+
export declare function assetReconciliation(tx: EntityManager, domain: Domain, fiscalYear: number): Promise<{
|
|
18
|
+
fiscalYear: number;
|
|
19
|
+
filed: boolean;
|
|
20
|
+
rows: (ReconciliationRow & {
|
|
21
|
+
differs: boolean;
|
|
22
|
+
})[];
|
|
23
|
+
}>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.saveAssets = saveAssets;
|
|
4
|
+
exports.balanceSheetLines = balanceSheetLines;
|
|
5
|
+
exports.assetReconciliation = assetReconciliation;
|
|
6
|
+
const accounting_1 = require("@things-factory/accounting");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const patches_1 = require("../patches");
|
|
9
|
+
const asset_1 = require("./asset");
|
|
10
|
+
const asset_rules_1 = require("./asset-rules");
|
|
11
|
+
const TEXT = ['statementCode', 'location', 'keeper', 'source', 'project', 'description'];
|
|
12
|
+
/** A patch as the row it writes, refused when the asset would not make sense (decisions 3-4). */
|
|
13
|
+
function rowOf(patch, old) {
|
|
14
|
+
const row = {};
|
|
15
|
+
const name = (0, patches_1.touched)(patch, 'name', old) ? (0, patches_1.textOf)(patch.name) : old.name;
|
|
16
|
+
if (!name)
|
|
17
|
+
throw new shell_1.Refusal('asset-name-required', {}, 'Name the asset');
|
|
18
|
+
row.name = name;
|
|
19
|
+
const kind = (patch.kind ?? old?.kind);
|
|
20
|
+
if (!kind || !Object.values(asset_rules_1.AssetKind).includes(kind))
|
|
21
|
+
throw new shell_1.Refusal('asset-kind-required', {}, 'Say what kind of asset it is');
|
|
22
|
+
row.kind = kind;
|
|
23
|
+
for (const field of TEXT)
|
|
24
|
+
if ((0, patches_1.touched)(patch, field, old))
|
|
25
|
+
row[field] = (0, patches_1.textOf)(patch[field]);
|
|
26
|
+
const acquiredOn = (0, patches_1.touched)(patch, 'acquiredOn', old) ? (0, patches_1.dayOf)(patch.acquiredOn, 'asset-acquired-on-invalid', true) : old.acquiredOn;
|
|
27
|
+
row.acquiredOn = acquiredOn;
|
|
28
|
+
if ((0, patches_1.touched)(patch, 'cost', old))
|
|
29
|
+
row.cost = (0, patches_1.amountOf)(patch.cost, 'asset-amount-invalid') ?? 0;
|
|
30
|
+
if ((0, patches_1.touched)(patch, 'residualValue', old))
|
|
31
|
+
row.residualValue = (0, patches_1.amountOf)(patch.residualValue, 'asset-amount-invalid') ?? 0;
|
|
32
|
+
const cost = row.cost ?? old.cost;
|
|
33
|
+
if ((row.residualValue ?? old?.residualValue ?? 0) > cost)
|
|
34
|
+
throw new shell_1.Refusal('asset-residual-above-cost', {}, 'The residual value is more than the cost');
|
|
35
|
+
/* A changed kind takes its own method only when the method was the old kind's own. */
|
|
36
|
+
if (patch.method)
|
|
37
|
+
row.method = patch.method;
|
|
38
|
+
else if (!old)
|
|
39
|
+
row.method = (0, asset_rules_1.defaultMethodOf)(kind);
|
|
40
|
+
else if (patch.kind !== undefined && old.method === (0, asset_rules_1.defaultMethodOf)(old.kind))
|
|
41
|
+
row.method = (0, asset_rules_1.defaultMethodOf)(kind);
|
|
42
|
+
const method = row.method ?? old.method;
|
|
43
|
+
if ((0, patches_1.touched)(patch, 'usefulLifeYears', old))
|
|
44
|
+
row.usefulLifeYears = (0, patches_1.amountOf)(patch.usefulLifeYears, 'asset-useful-life-invalid');
|
|
45
|
+
if ((0, patches_1.touched)(patch, 'declineRate', old))
|
|
46
|
+
row.declineRate = (0, patches_1.amountOf)(patch.declineRate, 'asset-decline-rate-invalid');
|
|
47
|
+
const life = row.usefulLifeYears !== undefined ? row.usefulLifeYears : old?.usefulLifeYears;
|
|
48
|
+
const rate = row.declineRate !== undefined ? row.declineRate : old?.declineRate;
|
|
49
|
+
if (method === asset_rules_1.DepreciationMethod.STRAIGHT_LINE && !(Number(life) > 0))
|
|
50
|
+
throw new shell_1.Refusal('asset-useful-life-required', {}, 'Give the useful life in years for straight-line depreciation');
|
|
51
|
+
if (method === asset_rules_1.DepreciationMethod.DECLINING_BALANCE && !(Number(rate) > 0 && Number(rate) < 1))
|
|
52
|
+
throw new shell_1.Refusal('asset-decline-rate-required', {}, 'Give the yearly rate (between 0 and 1) for declining-balance depreciation');
|
|
53
|
+
if ((0, patches_1.touched)(patch, 'depreciationStartOn', old))
|
|
54
|
+
row.depreciationStartOn = (0, patches_1.dayOf)(patch.depreciationStartOn, 'asset-start-on-invalid');
|
|
55
|
+
if ((0, patches_1.touched)(patch, 'status', old))
|
|
56
|
+
row.status = patch.status ?? asset_rules_1.AssetStatus.IN_USE;
|
|
57
|
+
if ((0, patches_1.touched)(patch, 'disposedOn', old))
|
|
58
|
+
row.disposedOn = (0, patches_1.dayOf)(patch.disposedOn, 'asset-disposed-on-invalid');
|
|
59
|
+
const status = row.status ?? old.status;
|
|
60
|
+
const disposedOn = row.disposedOn !== undefined ? row.disposedOn : old?.disposedOn;
|
|
61
|
+
if (status !== asset_rules_1.AssetStatus.IN_USE && !disposedOn)
|
|
62
|
+
throw new shell_1.Refusal('asset-disposed-on-required', {}, 'Give the day it was disposed of or scrapped');
|
|
63
|
+
if (disposedOn && disposedOn < acquiredOn)
|
|
64
|
+
throw new shell_1.Refusal('asset-disposed-before-acquired', {}, 'It was disposed of before it was acquired');
|
|
65
|
+
return row;
|
|
66
|
+
}
|
|
67
|
+
/** Apply the register grid's rows. */
|
|
68
|
+
function saveAssets(tx, domain, user, patches) {
|
|
69
|
+
return (0, patches_1.applyPatches)(tx, asset_1.Asset, domain, user, patches, rowOf, 'asset-not-found');
|
|
70
|
+
}
|
|
71
|
+
/** The filed balance sheet's lines of a year - null when none is filed. */
|
|
72
|
+
async function balanceSheetLines(tx, domain, fiscalYear) {
|
|
73
|
+
const statement = await tx.getRepository(accounting_1.FinancialStatement).findOne({ where: { domain: { id: domain.id }, fiscalYear, kind: accounting_1.FinancialStatementKind.BALANCE_SHEET } });
|
|
74
|
+
if (!statement)
|
|
75
|
+
return null;
|
|
76
|
+
const lines = await tx.getRepository(accounting_1.FinancialStatementLine).find({ where: { statement: { id: statement.id } } });
|
|
77
|
+
return lines.map(line => ({ code: line.code, name: line.name, amount: Number(line.amount), contra: !!line.contra, rank: line.rank }));
|
|
78
|
+
}
|
|
79
|
+
/** The register beside the filed balance sheet of a year (decision 5). */
|
|
80
|
+
async function assetReconciliation(tx, domain, fiscalYear) {
|
|
81
|
+
const [assets, lines] = await Promise.all([tx.getRepository(asset_1.Asset).find({ where: { domain: { id: domain.id } } }), balanceSheetLines(tx, domain, fiscalYear)]);
|
|
82
|
+
return { fiscalYear, filed: !!lines, rows: (0, asset_rules_1.reconcile)(assets, lines, fiscalYear).map(row => ({ ...row, differs: (0, asset_rules_1.differs)(row) })) };
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=asset-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-service.js","sourceRoot":"","sources":["../../../server/service/asset/asset-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { FinancialStatement, FinancialStatementKind, FinancialStatementLine } from '@things-factory/accounting'\nimport { Domain, Refusal } from '@things-factory/shell'\nimport { EntityManager } from 'typeorm'\n\nimport { amountOf, applyPatches, dayOf, Patch, textOf, touched } from '../patches'\nimport { Asset } from './asset'\nimport { AssetKind, AssetStatus, defaultMethodOf, DepreciationMethod, differs, reconcile, ReconciliationRow } from './asset-rules'\n\nconst TEXT = ['statementCode', 'location', 'keeper', 'source', 'project', 'description'] as const\n\n/** A patch as the row it writes, refused when the asset would not make sense (decisions 3-4). */\nfunction rowOf(patch: Patch, old?: Asset): Partial<Asset> {\n const row: Record<string, any> = {}\n const name = touched(patch, 'name', old) ? textOf(patch.name) : old!.name\n if (!name) throw new Refusal('asset-name-required', {}, 'Name the asset')\n row.name = name\n const kind = (patch.kind ?? old?.kind) as AssetKind\n if (!kind || !Object.values(AssetKind).includes(kind)) throw new Refusal('asset-kind-required', {}, 'Say what kind of asset it is')\n row.kind = kind\n for (const field of TEXT) if (touched(patch, field, old)) row[field] = textOf(patch[field])\n const acquiredOn = touched(patch, 'acquiredOn', old) ? dayOf(patch.acquiredOn, 'asset-acquired-on-invalid', true) : old!.acquiredOn\n row.acquiredOn = acquiredOn\n if (touched(patch, 'cost', old)) row.cost = amountOf(patch.cost, 'asset-amount-invalid') ?? 0\n if (touched(patch, 'residualValue', old)) row.residualValue = amountOf(patch.residualValue, 'asset-amount-invalid') ?? 0\n const cost = row.cost ?? old!.cost\n if ((row.residualValue ?? old?.residualValue ?? 0) > cost) throw new Refusal('asset-residual-above-cost', {}, 'The residual value is more than the cost')\n\n /* A changed kind takes its own method only when the method was the old kind's own. */\n if (patch.method) row.method = patch.method\n else if (!old) row.method = defaultMethodOf(kind)\n else if (patch.kind !== undefined && old.method === defaultMethodOf(old.kind)) row.method = defaultMethodOf(kind)\n const method = row.method ?? old!.method\n if (touched(patch, 'usefulLifeYears', old)) row.usefulLifeYears = amountOf(patch.usefulLifeYears, 'asset-useful-life-invalid')\n if (touched(patch, 'declineRate', old)) row.declineRate = amountOf(patch.declineRate, 'asset-decline-rate-invalid')\n const life = row.usefulLifeYears !== undefined ? row.usefulLifeYears : old?.usefulLifeYears\n const rate = row.declineRate !== undefined ? row.declineRate : old?.declineRate\n if (method === DepreciationMethod.STRAIGHT_LINE && !(Number(life) > 0))\n throw new Refusal('asset-useful-life-required', {}, 'Give the useful life in years for straight-line depreciation')\n if (method === DepreciationMethod.DECLINING_BALANCE && !(Number(rate) > 0 && Number(rate) < 1))\n throw new Refusal('asset-decline-rate-required', {}, 'Give the yearly rate (between 0 and 1) for declining-balance depreciation')\n if (touched(patch, 'depreciationStartOn', old)) row.depreciationStartOn = dayOf(patch.depreciationStartOn, 'asset-start-on-invalid')\n\n if (touched(patch, 'status', old)) row.status = patch.status ?? AssetStatus.IN_USE\n if (touched(patch, 'disposedOn', old)) row.disposedOn = dayOf(patch.disposedOn, 'asset-disposed-on-invalid')\n const status = row.status ?? old!.status\n const disposedOn = row.disposedOn !== undefined ? row.disposedOn : old?.disposedOn\n if (status !== AssetStatus.IN_USE && !disposedOn) throw new Refusal('asset-disposed-on-required', {}, 'Give the day it was disposed of or scrapped')\n if (disposedOn && disposedOn < acquiredOn!) throw new Refusal('asset-disposed-before-acquired', {}, 'It was disposed of before it was acquired')\n return row\n}\n\n/** Apply the register grid's rows. */\nexport function saveAssets(tx: EntityManager, domain: Domain, user: any, patches: Patch[]) {\n return applyPatches(tx, Asset, domain, user, patches, rowOf, 'asset-not-found')\n}\n\n/** The filed balance sheet's lines of a year - null when none is filed. */\nexport async function balanceSheetLines(tx: EntityManager, domain: Domain, fiscalYear: number) {\n const statement = await tx.getRepository(FinancialStatement).findOne({ where: { domain: { id: domain.id }, fiscalYear, kind: FinancialStatementKind.BALANCE_SHEET } as any })\n if (!statement) return null\n const lines = await tx.getRepository(FinancialStatementLine).find({ where: { statement: { id: statement.id } } as any })\n return lines.map(line => ({ code: line.code, name: line.name, amount: Number(line.amount), contra: !!line.contra, rank: line.rank }))\n}\n\n/** The register beside the filed balance sheet of a year (decision 5). */\nexport async function assetReconciliation(tx: EntityManager, domain: Domain, fiscalYear: number): Promise<{ fiscalYear: number; filed: boolean; rows: (ReconciliationRow & { differs: boolean })[] }> {\n const [assets, lines] = await Promise.all([tx.getRepository(Asset).find({ where: { domain: { id: domain.id } } as any }), balanceSheetLines(tx, domain, fiscalYear)])\n return { fiscalYear, filed: !!lines, rows: reconcile(assets as any, lines, fiscalYear).map(row => ({ ...row, differs: differs(row) })) }\n}\n"]}
|