@things-factory/biz-base 10.1.123 → 10.1.135
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-server/service/biz-option/index.d.ts +1 -1
- package/dist-server/service/biz-option-detail/index.d.ts +1 -1
- package/dist-server/service/bizplace/index.d.ts +1 -1
- package/dist-server/service/company/index.d.ts +1 -1
- package/dist-server/service/counterparty/counterparty-mutation.d.ts +8 -0
- package/dist-server/service/counterparty/counterparty-mutation.js +81 -0
- package/dist-server/service/counterparty/counterparty-mutation.js.map +1 -0
- package/dist-server/service/counterparty/counterparty-names.d.ts +80 -0
- package/dist-server/service/counterparty/counterparty-names.js +206 -0
- package/dist-server/service/counterparty/counterparty-names.js.map +1 -0
- package/dist-server/service/counterparty/counterparty-query.d.ts +11 -0
- package/dist-server/service/counterparty/counterparty-query.js +79 -0
- package/dist-server/service/counterparty/counterparty-query.js.map +1 -0
- package/dist-server/service/counterparty/counterparty-service.d.ts +22 -0
- package/dist-server/service/counterparty/counterparty-service.js +85 -0
- package/dist-server/service/counterparty/counterparty-service.js.map +1 -0
- package/dist-server/service/counterparty/counterparty-type.d.ts +37 -0
- package/dist-server/service/counterparty/counterparty-type.js +145 -0
- package/dist-server/service/counterparty/counterparty-type.js.map +1 -0
- package/dist-server/service/counterparty/counterparty.d.ts +40 -0
- package/dist-server/service/counterparty/counterparty.js +148 -0
- package/dist-server/service/counterparty/counterparty.js.map +1 -0
- package/dist-server/service/counterparty/index.d.ts +5 -0
- package/dist-server/service/counterparty/index.js +9 -0
- package/dist-server/service/counterparty/index.js.map +1 -0
- package/dist-server/service/index.d.ts +6 -4
- package/dist-server/service/index.js +7 -5
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/worker/index.d.ts +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -3
- package/tests/counterparty-names.test.mjs +116 -0
- package/tests/counterparty.test.mjs +69 -0
- package/translations/en.json +6 -1
- package/translations/ko.json +6 -1
- package/dist-server/service/contact-point/contact-point-mutation.d.ts +0 -13
- package/dist-server/service/contact-point/contact-point-mutation.js +0 -164
- package/dist-server/service/contact-point/contact-point-mutation.js.map +0 -1
- package/dist-server/service/contact-point/contact-point-query.d.ts +0 -7
- package/dist-server/service/contact-point/contact-point-query.js +0 -56
- package/dist-server/service/contact-point/contact-point-query.js.map +0 -1
- package/dist-server/service/contact-point/contact-point-types.d.ts +0 -58
- package/dist-server/service/contact-point/contact-point-types.js +0 -226
- package/dist-server/service/contact-point/contact-point-types.js.map +0 -1
- package/dist-server/service/contact-point/contact-point.d.ts +0 -34
- package/dist-server/service/contact-point/contact-point.js +0 -171
- package/dist-server/service/contact-point/contact-point.js.map +0 -1
- package/dist-server/service/contact-point/index.d.ts +0 -5
- package/dist-server/service/contact-point/index.js +0 -9
- package/dist-server/service/contact-point/index.js.map +0 -1
|
@@ -2,4 +2,4 @@ import { BizOption } from './biz-option';
|
|
|
2
2
|
import { BizOptionMutation } from './biz-option-mutation';
|
|
3
3
|
import { BizOptionQuery } from './biz-option-query';
|
|
4
4
|
export declare const entities: (typeof BizOption)[];
|
|
5
|
-
export declare const resolvers: (typeof
|
|
5
|
+
export declare const resolvers: (typeof BizOptionMutation | typeof BizOptionQuery)[];
|
|
@@ -2,4 +2,4 @@ import { BizOptionDetail } from './biz-option-detail';
|
|
|
2
2
|
import { BizOptionDetailMutation } from './biz-option-detail-mutation';
|
|
3
3
|
import { BizOptionDetailQuery } from './biz-option-detail-query';
|
|
4
4
|
export declare const entities: (typeof BizOptionDetail)[];
|
|
5
|
-
export declare const resolvers: (typeof
|
|
5
|
+
export declare const resolvers: (typeof BizOptionDetailMutation | typeof BizOptionDetailQuery)[];
|
|
@@ -2,4 +2,4 @@ import { Bizplace } from './bizplace';
|
|
|
2
2
|
import { BizplaceMutation } from './bizplace-mutation';
|
|
3
3
|
import { BizplaceQuery } from './bizplace-query';
|
|
4
4
|
export declare const entities: (typeof Bizplace)[];
|
|
5
|
-
export declare const resolvers: (typeof
|
|
5
|
+
export declare const resolvers: (typeof BizplaceMutation | typeof BizplaceQuery)[];
|
|
@@ -2,4 +2,4 @@ import { Company } from './company';
|
|
|
2
2
|
import { CompanyMutation } from './company-mutation';
|
|
3
3
|
import { CompanyQuery } from './company-query';
|
|
4
4
|
export declare const entities: (typeof Company)[];
|
|
5
|
-
export declare const resolvers: (typeof
|
|
5
|
+
export declare const resolvers: (typeof CompanyMutation | typeof CompanyQuery)[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Counterparty } from './counterparty';
|
|
2
|
+
import { CounterpartyPatch, NewCounterparty } from './counterparty-type';
|
|
3
|
+
export declare class CounterpartyMutation {
|
|
4
|
+
createCounterparty(input: NewCounterparty, context: ResolverContext): Promise<Counterparty>;
|
|
5
|
+
updateCounterparty(id: string, patch: CounterpartyPatch, context: ResolverContext): Promise<Counterparty>;
|
|
6
|
+
updateMultipleCounterparty(patches: CounterpartyPatch[], context: ResolverContext): Promise<Counterparty[]>;
|
|
7
|
+
deleteCounterparties(ids: string[], context: ResolverContext): Promise<boolean>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CounterpartyMutation = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
|
+
const counterparty_1 = require("./counterparty");
|
|
8
|
+
const counterparty_service_1 = require("./counterparty-service");
|
|
9
|
+
const counterparty_type_1 = require("./counterparty-type");
|
|
10
|
+
let CounterpartyMutation = class CounterpartyMutation {
|
|
11
|
+
async createCounterparty(input, context) {
|
|
12
|
+
const { tx, domain, user } = context.state;
|
|
13
|
+
const [saved] = await (0, counterparty_service_1.saveCounterparties)(tx, domain, user, [{ ...input, cuFlag: '+' }]);
|
|
14
|
+
return saved;
|
|
15
|
+
}
|
|
16
|
+
async updateCounterparty(id, patch, context) {
|
|
17
|
+
const { tx, domain, user } = context.state;
|
|
18
|
+
const [saved] = await (0, counterparty_service_1.saveCounterparties)(tx, domain, user, [{ ...patch, id, cuFlag: 'M' }]);
|
|
19
|
+
return saved;
|
|
20
|
+
}
|
|
21
|
+
async updateMultipleCounterparty(patches, context) {
|
|
22
|
+
const { tx, domain, user } = context.state;
|
|
23
|
+
return await (0, counterparty_service_1.saveCounterparties)(tx, domain, user, patches);
|
|
24
|
+
}
|
|
25
|
+
async deleteCounterparties(ids, context) {
|
|
26
|
+
const { tx, domain, user } = context.state;
|
|
27
|
+
await (0, counterparty_service_1.saveCounterparties)(tx, domain, user, ids.map(id => ({ id, cuFlag: '-' })));
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
exports.CounterpartyMutation = CounterpartyMutation;
|
|
32
|
+
tslib_1.__decorate([
|
|
33
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
34
|
+
(0, type_graphql_1.Directive)('@privilege(category: "counterparty", privilege: "mutation", domainOwnerGranted: true)'),
|
|
35
|
+
(0, type_graphql_1.Mutation)(returns => counterparty_1.Counterparty, { description: 'To register a counterparty' }),
|
|
36
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('counterparty')),
|
|
37
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
38
|
+
tslib_1.__metadata("design:type", Function),
|
|
39
|
+
tslib_1.__metadata("design:paramtypes", [counterparty_type_1.NewCounterparty, Object]),
|
|
40
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
41
|
+
], CounterpartyMutation.prototype, "createCounterparty", null);
|
|
42
|
+
tslib_1.__decorate([
|
|
43
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
44
|
+
(0, type_graphql_1.Directive)('@privilege(category: "counterparty", privilege: "mutation", domainOwnerGranted: true)'),
|
|
45
|
+
(0, type_graphql_1.Mutation)(returns => counterparty_1.Counterparty, { description: 'To change a counterparty' }),
|
|
46
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
47
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('patch')),
|
|
48
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
49
|
+
tslib_1.__metadata("design:type", Function),
|
|
50
|
+
tslib_1.__metadata("design:paramtypes", [String, counterparty_type_1.CounterpartyPatch, Object]),
|
|
51
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
52
|
+
], CounterpartyMutation.prototype, "updateCounterparty", null);
|
|
53
|
+
tslib_1.__decorate([
|
|
54
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
55
|
+
(0, type_graphql_1.Directive)('@privilege(category: "counterparty", privilege: "mutation", domainOwnerGranted: true)'),
|
|
56
|
+
(0, type_graphql_1.Mutation)(returns => [counterparty_1.Counterparty], {
|
|
57
|
+
description: 'To save the counterparty grid - new, changed and deleted rows together'
|
|
58
|
+
}),
|
|
59
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('patches', type => [counterparty_type_1.CounterpartyPatch])),
|
|
60
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
61
|
+
tslib_1.__metadata("design:type", Function),
|
|
62
|
+
tslib_1.__metadata("design:paramtypes", [Array, Object]),
|
|
63
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
64
|
+
], CounterpartyMutation.prototype, "updateMultipleCounterparty", null);
|
|
65
|
+
tslib_1.__decorate([
|
|
66
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
67
|
+
(0, type_graphql_1.Directive)('@privilege(category: "counterparty", privilege: "mutation", domainOwnerGranted: true)'),
|
|
68
|
+
(0, type_graphql_1.Mutation)(returns => Boolean, {
|
|
69
|
+
description: 'To delete counterparties - the rows that name them keep the name and lose the link'
|
|
70
|
+
}),
|
|
71
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('ids', type => [String])),
|
|
72
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
73
|
+
tslib_1.__metadata("design:type", Function),
|
|
74
|
+
tslib_1.__metadata("design:paramtypes", [Array, Object]),
|
|
75
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
76
|
+
], CounterpartyMutation.prototype, "deleteCounterparties", null);
|
|
77
|
+
exports.CounterpartyMutation = CounterpartyMutation = tslib_1.__decorate([
|
|
78
|
+
(0, type_graphql_1.Resolver)(counterparty_1.Counterparty),
|
|
79
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
|
|
80
|
+
], CounterpartyMutation);
|
|
81
|
+
//# sourceMappingURL=counterparty-mutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counterparty-mutation.js","sourceRoot":"","sources":["../../../server/service/counterparty/counterparty-mutation.ts"],"names":[],"mappings":";;;;AAAA,+CAAqF;AAErF,iDAAqD;AAErD,iDAA6C;AAC7C,iEAA2D;AAC3D,2DAAwE;AAIjE,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAIzB,AAAN,KAAK,CAAC,kBAAkB,CACD,KAAsB,EACpC,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,IAAA,yCAAkB,EAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;QACvF,OAAO,KAAK,CAAA;IACd,CAAC;IAKK,AAAN,KAAK,CAAC,kBAAkB,CACX,EAAU,EACP,KAAwB,EAC/B,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,IAAA,yCAAkB,EAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;QAC3F,OAAO,KAAK,CAAA;IACd,CAAC;IAOK,AAAN,KAAK,CAAC,0BAA0B,CACe,OAA4B,EAClE,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,OAAO,MAAM,IAAA,yCAAkB,EAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IAC5D,CAAC;IAOK,AAAN,KAAK,CAAC,oBAAoB,CACM,GAAa,EACpC,OAAwB;QAE/B,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,MAAM,IAAA,yCAAkB,EACtB,EAAE,EACF,MAAM,EACN,IAAI,EACJ,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CACrC,CAAA;QACD,OAAO,IAAI,CAAA;IACb,CAAC;CACF,CAAA;AAzDY,oDAAoB;AAIzB;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,uFAAuF,CAAC;IAClG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,2BAAY,EAAE,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;IAE9E,mBAAA,IAAA,kBAAG,EAAC,cAAc,CAAC,CAAA;IACnB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CADsB,mCAAe;;8DAM5C;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,uFAAuF,CAAC;IAClG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,2BAAY,EAAE,EAAE,WAAW,EAAE,0BAA0B,EAAE,CAAC;IAE5E,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IACT,mBAAA,IAAA,kBAAG,EAAC,OAAO,CAAC,CAAA;IACZ,mBAAA,IAAA,kBAAG,GAAE,CAAA;;qDADe,qCAAiB;;8DAMvC;AAOK;IALL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,uFAAuF,CAAC;IAClG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,2BAAY,CAAC,EAAE;QACnC,WAAW,EAAE,wEAAwE;KACtF,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,qCAAiB,CAAC,CAAC,CAAA;IAC3C,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sEAIP;AAOK;IALL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,uFAAuF,CAAC;IAClG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EAAE,oFAAoF;KAClG,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAC5B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;gEAUP;+BAxDU,oBAAoB;IAFhC,IAAA,uBAAQ,EAAC,2BAAY,CAAC;IACtB,IAAA,4BAAa,EAAC,qBAAa,CAAC;GAChB,oBAAoB,CAyDhC","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { SpeakRefusals } from '@things-factory/shell'\n\nimport { Counterparty } from './counterparty'\nimport { saveCounterparties } from './counterparty-service'\nimport { CounterpartyPatch, NewCounterparty } from './counterparty-type'\n\n@Resolver(Counterparty)\n@UseMiddleware(SpeakRefusals)\nexport class CounterpartyMutation {\n @Directive('@transaction')\n @Directive('@privilege(category: \"counterparty\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Counterparty, { description: 'To register a counterparty' })\n async createCounterparty(\n @Arg('counterparty') input: NewCounterparty,\n @Ctx() context: ResolverContext\n ): Promise<Counterparty> {\n const { tx, domain, user } = context.state\n const [saved] = await saveCounterparties(tx, domain, user, [{ ...input, cuFlag: '+' }])\n return saved\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"counterparty\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Counterparty, { description: 'To change a counterparty' })\n async updateCounterparty(\n @Arg('id') id: string,\n @Arg('patch') patch: CounterpartyPatch,\n @Ctx() context: ResolverContext\n ): Promise<Counterparty> {\n const { tx, domain, user } = context.state\n const [saved] = await saveCounterparties(tx, domain, user, [{ ...patch, id, cuFlag: 'M' }])\n return saved\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"counterparty\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Counterparty], {\n description: 'To save the counterparty grid - new, changed and deleted rows together'\n })\n async updateMultipleCounterparty(\n @Arg('patches', type => [CounterpartyPatch]) patches: CounterpartyPatch[],\n @Ctx() context: ResolverContext\n ): Promise<Counterparty[]> {\n const { tx, domain, user } = context.state\n return await saveCounterparties(tx, domain, user, patches)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"counterparty\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, {\n description: 'To delete counterparties - the rows that name them keep the name and lose the link'\n })\n async deleteCounterparties(\n @Arg('ids', type => [String]) ids: string[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain, user } = context.state\n await saveCounterparties(\n tx,\n domain,\n user,\n ids.map(id => ({ id, cuFlag: '-' }))\n )\n return true\n }\n}\n"]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How names point at counterparties — one place for every module that keeps a name and a link.
|
|
3
|
+
*
|
|
4
|
+
* A document (a contract, a bank line, an invoice) records **the name as it was** and, when the domain knows that
|
|
5
|
+
* party, a link to it. The name stays even if the party is renamed later. Names are compared the way people mean
|
|
6
|
+
* them (§`nameKey`), and a counterparty's aliases count as its names.
|
|
7
|
+
*
|
|
8
|
+
* Pure: the caller hands over what it looked up.
|
|
9
|
+
*/
|
|
10
|
+
export interface KnownCounterparty {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Compare names the way people mean them — case, spacing and `(주)` / `주식회사` do not make another party.
|
|
16
|
+
* NFKC folds the compatibility forms Hometax writes (`(주)` in fullwidth, `㈜`) into the plain ones.
|
|
17
|
+
*/
|
|
18
|
+
export declare function nameKey(name: string | null | undefined): string;
|
|
19
|
+
export type LinkChange = {
|
|
20
|
+
counterparty?: {
|
|
21
|
+
id: string;
|
|
22
|
+
} | null;
|
|
23
|
+
customerName?: string | null;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* What to write for the link, given the row's patch. Returns only what changes; an update that
|
|
27
|
+
* touches neither the name nor the counterparty returns `{}`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function linkFor(patch: {
|
|
30
|
+
counterparty?: {
|
|
31
|
+
id?: string | null;
|
|
32
|
+
} | null;
|
|
33
|
+
customerName?: string | null;
|
|
34
|
+
}, byId: (id: string) => KnownCounterparty | undefined, byName: (key: string) => KnownCounterparty | undefined): LinkChange;
|
|
35
|
+
/**
|
|
36
|
+
* 사업자등록번호 — ten digits, stored as `123-45-67890`. Empty stays empty; anything else that is
|
|
37
|
+
* not ten digits is refused rather than stored half-right.
|
|
38
|
+
*/
|
|
39
|
+
export declare function normalizeBusinessNumber(value: unknown): string | null;
|
|
40
|
+
/**
|
|
41
|
+
* Two counterparties whose names mean the same party (§`nameKey`) — after a batch would apply.
|
|
42
|
+
* Returns the clashing pair, or undefined. `(주)한빛` and `한빛` are one party; registering both
|
|
43
|
+
* would split its contracts in two.
|
|
44
|
+
*/
|
|
45
|
+
export declare function nameClash(existing: readonly KnownCounterparty[], changes: readonly {
|
|
46
|
+
id?: string;
|
|
47
|
+
name?: string | null;
|
|
48
|
+
}[], deleted?: readonly string[]): [string, string] | undefined;
|
|
49
|
+
/** Names to register: one spelling per party, skipping blanks and parties already known. */
|
|
50
|
+
export declare function namesToRegister(names: readonly (string | null | undefined)[], known: readonly KnownCounterparty[]): string[];
|
|
51
|
+
export interface PartyForMatch {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
aliases?: string | null;
|
|
55
|
+
}
|
|
56
|
+
export interface ProposedParty {
|
|
57
|
+
name: string;
|
|
58
|
+
variants: string[];
|
|
59
|
+
count: number;
|
|
60
|
+
maybePerson: boolean;
|
|
61
|
+
}
|
|
62
|
+
export declare function looksLikePersonName(name: string): boolean;
|
|
63
|
+
/** The parties a list of names (contracts, documents) means, one per `nameKey`, spelled the way the ledger spells it most. */
|
|
64
|
+
export declare function partiesFromNames(names: readonly (string | null | undefined)[]): ProposedParty[];
|
|
65
|
+
export declare function aliasesOf(party: PartyForMatch): string[];
|
|
66
|
+
/**
|
|
67
|
+
* A function telling which party a name is — the party's name or one of its aliases, spelled any way
|
|
68
|
+
* `nameKey` folds (§ a contract's 상호). An exact match, not a search.
|
|
69
|
+
*/
|
|
70
|
+
export declare function partyNamed(parties: readonly PartyForMatch[]): (name: string | null | undefined) => PartyForMatch | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* A function telling which party a text names. The longest matching name or alias wins; two
|
|
73
|
+
* different parties matching equally long is ambiguous — no answer.
|
|
74
|
+
*/
|
|
75
|
+
export declare function matcherFor(parties: readonly PartyForMatch[]): (text: string | null | undefined) => PartyForMatch | undefined;
|
|
76
|
+
/** The texts left unmatched most often — what a person might add as aliases. */
|
|
77
|
+
export declare function frequentUnmatched(texts: readonly (string | null | undefined)[], limit?: number): {
|
|
78
|
+
text: string;
|
|
79
|
+
count: number;
|
|
80
|
+
}[];
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* How names point at counterparties — one place for every module that keeps a name and a link.
|
|
4
|
+
*
|
|
5
|
+
* A document (a contract, a bank line, an invoice) records **the name as it was** and, when the domain knows that
|
|
6
|
+
* party, a link to it. The name stays even if the party is renamed later. Names are compared the way people mean
|
|
7
|
+
* them (§`nameKey`), and a counterparty's aliases count as its names.
|
|
8
|
+
*
|
|
9
|
+
* Pure: the caller hands over what it looked up.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.nameKey = nameKey;
|
|
13
|
+
exports.linkFor = linkFor;
|
|
14
|
+
exports.normalizeBusinessNumber = normalizeBusinessNumber;
|
|
15
|
+
exports.nameClash = nameClash;
|
|
16
|
+
exports.namesToRegister = namesToRegister;
|
|
17
|
+
exports.looksLikePersonName = looksLikePersonName;
|
|
18
|
+
exports.partiesFromNames = partiesFromNames;
|
|
19
|
+
exports.aliasesOf = aliasesOf;
|
|
20
|
+
exports.partyNamed = partyNamed;
|
|
21
|
+
exports.matcherFor = matcherFor;
|
|
22
|
+
exports.frequentUnmatched = frequentUnmatched;
|
|
23
|
+
const shell_1 = require("@things-factory/shell");
|
|
24
|
+
/**
|
|
25
|
+
* Compare names the way people mean them — case, spacing and `(주)` / `주식회사` do not make another party.
|
|
26
|
+
* NFKC folds the compatibility forms Hometax writes (`(주)` in fullwidth, `㈜`) into the plain ones.
|
|
27
|
+
*/
|
|
28
|
+
function nameKey(name) {
|
|
29
|
+
return (String(name ?? '')
|
|
30
|
+
.normalize('NFKC')
|
|
31
|
+
.replace(/\(\s*주\s*\)|㈜|주식회사|\(\s*유\s*\)|유한회사/g, '')
|
|
32
|
+
/* The same company written in Hangul or in Latin — 씨제이올리브네트웍스 is CJ올리브네트웍스. */
|
|
33
|
+
.replace(/씨제이/g, 'cj')
|
|
34
|
+
.replace(/에스케이/g, 'sk')
|
|
35
|
+
.replace(/엘지/g, 'lg')
|
|
36
|
+
.replace(/[\s\-_.·,()]+/g, '')
|
|
37
|
+
.toLowerCase());
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* What to write for the link, given the row's patch. Returns only what changes; an update that
|
|
41
|
+
* touches neither the name nor the counterparty returns `{}`.
|
|
42
|
+
*/
|
|
43
|
+
function linkFor(patch, byId, byName) {
|
|
44
|
+
if (patch.counterparty !== undefined) {
|
|
45
|
+
const id = patch.counterparty?.id;
|
|
46
|
+
if (!id)
|
|
47
|
+
return { counterparty: null, ...('customerName' in patch ? { customerName: patch.customerName ?? null } : {}) };
|
|
48
|
+
const known = byId(id);
|
|
49
|
+
if (!known)
|
|
50
|
+
throw new shell_1.Refusal('counterparty-not-found', { id }, 'the counterparty was not found. reload and try again.');
|
|
51
|
+
return { counterparty: { id: known.id }, customerName: known.name };
|
|
52
|
+
}
|
|
53
|
+
if (!('customerName' in patch))
|
|
54
|
+
return {};
|
|
55
|
+
const name = patch.customerName?.trim() || null;
|
|
56
|
+
if (!name)
|
|
57
|
+
return { counterparty: null, customerName: null };
|
|
58
|
+
const known = byName(nameKey(name));
|
|
59
|
+
return known ? { counterparty: { id: known.id }, customerName: name } : { counterparty: null, customerName: name };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 사업자등록번호 — ten digits, stored as `123-45-67890`. Empty stays empty; anything else that is
|
|
63
|
+
* not ten digits is refused rather than stored half-right.
|
|
64
|
+
*/
|
|
65
|
+
function normalizeBusinessNumber(value) {
|
|
66
|
+
const text = String(value ?? '').trim();
|
|
67
|
+
if (!text)
|
|
68
|
+
return null;
|
|
69
|
+
const digits = text.replace(/[-\s]/g, '');
|
|
70
|
+
if (!/^\d{10}$/.test(digits))
|
|
71
|
+
throw new shell_1.Refusal('business-number-invalid', { text }, `'${text}' is not a business registration number (10 digits).`);
|
|
72
|
+
return `${digits.slice(0, 3)}-${digits.slice(3, 5)}-${digits.slice(5)}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Two counterparties whose names mean the same party (§`nameKey`) — after a batch would apply.
|
|
76
|
+
* Returns the clashing pair, or undefined. `(주)한빛` and `한빛` are one party; registering both
|
|
77
|
+
* would split its contracts in two.
|
|
78
|
+
*/
|
|
79
|
+
function nameClash(existing, changes, deleted = []) {
|
|
80
|
+
const after = new Map();
|
|
81
|
+
for (const one of existing)
|
|
82
|
+
if (!deleted.includes(one.id))
|
|
83
|
+
after.set(one.id, one.name);
|
|
84
|
+
let fresh = 0;
|
|
85
|
+
for (const change of changes) {
|
|
86
|
+
if (change.id) {
|
|
87
|
+
if (change.name)
|
|
88
|
+
after.set(change.id, change.name);
|
|
89
|
+
}
|
|
90
|
+
else if (change.name) {
|
|
91
|
+
after.set(`new:${fresh++}`, change.name);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const seen = new Map();
|
|
95
|
+
for (const name of after.values()) {
|
|
96
|
+
const key = nameKey(name);
|
|
97
|
+
if (!key)
|
|
98
|
+
continue;
|
|
99
|
+
const other = seen.get(key);
|
|
100
|
+
if (other !== undefined)
|
|
101
|
+
return [other, name];
|
|
102
|
+
seen.set(key, name);
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
/** Names to register: one spelling per party, skipping blanks and parties already known. */
|
|
107
|
+
function namesToRegister(names, known) {
|
|
108
|
+
const taken = new Set(known.map(one => nameKey(one.name)));
|
|
109
|
+
const out = [];
|
|
110
|
+
for (const name of names) {
|
|
111
|
+
const trimmed = String(name ?? '').trim();
|
|
112
|
+
const key = nameKey(trimmed);
|
|
113
|
+
if (!key || taken.has(key))
|
|
114
|
+
continue;
|
|
115
|
+
taken.add(key);
|
|
116
|
+
out.push(trimmed);
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
/** Keys shorter than this match too much by accident. */
|
|
121
|
+
const MIN_KEY = 2;
|
|
122
|
+
const SURNAMES = new Set('김이박최정강조윤장임한오서신권황안송류전홍고문양손배백허유남심노하곽성차주우구민진지엄채원천방공현함변염여추도소석선설마길연위표명기반왕금옥육인맹제모탁국어은편용예경봉사부가복태목형피두감음빈동온호범좌팽승간상갈단견당'.split(''));
|
|
123
|
+
function looksLikePersonName(name) {
|
|
124
|
+
const trimmed = name.trim();
|
|
125
|
+
return /^[가-힣]{2,4}$/.test(trimmed) && trimmed.length === 3 && SURNAMES.has(trimmed[0]) && !/(테크|솔루션|푸드|그룹|시스템|컴|넷|랩|소프트|산업|상사|물산|로지)/.test(trimmed);
|
|
126
|
+
}
|
|
127
|
+
/** The parties a list of names (contracts, documents) means, one per `nameKey`, spelled the way the ledger spells it most. */
|
|
128
|
+
function partiesFromNames(names) {
|
|
129
|
+
const groups = new Map();
|
|
130
|
+
for (const raw of names) {
|
|
131
|
+
const name = String(raw ?? '').trim();
|
|
132
|
+
const key = nameKey(name);
|
|
133
|
+
if (key.length < MIN_KEY)
|
|
134
|
+
continue;
|
|
135
|
+
const spellings = groups.get(key) ?? new Map();
|
|
136
|
+
spellings.set(name, (spellings.get(name) ?? 0) + 1);
|
|
137
|
+
groups.set(key, spellings);
|
|
138
|
+
}
|
|
139
|
+
return [...groups.values()]
|
|
140
|
+
.map(spellings => {
|
|
141
|
+
/* The spelling used most; on a tie the one without a corporate marker, then the shortest. */
|
|
142
|
+
const variants = [...spellings.entries()].sort((a, b) => b[1] - a[1] || marker(a[0]) - marker(b[0]) || a[0].length - b[0].length).map(([one]) => one);
|
|
143
|
+
const count = [...spellings.values()].reduce((sum, one) => sum + one, 0);
|
|
144
|
+
return { name: variants[0], variants, count, maybePerson: looksLikePersonName(variants[0]) };
|
|
145
|
+
})
|
|
146
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
147
|
+
}
|
|
148
|
+
const marker = (name) => (/\(\s*주\s*\)|㈜|주식회사/.test(name) ? 1 : 0);
|
|
149
|
+
function aliasesOf(party) {
|
|
150
|
+
return String(party.aliases ?? '')
|
|
151
|
+
.split(/[\n,]/)
|
|
152
|
+
.map(one => one.trim())
|
|
153
|
+
.filter(Boolean);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* A function telling which party a name is — the party's name or one of its aliases, spelled any way
|
|
157
|
+
* `nameKey` folds (§ a contract's 상호). An exact match, not a search.
|
|
158
|
+
*/
|
|
159
|
+
function partyNamed(parties) {
|
|
160
|
+
const byKey = new Map();
|
|
161
|
+
for (const party of parties)
|
|
162
|
+
for (const name of [party.name, ...aliasesOf(party)])
|
|
163
|
+
byKey.set(nameKey(name), party);
|
|
164
|
+
return name => (nameKey(name) ? byKey.get(nameKey(name)) : undefined);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* A function telling which party a text names. The longest matching name or alias wins; two
|
|
168
|
+
* different parties matching equally long is ambiguous — no answer.
|
|
169
|
+
*/
|
|
170
|
+
function matcherFor(parties) {
|
|
171
|
+
const keys = [];
|
|
172
|
+
for (const party of parties) {
|
|
173
|
+
for (const name of [party.name, ...aliasesOf(party)]) {
|
|
174
|
+
const key = nameKey(name);
|
|
175
|
+
if (key.length >= MIN_KEY)
|
|
176
|
+
keys.push({ key, party });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
keys.sort((a, b) => b.key.length - a.key.length);
|
|
180
|
+
return text => {
|
|
181
|
+
const hay = nameKey(text);
|
|
182
|
+
if (!hay)
|
|
183
|
+
return undefined;
|
|
184
|
+
const hits = keys.filter(one => hay.includes(one.key));
|
|
185
|
+
if (!hits.length)
|
|
186
|
+
return undefined;
|
|
187
|
+
const longest = hits[0].key.length;
|
|
188
|
+
const top = new Set(hits.filter(one => one.key.length === longest).map(one => one.party.id));
|
|
189
|
+
return top.size === 1 ? hits[0].party : undefined;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/** The texts left unmatched most often — what a person might add as aliases. */
|
|
193
|
+
function frequentUnmatched(texts, limit = 30) {
|
|
194
|
+
const counts = new Map();
|
|
195
|
+
for (const raw of texts) {
|
|
196
|
+
const text = String(raw ?? '').trim();
|
|
197
|
+
if (!text)
|
|
198
|
+
continue;
|
|
199
|
+
counts.set(text, (counts.get(text) ?? 0) + 1);
|
|
200
|
+
}
|
|
201
|
+
return [...counts.entries()]
|
|
202
|
+
.map(([text, count]) => ({ text, count }))
|
|
203
|
+
.sort((a, b) => b.count - a.count || a.text.localeCompare(b.text))
|
|
204
|
+
.slice(0, limit);
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=counterparty-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counterparty-names.js","sourceRoot":"","sources":["../../../server/service/counterparty/counterparty-names.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * How names point at counterparties — one place for every module that keeps a name and a link.\n *\n * A document (a contract, a bank line, an invoice) records **the name as it was** and, when the domain knows that\n * party, a link to it. The name stays even if the party is renamed later. Names are compared the way people mean\n * them (§`nameKey`), and a counterparty's aliases count as its names.\n *\n * Pure: the caller hands over what it looked up.\n */\n\nimport { Refusal } from '@things-factory/shell'\n\nexport interface KnownCounterparty {\n id: string\n name: string\n}\n\n/**\n * Compare names the way people mean them — case, spacing and `(주)` / `주식회사` do not make another party.\n * NFKC folds the compatibility forms Hometax writes (`(주)` in fullwidth, `㈜`) into the plain ones.\n */\nexport function nameKey(name: string | null | undefined): string {\n return (\n String(name ?? '')\n .normalize('NFKC')\n .replace(/\\(\\s*주\\s*\\)|㈜|주식회사|\\(\\s*유\\s*\\)|유한회사/g, '')\n /* The same company written in Hangul or in Latin — 씨제이올리브네트웍스 is CJ올리브네트웍스. */\n .replace(/씨제이/g, 'cj')\n .replace(/에스케이/g, 'sk')\n .replace(/엘지/g, 'lg')\n .replace(/[\\s\\-_.·,()]+/g, '')\n .toLowerCase()\n )\n}\n\nexport type LinkChange = { counterparty?: { id: string } | null; customerName?: string | null }\n\n/**\n * What to write for the link, given the row's patch. Returns only what changes; an update that\n * touches neither the name nor the counterparty returns `{}`.\n */\nexport function linkFor(\n patch: { counterparty?: { id?: string | null } | null; customerName?: string | null },\n byId: (id: string) => KnownCounterparty | undefined,\n byName: (key: string) => KnownCounterparty | undefined\n): LinkChange {\n if (patch.counterparty !== undefined) {\n const id = patch.counterparty?.id\n if (!id) return { counterparty: null, ...('customerName' in patch ? { customerName: patch.customerName ?? null } : {}) }\n\n const known = byId(id)\n if (!known) throw new Refusal('counterparty-not-found', { id }, 'the counterparty was not found. reload and try again.')\n return { counterparty: { id: known.id }, customerName: known.name }\n }\n\n if (!('customerName' in patch)) return {}\n\n const name = patch.customerName?.trim() || null\n if (!name) return { counterparty: null, customerName: null }\n\n const known = byName(nameKey(name))\n return known ? { counterparty: { id: known.id }, customerName: name } : { counterparty: null, customerName: name }\n}\n\n/**\n * 사업자등록번호 — ten digits, stored as `123-45-67890`. Empty stays empty; anything else that is\n * not ten digits is refused rather than stored half-right.\n */\nexport function normalizeBusinessNumber(value: unknown): string | null {\n const text = String(value ?? '').trim()\n if (!text) return null\n\n const digits = text.replace(/[-\\s]/g, '')\n if (!/^\\d{10}$/.test(digits)) throw new Refusal('business-number-invalid', { text }, `'${text}' is not a business registration number (10 digits).`)\n\n return `${digits.slice(0, 3)}-${digits.slice(3, 5)}-${digits.slice(5)}`\n}\n\n/**\n * Two counterparties whose names mean the same party (§`nameKey`) — after a batch would apply.\n * Returns the clashing pair, or undefined. `(주)한빛` and `한빛` are one party; registering both\n * would split its contracts in two.\n */\nexport function nameClash(\n existing: readonly KnownCounterparty[],\n changes: readonly { id?: string; name?: string | null }[],\n deleted: readonly string[] = []\n): [string, string] | undefined {\n const after = new Map<string, string>()\n for (const one of existing) if (!deleted.includes(one.id)) after.set(one.id, one.name)\n\n let fresh = 0\n for (const change of changes) {\n if (change.id) {\n if (change.name) after.set(change.id, change.name)\n } else if (change.name) {\n after.set(`new:${fresh++}`, change.name)\n }\n }\n\n const seen = new Map<string, string>()\n for (const name of after.values()) {\n const key = nameKey(name)\n if (!key) continue\n const other = seen.get(key)\n if (other !== undefined) return [other, name]\n seen.set(key, name)\n }\n\n return undefined\n}\n\n/** Names to register: one spelling per party, skipping blanks and parties already known. */\nexport function namesToRegister(names: readonly (string | null | undefined)[], known: readonly KnownCounterparty[]): string[] {\n const taken = new Set(known.map(one => nameKey(one.name)))\n const out: string[] = []\n\n for (const name of names) {\n const trimmed = String(name ?? '').trim()\n const key = nameKey(trimmed)\n if (!key || taken.has(key)) continue\n taken.add(key)\n out.push(trimmed)\n }\n\n return out\n}\n\nexport interface PartyForMatch {\n id: string\n name: string\n aliases?: string | null\n}\n\nexport interface ProposedParty {\n name: string\n variants: string[]\n count: number\n maybePerson: boolean\n}\n\n/** Keys shorter than this match too much by accident. */\nconst MIN_KEY = 2\n\nconst SURNAMES = new Set('김이박최정강조윤장임한오서신권황안송류전홍고문양손배백허유남심노하곽성차주우구민진지엄채원천방공현함변염여추도소석선설마길연위표명기반왕금옥육인맹제모탁국어은편용예경봉사부가복태목형피두감음빈동온호범좌팽승간상갈단견당'.split(''))\n\nexport function looksLikePersonName(name: string): boolean {\n const trimmed = name.trim()\n return /^[가-힣]{2,4}$/.test(trimmed) && trimmed.length === 3 && SURNAMES.has(trimmed[0]) && !/(테크|솔루션|푸드|그룹|시스템|컴|넷|랩|소프트|산업|상사|물산|로지)/.test(trimmed)\n}\n\n/** The parties a list of names (contracts, documents) means, one per `nameKey`, spelled the way the ledger spells it most. */\nexport function partiesFromNames(names: readonly (string | null | undefined)[]): ProposedParty[] {\n const groups = new Map<string, Map<string, number>>()\n for (const raw of names) {\n const name = String(raw ?? '').trim()\n const key = nameKey(name)\n if (key.length < MIN_KEY) continue\n const spellings = groups.get(key) ?? new Map<string, number>()\n spellings.set(name, (spellings.get(name) ?? 0) + 1)\n groups.set(key, spellings)\n }\n\n return [...groups.values()]\n .map(spellings => {\n /* The spelling used most; on a tie the one without a corporate marker, then the shortest. */\n const variants = [...spellings.entries()].sort((a, b) => b[1] - a[1] || marker(a[0]) - marker(b[0]) || a[0].length - b[0].length).map(([one]) => one)\n const count = [...spellings.values()].reduce((sum, one) => sum + one, 0)\n return { name: variants[0], variants, count, maybePerson: looksLikePersonName(variants[0]) }\n })\n .sort((a, b) => a.name.localeCompare(b.name))\n}\n\nconst marker = (name: string) => (/\\(\\s*주\\s*\\)|㈜|주식회사/.test(name) ? 1 : 0)\n\nexport function aliasesOf(party: PartyForMatch): string[] {\n return String(party.aliases ?? '')\n .split(/[\\n,]/)\n .map(one => one.trim())\n .filter(Boolean)\n}\n\n/**\n * A function telling which party a name is — the party's name or one of its aliases, spelled any way\n * `nameKey` folds (§ a contract's 상호). An exact match, not a search.\n */\nexport function partyNamed(parties: readonly PartyForMatch[]): (name: string | null | undefined) => PartyForMatch | undefined {\n const byKey = new Map<string, PartyForMatch>()\n for (const party of parties) for (const name of [party.name, ...aliasesOf(party)]) byKey.set(nameKey(name), party)\n return name => (nameKey(name) ? byKey.get(nameKey(name)) : undefined)\n}\n\n/**\n * A function telling which party a text names. The longest matching name or alias wins; two\n * different parties matching equally long is ambiguous — no answer.\n */\nexport function matcherFor(parties: readonly PartyForMatch[]): (text: string | null | undefined) => PartyForMatch | undefined {\n const keys: { key: string; party: PartyForMatch }[] = []\n for (const party of parties) {\n for (const name of [party.name, ...aliasesOf(party)]) {\n const key = nameKey(name)\n if (key.length >= MIN_KEY) keys.push({ key, party })\n }\n }\n keys.sort((a, b) => b.key.length - a.key.length)\n\n return text => {\n const hay = nameKey(text)\n if (!hay) return undefined\n const hits = keys.filter(one => hay.includes(one.key))\n if (!hits.length) return undefined\n const longest = hits[0].key.length\n const top = new Set(hits.filter(one => one.key.length === longest).map(one => one.party.id))\n return top.size === 1 ? hits[0].party : undefined\n }\n}\n\n/** The texts left unmatched most often — what a person might add as aliases. */\nexport function frequentUnmatched(texts: readonly (string | null | undefined)[], limit = 30): { text: string; count: number }[] {\n const counts = new Map<string, number>()\n for (const raw of texts) {\n const text = String(raw ?? '').trim()\n if (!text) continue\n counts.set(text, (counts.get(text) ?? 0) + 1)\n }\n return [...counts.entries()]\n .map(([text, count]) => ({ text, count }))\n .sort((a, b) => b.count - a.count || a.text.localeCompare(b.text))\n .slice(0, limit)\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { User } from '@things-factory/auth-base';
|
|
2
|
+
import { Domain, ListParam } from '@things-factory/shell';
|
|
3
|
+
import { Counterparty } from './counterparty';
|
|
4
|
+
import { CounterpartyList } from './counterparty-type';
|
|
5
|
+
export declare class CounterpartyQuery {
|
|
6
|
+
counterparty(id: string, context: ResolverContext): Promise<Counterparty | null>;
|
|
7
|
+
counterparties(params: ListParam, context: ResolverContext): Promise<CounterpartyList>;
|
|
8
|
+
domain(counterparty: Counterparty): Promise<Domain | null>;
|
|
9
|
+
creator(counterparty: Counterparty): Promise<User | null>;
|
|
10
|
+
updater(counterparty: Counterparty): Promise<User | null>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CounterpartyQuery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const counterparty_1 = require("./counterparty");
|
|
9
|
+
const counterparty_type_1 = require("./counterparty-type");
|
|
10
|
+
let CounterpartyQuery = class CounterpartyQuery {
|
|
11
|
+
async counterparty(id, context) {
|
|
12
|
+
return await (0, shell_1.getRepository)(counterparty_1.Counterparty).findOne({ where: { domain: { id: context.state.domain.id }, id } });
|
|
13
|
+
}
|
|
14
|
+
async counterparties(params, context) {
|
|
15
|
+
const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
|
|
16
|
+
domain: context.state.domain,
|
|
17
|
+
params,
|
|
18
|
+
repository: (0, shell_1.getRepository)(counterparty_1.Counterparty),
|
|
19
|
+
searchables: ['name', 'aliases', 'businessNumber', 'representative', 'notes'],
|
|
20
|
+
alias: 'counterparty'
|
|
21
|
+
});
|
|
22
|
+
queryBuilder.addOrderBy('counterparty.name', 'ASC');
|
|
23
|
+
const [items, total] = await queryBuilder.getManyAndCount();
|
|
24
|
+
return { items, total };
|
|
25
|
+
}
|
|
26
|
+
async domain(counterparty) {
|
|
27
|
+
return counterparty.domain ?? (counterparty.domainId ? await (0, shell_1.getRepository)(shell_1.Domain).findOneBy({ id: counterparty.domainId }) : null);
|
|
28
|
+
}
|
|
29
|
+
async creator(counterparty) {
|
|
30
|
+
return counterparty.creator ?? (counterparty.creatorId ? await (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: counterparty.creatorId }) : null);
|
|
31
|
+
}
|
|
32
|
+
async updater(counterparty) {
|
|
33
|
+
return counterparty.updater ?? (counterparty.updaterId ? await (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: counterparty.updaterId }) : null);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
exports.CounterpartyQuery = CounterpartyQuery;
|
|
37
|
+
tslib_1.__decorate([
|
|
38
|
+
(0, type_graphql_1.Directive)('@privilege(category: "counterparty", privilege: "query", domainOwnerGranted: true)'),
|
|
39
|
+
(0, type_graphql_1.Query)(returns => counterparty_1.Counterparty, { nullable: true, description: 'To fetch a counterparty of the domain' }),
|
|
40
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
41
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
42
|
+
tslib_1.__metadata("design:type", Function),
|
|
43
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
44
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
45
|
+
], CounterpartyQuery.prototype, "counterparty", null);
|
|
46
|
+
tslib_1.__decorate([
|
|
47
|
+
(0, type_graphql_1.Directive)('@privilege(category: "counterparty", privilege: "query", domainOwnerGranted: true)'),
|
|
48
|
+
(0, type_graphql_1.Query)(returns => counterparty_type_1.CounterpartyList, { description: "To fetch a page of the domain's counterparties" }),
|
|
49
|
+
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
50
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
51
|
+
tslib_1.__metadata("design:type", Function),
|
|
52
|
+
tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
|
|
53
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
54
|
+
], CounterpartyQuery.prototype, "counterparties", null);
|
|
55
|
+
tslib_1.__decorate([
|
|
56
|
+
(0, type_graphql_1.FieldResolver)(type => shell_1.Domain, { nullable: true }),
|
|
57
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
58
|
+
tslib_1.__metadata("design:type", Function),
|
|
59
|
+
tslib_1.__metadata("design:paramtypes", [counterparty_1.Counterparty]),
|
|
60
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
61
|
+
], CounterpartyQuery.prototype, "domain", null);
|
|
62
|
+
tslib_1.__decorate([
|
|
63
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
|
|
64
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
65
|
+
tslib_1.__metadata("design:type", Function),
|
|
66
|
+
tslib_1.__metadata("design:paramtypes", [counterparty_1.Counterparty]),
|
|
67
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
68
|
+
], CounterpartyQuery.prototype, "creator", null);
|
|
69
|
+
tslib_1.__decorate([
|
|
70
|
+
(0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true }),
|
|
71
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
72
|
+
tslib_1.__metadata("design:type", Function),
|
|
73
|
+
tslib_1.__metadata("design:paramtypes", [counterparty_1.Counterparty]),
|
|
74
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
75
|
+
], CounterpartyQuery.prototype, "updater", null);
|
|
76
|
+
exports.CounterpartyQuery = CounterpartyQuery = tslib_1.__decorate([
|
|
77
|
+
(0, type_graphql_1.Resolver)(counterparty_1.Counterparty)
|
|
78
|
+
], CounterpartyQuery);
|
|
79
|
+
//# sourceMappingURL=counterparty-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counterparty-query.js","sourceRoot":"","sources":["../../../server/service/counterparty/counterparty-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\n\nimport { Counterparty } from './counterparty'\nimport { CounterpartyList } from './counterparty-type'\n\n@Resolver(Counterparty)\nexport class CounterpartyQuery {\n @Directive('@privilege(category: \"counterparty\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Counterparty, { nullable: true, description: 'To fetch a counterparty of the domain' })\n async counterparty(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Counterparty | null> {\n return await getRepository(Counterparty).findOne({ where: { domain: { id: context.state.domain.id }, id } })\n }\n\n @Directive('@privilege(category: \"counterparty\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => CounterpartyList, { description: \"To fetch a page of the domain's counterparties\" })\n async counterparties(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<CounterpartyList> {\n const queryBuilder = getQueryBuilderFromListParams({\n domain: context.state.domain,\n params,\n repository: getRepository(Counterparty),\n searchables: ['name', 'aliases', 'businessNumber', 'representative', 'notes'],\n alias: 'counterparty'\n })\n queryBuilder.addOrderBy('counterparty.name', 'ASC')\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n @FieldResolver(type => Domain, { nullable: true })\n async domain(@Root() counterparty: Counterparty): Promise<Domain | null> {\n return counterparty.domain ?? (counterparty.domainId ? await getRepository(Domain).findOneBy({ id: counterparty.domainId }) : null)\n }\n\n @FieldResolver(type => User, { nullable: true })\n async creator(@Root() counterparty: Counterparty): Promise<User | null> {\n return counterparty.creator ?? (counterparty.creatorId ? await getRepository(User).findOneBy({ id: counterparty.creatorId }) : null)\n }\n\n @FieldResolver(type => User, { nullable: true })\n async updater(@Root() counterparty: Counterparty): Promise<User | null> {\n return counterparty.updater ?? (counterparty.updaterId ? await getRepository(User).findOneBy({ id: counterparty.updaterId }) : null)\n }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { EntityManager } from 'typeorm';
|
|
2
|
+
import { Counterparty } from './counterparty';
|
|
3
|
+
import { CounterpartyPatch } from './counterparty-type';
|
|
4
|
+
/**
|
|
5
|
+
* Saving the counterparty list of a domain, and what an app does once it is saved.
|
|
6
|
+
*
|
|
7
|
+
* A module whose documents keep a counterparty's name (a contract, a bank line) links the rows that carry a newly
|
|
8
|
+
* registered name — that is its rule, not this one's — by listening here (§`onCounterpartiesSaved`).
|
|
9
|
+
*/
|
|
10
|
+
type Saved = (tx: EntityManager, domain: {
|
|
11
|
+
id: string;
|
|
12
|
+
}, saved: Counterparty[]) => Promise<void>;
|
|
13
|
+
/** Run after every save of counterparties, in the same transaction. */
|
|
14
|
+
export declare function onCounterpartiesSaved(listener: Saved): void;
|
|
15
|
+
/**
|
|
16
|
+
* Apply grid rows to a domain's counterparties: `+` (or no id) registers, `M` changes, `-` deletes (softly — the rows
|
|
17
|
+
* that name it keep the name). Two counterparties whose names mean the same party are refused (§`nameClash`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function saveCounterparties(tx: EntityManager, domain: {
|
|
20
|
+
id: string;
|
|
21
|
+
}, user: any, patches: CounterpartyPatch[]): Promise<Counterparty[]>;
|
|
22
|
+
export {};
|