@things-factory/accounting 10.1.206 → 10.1.209
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/activities/activity-expenditure.js +5 -2
- package/dist-server/activities/activity-expenditure.js.map +1 -1
- package/dist-server/service/account/account-match.d.ts +4 -5
- package/dist-server/service/account/account-match.js +7 -8
- package/dist-server/service/account/account-match.js.map +1 -1
- package/dist-server/service/account/account-mutation.js +5 -7
- package/dist-server/service/account/account-mutation.js.map +1 -1
- package/dist-server/service/account/account-service.d.ts +5 -0
- package/dist-server/service/account/account-service.js +17 -0
- package/dist-server/service/account/account-service.js.map +1 -0
- package/dist-server/service/bank-account/bank-account-service.d.ts +4 -1
- package/dist-server/service/bank-account/bank-account-service.js +5 -1
- package/dist-server/service/bank-account/bank-account-service.js.map +1 -1
- package/dist-server/service/expenditure-request/expenditure-request-item.d.ts +4 -3
- package/dist-server/service/expenditure-request/expenditure-request-item.js +6 -5
- package/dist-server/service/expenditure-request/expenditure-request-item.js.map +1 -1
- package/dist-server/service/expenditure-request/expenditure-request-mutation.d.ts +2 -2
- package/dist-server/service/expenditure-request/expenditure-request-mutation.js +13 -11
- package/dist-server/service/expenditure-request/expenditure-request-mutation.js.map +1 -1
- package/dist-server/service/expenditure-request/expenditure-request-query.d.ts +9 -2
- package/dist-server/service/expenditure-request/expenditure-request-query.js +28 -6
- package/dist-server/service/expenditure-request/expenditure-request-query.js.map +1 -1
- package/dist-server/service/expenditure-request/expenditure-request-service.d.ts +14 -4
- package/dist-server/service/expenditure-request/expenditure-request-service.js +47 -9
- package/dist-server/service/expenditure-request/expenditure-request-service.js.map +1 -1
- package/dist-server/service/expenditure-request/expenditure-request-type.d.ts +1 -1
- package/dist-server/service/expenditure-request/expenditure-request-type.js +3 -3
- package/dist-server/service/expenditure-request/expenditure-request-type.js.map +1 -1
- package/dist-server/service/expenditure-request/receipt-reader.d.ts +18 -9
- package/dist-server/service/expenditure-request/receipt-reader.js +19 -10
- package/dist-server/service/expenditure-request/receipt-reader.js.map +1 -1
- package/dist-server/service/index.d.ts +1 -0
- package/dist-server/service/index.js +1 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/payment/index.js +3 -0
- package/dist-server/service/payment/index.js.map +1 -1
- package/dist-server/service/recurring-cash-item/recurring-cash-item-mutation.d.ts +0 -1
- package/dist-server/service/recurring-cash-item/recurring-cash-item-mutation.js +0 -17
- package/dist-server/service/recurring-cash-item/recurring-cash-item-mutation.js.map +1 -1
- package/dist-server/service/recurring-cash-item/recurring-cash-item-service.d.ts +4 -8
- package/dist-server/service/recurring-cash-item/recurring-cash-item-service.js +5 -38
- package/dist-server/service/recurring-cash-item/recurring-cash-item-service.js.map +1 -1
- package/dist-server/service/recurring-cash-item/recurring-cash-item-type.js +1 -1
- package/dist-server/service/recurring-cash-item/recurring-cash-item-type.js.map +1 -1
- package/dist-server/service/recurring-cash-item/recurring-cash-item.d.ts +2 -2
- package/dist-server/service/recurring-cash-item/recurring-cash-item.js +5 -5
- package/dist-server/service/recurring-cash-item/recurring-cash-item.js.map +1 -1
- package/dist-server/service/recurring-cash-item/recurring-schedule.d.ts +6 -18
- package/dist-server/service/recurring-cash-item/recurring-schedule.js +13 -26
- package/dist-server/service/recurring-cash-item/recurring-schedule.js.map +1 -1
- package/dist-server/service/transaction/transaction-history.d.ts +1 -7
- package/dist-server/service/transaction/transaction-history.js +0 -25
- package/dist-server/service/transaction/transaction-history.js.map +1 -1
- package/dist-server/service/transaction/transaction-period.d.ts +0 -8
- package/dist-server/service/transaction/transaction-period.js +0 -30
- package/dist-server/service/transaction/transaction-period.js.map +1 -1
- package/dist-server/service/transaction/transaction-query.d.ts +0 -2
- package/dist-server/service/transaction/transaction-query.js +2 -16
- package/dist-server/service/transaction/transaction-query.js.map +1 -1
- package/dist-server/service/transaction/transaction-service.d.ts +4 -6
- package/dist-server/service/transaction/transaction-service.js +10 -35
- package/dist-server/service/transaction/transaction-service.js.map +1 -1
- package/dist-server/service/transaction/transaction-type.d.ts +1 -15
- package/dist-server/service/transaction/transaction-type.js +2 -58
- package/dist-server/service/transaction/transaction-type.js.map +1 -1
- package/dist-server/service/transaction/transaction.d.ts +6 -15
- package/dist-server/service/transaction/transaction.js +13 -52
- package/dist-server/service/transaction/transaction.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/translations/en.json +12 -6
- package/translations/es.json +12 -6
- package/translations/ja.json +11 -1
- package/translations/ko.json +13 -7
- package/translations/ms.json +11 -1
- package/translations/zh.json +11 -1
|
@@ -12,19 +12,19 @@ const expenditure_request_service_1 = require("./expenditure-request-service");
|
|
|
12
12
|
const expenditure_request_type_1 = require("./expenditure-request-type");
|
|
13
13
|
let ExpenditureRequestMutation = class ExpenditureRequestMutation {
|
|
14
14
|
/** Write a request and its lines. A new request is the caller's; an existing one only its requester's, while editable. */
|
|
15
|
-
async saveExpenditureRequest(request, items, context) {
|
|
15
|
+
async saveExpenditureRequest(request, items, unpaidInvoicesOnly, context) {
|
|
16
16
|
const { domain, user, tx, unsafeIP, prohibitedPrivileges } = context.state;
|
|
17
17
|
const taxInvoices = await (0, auth_base_1.checkPermission)({ category: 'tax-invoice', privilege: 'query', owner: false }, user, domain, unsafeIP, prohibitedPrivileges);
|
|
18
|
-
return await (0, expenditure_request_service_1.saveRequest)(tx, domain, user, request, items ?? [], { taxInvoices });
|
|
18
|
+
return await (0, expenditure_request_service_1.saveRequest)(tx, domain, user, request, items ?? [], { taxInvoices, unpaidInvoicesOnly: !!unpaidInvoicesOnly });
|
|
19
19
|
}
|
|
20
20
|
/** One line from the phone - it joins this month's editable reimbursement, or starts one. */
|
|
21
21
|
async addExpenditureLine(line, context) {
|
|
22
22
|
const { domain, user, tx } = context.state;
|
|
23
23
|
return await (0, expenditure_request_service_1.addLine)(tx, domain, user, line, context);
|
|
24
24
|
}
|
|
25
|
-
async
|
|
25
|
+
async saveExpenditureLineFiles(itemId, attach, remove, context) {
|
|
26
26
|
const { domain, user, tx } = context.state;
|
|
27
|
-
return await (0, expenditure_request_service_1.
|
|
27
|
+
return await (0, expenditure_request_service_1.saveLineFiles)(tx, domain, user, itemId, { attach: attach ?? [], remove: remove ?? [] }, context);
|
|
28
28
|
}
|
|
29
29
|
async submitExpenditureRequest(id, context) {
|
|
30
30
|
const { domain, user, tx } = context.state;
|
|
@@ -56,9 +56,10 @@ tslib_1.__decorate([
|
|
|
56
56
|
(0, type_graphql_1.Mutation)(returns => expenditure_request_1.ExpenditureRequest, { description: 'Save an expenditure request and its lines' }),
|
|
57
57
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('request', type => expenditure_request_type_1.ExpenditureRequestInput)),
|
|
58
58
|
tslib_1.__param(1, (0, type_graphql_1.Arg)('items', type => [expenditure_request_type_1.ExpenditureRequestItemPatch], { nullable: true })),
|
|
59
|
-
tslib_1.__param(2, (0, type_graphql_1.
|
|
59
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('unpaidInvoicesOnly', type => Boolean, { nullable: true })),
|
|
60
|
+
tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
|
|
60
61
|
tslib_1.__metadata("design:type", Function),
|
|
61
|
-
tslib_1.__metadata("design:paramtypes", [expenditure_request_type_1.ExpenditureRequestInput, Array, Object]),
|
|
62
|
+
tslib_1.__metadata("design:paramtypes", [expenditure_request_type_1.ExpenditureRequestInput, Array, Boolean, Object]),
|
|
62
63
|
tslib_1.__metadata("design:returntype", Promise)
|
|
63
64
|
], ExpenditureRequestMutation.prototype, "saveExpenditureRequest", null);
|
|
64
65
|
tslib_1.__decorate([
|
|
@@ -74,14 +75,15 @@ tslib_1.__decorate([
|
|
|
74
75
|
tslib_1.__decorate([
|
|
75
76
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
76
77
|
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "mutation", domainOwnerGranted: true)'),
|
|
77
|
-
(0, type_graphql_1.Mutation)(returns => expenditure_request_item_1.ExpenditureRequestItem, { description:
|
|
78
|
+
(0, type_graphql_1.Mutation)(returns => expenditure_request_item_1.ExpenditureRequestItem, { description: "Attach files to a line and take others off it - the line's receipts and papers" }),
|
|
78
79
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('itemId')),
|
|
79
|
-
tslib_1.__param(1, (0, type_graphql_1.Arg)('
|
|
80
|
-
tslib_1.__param(2, (0, type_graphql_1.
|
|
80
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('attach', type => [GraphQLUpload_js_1.default], { nullable: true })),
|
|
81
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('remove', type => [String], { nullable: true })),
|
|
82
|
+
tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
|
|
81
83
|
tslib_1.__metadata("design:type", Function),
|
|
82
|
-
tslib_1.__metadata("design:paramtypes", [String,
|
|
84
|
+
tslib_1.__metadata("design:paramtypes", [String, Array, Array, Object]),
|
|
83
85
|
tslib_1.__metadata("design:returntype", Promise)
|
|
84
|
-
], ExpenditureRequestMutation.prototype, "
|
|
86
|
+
], ExpenditureRequestMutation.prototype, "saveExpenditureLineFiles", null);
|
|
85
87
|
tslib_1.__decorate([
|
|
86
88
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
87
89
|
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "mutation", domainOwnerGranted: true)'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expenditure-request-mutation.js","sourceRoot":"","sources":["../../../server/service/expenditure-request/expenditure-request-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Float, Mutation, Resolver, UseMiddleware } from 'type-graphql'\n\nimport type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\n\nimport { checkPermission } from '@things-factory/auth-base'\nimport { SpeakRefusals } from '@things-factory/shell'\n\nimport { ExpenditureRequest } from './expenditure-request'\nimport { ExpenditureRequestItem } from './expenditure-request-item'\nimport { addLine, deleteRequest, payRequests, payWithLine, replaceReceipt, saveRequest, submitRequest, withdrawRequest } from './expenditure-request-service'\nimport { ExpenditurePaymentInput, ExpenditureRequestInput, ExpenditureRequestItemPatch, NewExpenditureLine } from './expenditure-request-type'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(ExpenditureRequest)\nexport class ExpenditureRequestMutation {\n /** Write a request and its lines. A new request is the caller's; an existing one only its requester's, while editable. */\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: 'Save an expenditure request and its lines' })\n async saveExpenditureRequest(\n @Arg('request', type => ExpenditureRequestInput) request: ExpenditureRequestInput,\n @Arg('items', type => [ExpenditureRequestItemPatch], { nullable: true }) items: ExpenditureRequestItemPatch[],\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureRequest> {\n const { domain, user, tx, unsafeIP, prohibitedPrivileges } = context.state\n const taxInvoices = await checkPermission({ category: 'tax-invoice', privilege: 'query', owner: false }, user, domain, unsafeIP, prohibitedPrivileges)\n return await saveRequest(tx, domain, user, request, items ?? [], { taxInvoices })\n }\n\n /** One line from the phone - it joins this month's editable reimbursement, or starts one. */\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: \"Add one expense line to the caller's reimbursement of that month\" })\n async addExpenditureLine(@Arg('line', type => NewExpenditureLine) line: NewExpenditureLine, @Ctx() context: ResolverContext): Promise<ExpenditureRequest> {\n const { domain, user, tx } = context.state\n return await addLine(tx, domain, user, line, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequestItem, { description: 'Put (or replace) the receipt of a line' })\n async attachExpenditureReceipt(\n @Arg('itemId') itemId: string,\n @Arg('file', type => GraphQLUpload) file: FileUpload,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureRequestItem> {\n const { domain, user, tx } = context.state\n return await replaceReceipt(tx, domain, user, itemId, file, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: 'Put an expenditure request up for approval (상신)' })\n async submitExpenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest> {\n const { domain, user, tx } = context.state\n return await submitRequest(tx, domain, user, id, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: 'Take a submitted request back from its approvers (회수)' })\n async withdrawExpenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest> {\n const { domain, user, tx } = context.state\n return await withdrawRequest(tx, domain, user, id, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, { description: 'Delete an editable expenditure request of the caller' })\n async deleteExpenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, user, tx } = context.state\n return await deleteRequest(tx, domain, user, id)\n }\n\n /** Finance paid approved requests at the bank; each becomes a withdrawal that the next statement import matches. */\n @Directive('@transaction')\n @Directive('@privilege(category: \"expenditure\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [ExpenditureRequest], { description: 'Record that approved expenditure requests were paid' })\n async payExpenditureRequests(\n @Arg('ids', type => [String]) ids: string[],\n @Arg('payment', type => ExpenditurePaymentInput) payment: ExpenditurePaymentInput,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureRequest[]> {\n const { domain, user, tx } = context.state\n return await payRequests(tx, domain, user, ids, payment)\n }\n\n /** Pay a request with a withdrawal already in the books - a bank statement brought it in first. */\n @Directive('@transaction')\n @Directive('@privilege(category: \"expenditure\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: 'Put a withdrawal already in the books on an approved expenditure request' })\n async payExpenditureRequestWithLine(\n @Arg('id') id: string,\n @Arg('transactionId') transactionId: string,\n @Arg('amount', type => Float, { nullable: true }) amount: number,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureRequest> {\n const { domain, user, tx } = context.state\n return await payWithLine(tx, domain, user, id, transactionId, amount)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"expenditure-request-mutation.js","sourceRoot":"","sources":["../../../server/service/expenditure-request/expenditure-request-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Float, Mutation, Resolver, UseMiddleware } from 'type-graphql'\n\nimport type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\n\nimport { checkPermission } from '@things-factory/auth-base'\nimport { SpeakRefusals } from '@things-factory/shell'\n\nimport { ExpenditureRequest } from './expenditure-request'\nimport { ExpenditureRequestItem } from './expenditure-request-item'\nimport { addLine, deleteRequest, payRequests, payWithLine, saveLineFiles, saveRequest, submitRequest, withdrawRequest } from './expenditure-request-service'\nimport { ExpenditurePaymentInput, ExpenditureRequestInput, ExpenditureRequestItemPatch, NewExpenditureLine } from './expenditure-request-type'\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(ExpenditureRequest)\nexport class ExpenditureRequestMutation {\n /** Write a request and its lines. A new request is the caller's; an existing one only its requester's, while editable. */\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: 'Save an expenditure request and its lines' })\n async saveExpenditureRequest(\n @Arg('request', type => ExpenditureRequestInput) request: ExpenditureRequestInput,\n @Arg('items', type => [ExpenditureRequestItemPatch], { nullable: true }) items: ExpenditureRequestItemPatch[],\n @Arg('unpaidInvoicesOnly', type => Boolean, { nullable: true }) unpaidInvoicesOnly: boolean,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureRequest> {\n const { domain, user, tx, unsafeIP, prohibitedPrivileges } = context.state\n const taxInvoices = await checkPermission({ category: 'tax-invoice', privilege: 'query', owner: false }, user, domain, unsafeIP, prohibitedPrivileges)\n return await saveRequest(tx, domain, user, request, items ?? [], { taxInvoices, unpaidInvoicesOnly: !!unpaidInvoicesOnly })\n }\n\n /** One line from the phone - it joins this month's editable reimbursement, or starts one. */\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: \"Add one expense line to the caller's reimbursement of that month\" })\n async addExpenditureLine(@Arg('line', type => NewExpenditureLine) line: NewExpenditureLine, @Ctx() context: ResolverContext): Promise<ExpenditureRequest> {\n const { domain, user, tx } = context.state\n return await addLine(tx, domain, user, line, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequestItem, { description: \"Attach files to a line and take others off it - the line's receipts and papers\" })\n async saveExpenditureLineFiles(\n @Arg('itemId') itemId: string,\n @Arg('attach', type => [GraphQLUpload], { nullable: true }) attach: FileUpload[],\n @Arg('remove', type => [String], { nullable: true }) remove: string[],\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureRequestItem> {\n const { domain, user, tx } = context.state\n return await saveLineFiles(tx, domain, user, itemId, { attach: attach ?? [], remove: remove ?? [] }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: 'Put an expenditure request up for approval (상신)' })\n async submitExpenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest> {\n const { domain, user, tx } = context.state\n return await submitRequest(tx, domain, user, id, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: 'Take a submitted request back from its approvers (회수)' })\n async withdrawExpenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest> {\n const { domain, user, tx } = context.state\n return await withdrawRequest(tx, domain, user, id, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"accounting-self\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, { description: 'Delete an editable expenditure request of the caller' })\n async deleteExpenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, user, tx } = context.state\n return await deleteRequest(tx, domain, user, id)\n }\n\n /** Finance paid approved requests at the bank; each becomes a withdrawal that the next statement import matches. */\n @Directive('@transaction')\n @Directive('@privilege(category: \"expenditure\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [ExpenditureRequest], { description: 'Record that approved expenditure requests were paid' })\n async payExpenditureRequests(\n @Arg('ids', type => [String]) ids: string[],\n @Arg('payment', type => ExpenditurePaymentInput) payment: ExpenditurePaymentInput,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureRequest[]> {\n const { domain, user, tx } = context.state\n return await payRequests(tx, domain, user, ids, payment)\n }\n\n /** Pay a request with a withdrawal already in the books - a bank statement brought it in first. */\n @Directive('@transaction')\n @Directive('@privilege(category: \"expenditure\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ExpenditureRequest, { description: 'Put a withdrawal already in the books on an approved expenditure request' })\n async payExpenditureRequestWithLine(\n @Arg('id') id: string,\n @Arg('transactionId') transactionId: string,\n @Arg('amount', type => Float, { nullable: true }) amount: number,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureRequest> {\n const { domain, user, tx } = context.state\n return await payWithLine(tx, domain, user, id, transactionId, amount)\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Domain, ListParam } from '@things-factory/shell';
|
|
2
2
|
import { User } from '@things-factory/auth-base';
|
|
3
|
+
import { Attachment } from '@things-factory/attachment-base';
|
|
3
4
|
import { Counterparty, CounterpartyBankAccount } from '@things-factory/biz-base';
|
|
4
5
|
import { Department } from '@things-factory/organization';
|
|
5
6
|
import { TaxInvoice } from '@things-factory/tax-invoice';
|
|
@@ -17,6 +18,12 @@ export declare class ExpenditureRequestQuery {
|
|
|
17
18
|
/** Every request of the domain - what finance sees. */
|
|
18
19
|
expenditureRequests(params: ListParam, context: ResolverContext): Promise<ExpenditureRequestList>;
|
|
19
20
|
expenditureRequest(id: string, context: ResolverContext): Promise<ExpenditureRequest | null>;
|
|
21
|
+
/**
|
|
22
|
+
* One request as its approvers read it - the lines and their files. Open to whoever may open those files: its writer,
|
|
23
|
+
* whoever takes part in its approval, and the paying seat (§`receipt-reader.ts`). The approval card links to it.
|
|
24
|
+
* Anyone else is refused as the paying seat's door refuses them, so the 360 says 「볼 수 없음」, not 「없음」.
|
|
25
|
+
*/
|
|
26
|
+
expenditureRequestForReview(id: string, context: ResolverContext): Promise<ExpenditureRequest | null>;
|
|
20
27
|
/**
|
|
21
28
|
* The payment queue (지급 대기) - approved requests still to pay, by the day they are to be paid, and the paid ones
|
|
22
29
|
* whose bank line no statement has matched yet.
|
|
@@ -40,8 +47,8 @@ export declare class ExpenditureRequestItemQuery {
|
|
|
40
47
|
request(item: ExpenditureRequestItem): Promise<ExpenditureRequest | null>;
|
|
41
48
|
account(item: ExpenditureRequestItem): Promise<Account | null>;
|
|
42
49
|
taxInvoice(item: ExpenditureRequestItem): Promise<TaxInvoice | null>;
|
|
43
|
-
/**
|
|
44
|
-
|
|
50
|
+
/** The line's receipts and papers - so an approver sees what was spent. */
|
|
51
|
+
files(item: ExpenditureRequestItem): Promise<Attachment[]>;
|
|
45
52
|
domain(item: ExpenditureRequestItem): Promise<Domain>;
|
|
46
53
|
creator(item: ExpenditureRequestItem): Promise<User | null>;
|
|
47
54
|
updater(item: ExpenditureRequestItem): Promise<User | null>;
|
|
@@ -16,6 +16,7 @@ const expenditure_request_item_1 = require("./expenditure-request-item");
|
|
|
16
16
|
const expenditure_payment_state_1 = require("./expenditure-payment-state");
|
|
17
17
|
const expenditure_request_rules_1 = require("./expenditure-request-rules");
|
|
18
18
|
const expenditure_request_service_1 = require("./expenditure-request-service");
|
|
19
|
+
const receipt_reader_1 = require("./receipt-reader");
|
|
19
20
|
const expenditure_request_type_1 = require("./expenditure-request-type");
|
|
20
21
|
const byId = async (entity, id, withDeleted = false) => id ? (await (0, shell_1.getRepository)(entity).findOne({ where: { id }, withDeleted })) : null;
|
|
21
22
|
async function summaryOf(domain, year, month, requesterId) {
|
|
@@ -82,6 +83,19 @@ let ExpenditureRequestQuery = class ExpenditureRequestQuery {
|
|
|
82
83
|
async expenditureRequest(id, context) {
|
|
83
84
|
return await (0, shell_1.getRepository)(expenditure_request_1.ExpenditureRequest).findOne({ where: { id, domain: { id: context.state.domain.id } } });
|
|
84
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* One request as its approvers read it - the lines and their files. Open to whoever may open those files: its writer,
|
|
88
|
+
* whoever takes part in its approval, and the paying seat (§`receipt-reader.ts`). The approval card links to it.
|
|
89
|
+
* Anyone else is refused as the paying seat's door refuses them, so the 360 says 「볼 수 없음」, not 「없음」.
|
|
90
|
+
*/
|
|
91
|
+
async expenditureRequestForReview(id, context) {
|
|
92
|
+
const request = await (0, shell_1.getRepository)(expenditure_request_1.ExpenditureRequest).findOne({ where: { id, domain: { id: context.state.domain.id } } });
|
|
93
|
+
if (!request)
|
|
94
|
+
return null;
|
|
95
|
+
if (!(await (0, receipt_reader_1.mayReadRequest)(request, context, receipt_reader_1.REQUEST_READ_FACTS)))
|
|
96
|
+
throw (0, auth_base_1.privilegeRejection)(context, 'expenditure', 'query', 'role', 'query');
|
|
97
|
+
return request;
|
|
98
|
+
}
|
|
85
99
|
/**
|
|
86
100
|
* The payment queue (지급 대기) - approved requests still to pay, by the day they are to be paid, and the paid ones
|
|
87
101
|
* whose bank line no statement has matched yet.
|
|
@@ -197,6 +211,15 @@ tslib_1.__decorate([
|
|
|
197
211
|
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
198
212
|
tslib_1.__metadata("design:returntype", Promise)
|
|
199
213
|
], ExpenditureRequestQuery.prototype, "expenditureRequest", null);
|
|
214
|
+
tslib_1.__decorate([
|
|
215
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "query", domainOwnerGranted: true)'),
|
|
216
|
+
(0, type_graphql_1.Query)(returns => expenditure_request_1.ExpenditureRequest, { nullable: true, description: 'One expenditure request, for its writer, its approvers and the paying seat' }),
|
|
217
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
218
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
219
|
+
tslib_1.__metadata("design:type", Function),
|
|
220
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
221
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
222
|
+
], ExpenditureRequestQuery.prototype, "expenditureRequestForReview", null);
|
|
200
223
|
tslib_1.__decorate([
|
|
201
224
|
(0, type_graphql_1.Directive)('@privilege(category: "expenditure", privilege: "query", domainOwnerGranted: true)'),
|
|
202
225
|
(0, type_graphql_1.Query)(returns => expenditure_request_type_1.ExpenditureQueue, { description: 'Approved requests still to pay, and paid ones not yet matched to the bank' }),
|
|
@@ -309,10 +332,9 @@ let ExpenditureRequestItemQuery = class ExpenditureRequestItemQuery {
|
|
|
309
332
|
async taxInvoice(item) {
|
|
310
333
|
return item.taxInvoice ?? (await byId(tax_invoice_1.TaxInvoice, item.taxInvoiceId, true));
|
|
311
334
|
}
|
|
312
|
-
/**
|
|
313
|
-
async
|
|
314
|
-
|
|
315
|
-
return attachment?.fullpath ?? null;
|
|
335
|
+
/** The line's receipts and papers - so an approver sees what was spent. */
|
|
336
|
+
async files(item) {
|
|
337
|
+
return await (0, shell_1.getRepository)(attachment_base_1.Attachment).find({ where: { domain: { id: item.domainId }, refType: expenditure_request_service_1.RECEIPT_REF_TYPE, refBy: item.id }, order: { createdAt: 'ASC' } });
|
|
316
338
|
}
|
|
317
339
|
async domain(item) {
|
|
318
340
|
return await (0, shell_1.getRepository)(shell_1.Domain).findOneBy({ id: item.domainId });
|
|
@@ -347,12 +369,12 @@ tslib_1.__decorate([
|
|
|
347
369
|
tslib_1.__metadata("design:returntype", Promise)
|
|
348
370
|
], ExpenditureRequestItemQuery.prototype, "taxInvoice", null);
|
|
349
371
|
tslib_1.__decorate([
|
|
350
|
-
(0, type_graphql_1.FieldResolver)(type =>
|
|
372
|
+
(0, type_graphql_1.FieldResolver)(type => [attachment_base_1.Attachment]),
|
|
351
373
|
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
352
374
|
tslib_1.__metadata("design:type", Function),
|
|
353
375
|
tslib_1.__metadata("design:paramtypes", [expenditure_request_item_1.ExpenditureRequestItem]),
|
|
354
376
|
tslib_1.__metadata("design:returntype", Promise)
|
|
355
|
-
], ExpenditureRequestItemQuery.prototype, "
|
|
377
|
+
], ExpenditureRequestItemQuery.prototype, "files", null);
|
|
356
378
|
tslib_1.__decorate([
|
|
357
379
|
(0, type_graphql_1.FieldResolver)(type => shell_1.Domain),
|
|
358
380
|
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expenditure-request-query.js","sourceRoot":"","sources":["../../../server/service/expenditure-request/expenditure-request-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Int, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\nimport { Like } from 'typeorm'\n\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { Attachment } from '@things-factory/attachment-base'\nimport { accountTailOf, Counterparty, CounterpartyBankAccount } from '@things-factory/biz-base'\nimport { Department } from '@things-factory/organization'\nimport { TaxInvoice } from '@things-factory/tax-invoice'\n\nimport { Account } from '../account/account'\nimport { ExpenditureKind, ExpenditureRequest, ExpenditureRequestStatus } from './expenditure-request'\nimport { ExpenditureRequestItem } from './expenditure-request-item'\nimport { paymentStatesOf, ExpenditurePaymentState } from './expenditure-payment-state'\nimport { monthlySummary, statusCounts, type RequestStatus } from './expenditure-request-rules'\nimport { approvedWithStates, driftOf, RECEIPT_REF_TYPE } from './expenditure-request-service'\nimport { ExpenditurePayment, ExpenditureQueue, ExpenditureQueueRow, ExpenditureRequestList, ExpenditureSummary } from './expenditure-request-type'\n\nconst byId = async <T>(entity: new () => T, id: string | null | undefined, withDeleted = false): Promise<T | null> =>\n id ? ((await getRepository(entity).findOne({ where: { id } as any, withDeleted })) as T | null) : null\n\nasync function summaryOf(domain: { id: string }, year: number, month: number | undefined, requesterId?: string): Promise<ExpenditureSummary> {\n const period = month ? `${year}-${String(month).padStart(2, '0')}` : `${year}-%`\n const requests = await getRepository(ExpenditureRequest).find({\n where: {\n domain: { id: domain.id },\n kind: ExpenditureKind.REIMBURSEMENT,\n month: month ? period : Like(period),\n ...(requesterId ? { requester: { id: requesterId } } : {})\n } as any,\n relations: ['requester', 'items', 'items.account']\n })\n const shaped = requests.map(one => ({\n month: one.month,\n requesterId: one.requesterId ?? one.requester?.id,\n requesterName: one.requester?.name ?? null,\n status: one.status as RequestStatus,\n /* Summed by 계정과목; a line not yet filed counts under the category written on it. */\n items: (one.items ?? []).filter(item => !item.deletedAt).map(item => ({ ...item, category: item.account?.name ?? item.category }))\n }))\n\n const rows = monthlySummary(shaped)\n const approved = requests.filter(one => one.status === ExpenditureRequestStatus.APPROVED)\n approved.forEach(one => (one.items = (one.items ?? []).filter(item => !item.deletedAt)))\n const states = await paymentStatesOf(getRepository(ExpenditureRequest).manager, domain, approved as any)\n\n return {\n rows,\n statuses: Object.entries(statusCounts(shaped)).map(([status, count]) => ({ status, count })),\n approvedTotal: rows.reduce((sum, one) => sum + one.total, 0),\n unpaid: [...states.values()].reduce((sum, one) => sum + one.outstanding, 0)\n }\n}\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(ExpenditureRequest)\nexport class ExpenditureRequestQuery {\n /** The last four digits of the account paid into - what the requester and the approvers see (ADR-0139). */\n @FieldResolver(type => String, { nullable: true, description: \"The last four digits of the account paid into\" })\n payeeAccountTail(@Root() request: ExpenditureRequest): string | undefined {\n return accountTailOf(request.payeeAccountNumber)\n }\n\n /** The caller's own requests - what an employee sees. */\n @Directive('@privilege(category: \"accounting-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequestList, { description: \"The caller's own expenditure requests\" })\n async myExpenditureRequests(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ExpenditureRequestList> {\n const { domain, user } = context.state\n const queryBuilder = getQueryBuilderFromListParams({ domain, params, repository: getRepository(ExpenditureRequest), searchables: ['title', 'notes'], alias: 'request' })\n queryBuilder.andWhere('request.requester = :requester', { requester: user.id })\n queryBuilder.addOrderBy('request.createdAt', 'DESC')\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n /** One of the caller's own requests, with its lines. */\n @Directive('@privilege(category: \"accounting-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequest, { nullable: true, description: \"One of the caller's own expenditure requests\" })\n async myExpenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest | null> {\n const { domain, user } = context.state\n return await getRepository(ExpenditureRequest).findOne({ where: { id, domain: { id: domain.id }, requester: { id: user.id } } as any })\n }\n\n /** Every request of the domain - what finance sees. */\n /*\n * Every request, one by one - who spent what, the receipts, the queue to pay - is the paying seat's: `expenditure`\n * (the user, 2026-10-18). The month's summary stays `accounting`, which the executives read.\n */\n @Directive('@privilege(category: \"expenditure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequestList, { description: 'Every expenditure request of the domain' })\n async expenditureRequests(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ExpenditureRequestList> {\n const { domain } = context.state\n const queryBuilder = getQueryBuilderFromListParams({ domain, params, repository: getRepository(ExpenditureRequest), searchables: ['title', 'notes'], alias: 'request' })\n queryBuilder.addOrderBy('request.createdAt', 'DESC')\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"expenditure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequest, { nullable: true, description: 'One expenditure request of the domain' })\n async expenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest | null> {\n return await getRepository(ExpenditureRequest).findOne({ where: { id, domain: { id: context.state.domain.id } } as any })\n }\n\n /**\n * The payment queue (지급 대기) - approved requests still to pay, by the day they are to be paid, and the paid ones\n * whose bank line no statement has matched yet.\n */\n @Directive('@privilege(category: \"expenditure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureQueue, { description: 'Approved requests still to pay, and paid ones not yet matched to the bank' })\n async expenditureQueue(@Ctx() context: ResolverContext): Promise<ExpenditureQueue> {\n const { domain } = context.state\n const manager = getRepository(ExpenditureRequest).manager\n const { requests, states } = await approvedWithStates(manager, domain)\n\n const rows: ExpenditureQueueRow[] = []\n for (const request of requests) {\n const payment = states.get(request.id)!\n if (payment.state === ExpenditurePaymentState.NOTHING_TO_PAY) continue\n rows.push({\n request,\n payment,\n payeeName: (request.kind === ExpenditureKind.VENDOR ? request.counterparty?.name : request.requester?.name) ?? undefined,\n payeeAccountDrift: payment.outstanding > 0 ? await driftOf(manager, request) : undefined\n })\n }\n const due = (row: ExpenditureQueueRow) => row.request.dueDate ?? '9999-12-31'\n const waiting = rows\n .filter(row => row.payment.outstanding > 0)\n .sort((a, b) => due(a).localeCompare(due(b)) || String(a.request.decidedAt ?? '').localeCompare(String(b.request.decidedAt ?? '')))\n const unreconciled = rows.filter(row => row.payment.outstanding <= 0 && !row.payment.reconciled)\n return { waiting, unreconciled }\n }\n\n @Directive('@privilege(category: \"accounting\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureSummary, { description: 'Approved reimbursements per month, requester and category, with requests per status' })\n async expenditureSummary(\n @Arg('year', type => Int) year: number,\n @Arg('month', type => Int, { nullable: true }) month: number,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureSummary> {\n return await summaryOf(context.state.domain, year, month || undefined)\n }\n\n @Directive('@privilege(category: \"accounting-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureSummary, { description: \"The caller's own monthly summary of reimbursements\" })\n async myExpenditureSummary(\n @Arg('year', type => Int) year: number,\n @Arg('month', type => Int, { nullable: true }) month: number,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureSummary> {\n return await summaryOf(context.state.domain, year, month || undefined, context.state.user.id)\n }\n\n /** How far it is paid - read from its payments (ADR-0135 §2-4). */\n @FieldResolver(type => ExpenditurePayment, { nullable: true })\n async payment(@Root() request: ExpenditureRequest): Promise<ExpenditurePayment | null> {\n if (request.status !== ExpenditureRequestStatus.APPROVED) return null\n const items = await getRepository(ExpenditureRequestItem).find({ where: { request: { id: request.id } } as any })\n const states = await paymentStatesOf(getRepository(ExpenditureRequest).manager, { id: request.domainId! }, [{ id: request.id, items }])\n return states.get(request.id) ?? null\n }\n\n @FieldResolver(type => [ExpenditureRequestItem])\n async items(@Root() request: ExpenditureRequest): Promise<ExpenditureRequestItem[]> {\n if (request.items) return request.items.filter(item => !item.deletedAt)\n return await getRepository(ExpenditureRequestItem).find({ where: { request: { id: request.id } } as any, order: { spentDate: 'ASC', createdAt: 'ASC' } as any })\n }\n\n @FieldResolver(type => User, { nullable: true })\n async requester(@Root() request: ExpenditureRequest): Promise<User | null> {\n return request.requester ?? (await byId(User, request.requesterId))\n }\n\n @FieldResolver(type => Department, { nullable: true })\n async department(@Root() request: ExpenditureRequest): Promise<Department | null> {\n return request.department ?? (await byId(Department, request.departmentId))\n }\n\n @FieldResolver(type => Counterparty, { nullable: true })\n async counterparty(@Root() request: ExpenditureRequest): Promise<Counterparty | null> {\n return request.counterparty ?? (await byId(Counterparty, request.counterpartyId, true))\n }\n\n @FieldResolver(type => CounterpartyBankAccount, { nullable: true })\n async payeeAccount(@Root() request: ExpenditureRequest): Promise<CounterpartyBankAccount | null> {\n return request.payeeAccount ?? (await byId(CounterpartyBankAccount, request.payeeAccountId, true))\n }\n\n @FieldResolver(type => User, { nullable: true })\n async decidedBy(@Root() request: ExpenditureRequest): Promise<User | null> {\n return request.decidedBy ?? (await byId(User, request.decidedById))\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() request: ExpenditureRequest): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: request.domainId })\n }\n\n @FieldResolver(type => User, { nullable: true })\n async creator(@Root() request: ExpenditureRequest): Promise<User | null> {\n return await byId(User, request.creatorId)\n }\n\n @FieldResolver(type => User, { nullable: true })\n async updater(@Root() request: ExpenditureRequest): Promise<User | null> {\n return await byId(User, request.updaterId)\n }\n}\n\n@Resolver(ExpenditureRequestItem)\nexport class ExpenditureRequestItemQuery {\n @FieldResolver(type => ExpenditureRequest, { nullable: true })\n async request(@Root() item: ExpenditureRequestItem): Promise<ExpenditureRequest | null> {\n return item.request ?? (await byId(ExpenditureRequest, item.requestId))\n }\n\n @FieldResolver(type => Account, { nullable: true })\n async account(@Root() item: ExpenditureRequestItem): Promise<Account | null> {\n return item.account ?? (await byId(Account, item.accountId))\n }\n\n @FieldResolver(type => TaxInvoice, { nullable: true })\n async taxInvoice(@Root() item: ExpenditureRequestItem): Promise<TaxInvoice | null> {\n return item.taxInvoice ?? (await byId(TaxInvoice, item.taxInvoiceId, true))\n }\n\n /** Where the receipt is, or null - so an approver can see what was spent. */\n @FieldResolver(type => String, { nullable: true })\n async receiptUrl(@Root() item: ExpenditureRequestItem): Promise<string | null> {\n const attachment = await getRepository(Attachment).findOne({ where: { refType: RECEIPT_REF_TYPE, refBy: item.id }, order: { createdAt: 'DESC' } as any })\n return attachment?.fullpath ?? null\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() item: ExpenditureRequestItem): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: item.domainId })\n }\n\n @FieldResolver(type => User, { nullable: true })\n async creator(@Root() item: ExpenditureRequestItem): Promise<User | null> {\n return await byId(User, item.creatorId)\n }\n\n @FieldResolver(type => User, { nullable: true })\n async updater(@Root() item: ExpenditureRequestItem): Promise<User | null> {\n return await byId(User, item.updaterId)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"expenditure-request-query.js","sourceRoot":"","sources":["../../../server/service/expenditure-request/expenditure-request-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Int, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\nimport { Like } from 'typeorm'\n\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, SpeakRefusals } from '@things-factory/shell'\nimport { privilegeRejection, User } from '@things-factory/auth-base'\nimport { Attachment } from '@things-factory/attachment-base'\nimport { accountTailOf, Counterparty, CounterpartyBankAccount } from '@things-factory/biz-base'\nimport { Department } from '@things-factory/organization'\nimport { TaxInvoice } from '@things-factory/tax-invoice'\n\nimport { Account } from '../account/account'\nimport { ExpenditureKind, ExpenditureRequest, ExpenditureRequestStatus } from './expenditure-request'\nimport { ExpenditureRequestItem } from './expenditure-request-item'\nimport { paymentStatesOf, ExpenditurePaymentState } from './expenditure-payment-state'\nimport { monthlySummary, statusCounts, type RequestStatus } from './expenditure-request-rules'\nimport { approvedWithStates, driftOf, RECEIPT_REF_TYPE } from './expenditure-request-service'\nimport { mayReadRequest, REQUEST_READ_FACTS } from './receipt-reader'\nimport { ExpenditurePayment, ExpenditureQueue, ExpenditureQueueRow, ExpenditureRequestList, ExpenditureSummary } from './expenditure-request-type'\n\nconst byId = async <T>(entity: new () => T, id: string | null | undefined, withDeleted = false): Promise<T | null> =>\n id ? ((await getRepository(entity).findOne({ where: { id } as any, withDeleted })) as T | null) : null\n\nasync function summaryOf(domain: { id: string }, year: number, month: number | undefined, requesterId?: string): Promise<ExpenditureSummary> {\n const period = month ? `${year}-${String(month).padStart(2, '0')}` : `${year}-%`\n const requests = await getRepository(ExpenditureRequest).find({\n where: {\n domain: { id: domain.id },\n kind: ExpenditureKind.REIMBURSEMENT,\n month: month ? period : Like(period),\n ...(requesterId ? { requester: { id: requesterId } } : {})\n } as any,\n relations: ['requester', 'items', 'items.account']\n })\n const shaped = requests.map(one => ({\n month: one.month,\n requesterId: one.requesterId ?? one.requester?.id,\n requesterName: one.requester?.name ?? null,\n status: one.status as RequestStatus,\n /* Summed by 계정과목; a line not yet filed counts under the category written on it. */\n items: (one.items ?? []).filter(item => !item.deletedAt).map(item => ({ ...item, category: item.account?.name ?? item.category }))\n }))\n\n const rows = monthlySummary(shaped)\n const approved = requests.filter(one => one.status === ExpenditureRequestStatus.APPROVED)\n approved.forEach(one => (one.items = (one.items ?? []).filter(item => !item.deletedAt)))\n const states = await paymentStatesOf(getRepository(ExpenditureRequest).manager, domain, approved as any)\n\n return {\n rows,\n statuses: Object.entries(statusCounts(shaped)).map(([status, count]) => ({ status, count })),\n approvedTotal: rows.reduce((sum, one) => sum + one.total, 0),\n unpaid: [...states.values()].reduce((sum, one) => sum + one.outstanding, 0)\n }\n}\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(ExpenditureRequest)\nexport class ExpenditureRequestQuery {\n /** The last four digits of the account paid into - what the requester and the approvers see (ADR-0139). */\n @FieldResolver(type => String, { nullable: true, description: \"The last four digits of the account paid into\" })\n payeeAccountTail(@Root() request: ExpenditureRequest): string | undefined {\n return accountTailOf(request.payeeAccountNumber)\n }\n\n /** The caller's own requests - what an employee sees. */\n @Directive('@privilege(category: \"accounting-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequestList, { description: \"The caller's own expenditure requests\" })\n async myExpenditureRequests(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ExpenditureRequestList> {\n const { domain, user } = context.state\n const queryBuilder = getQueryBuilderFromListParams({ domain, params, repository: getRepository(ExpenditureRequest), searchables: ['title', 'notes'], alias: 'request' })\n queryBuilder.andWhere('request.requester = :requester', { requester: user.id })\n queryBuilder.addOrderBy('request.createdAt', 'DESC')\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n /** One of the caller's own requests, with its lines. */\n @Directive('@privilege(category: \"accounting-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequest, { nullable: true, description: \"One of the caller's own expenditure requests\" })\n async myExpenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest | null> {\n const { domain, user } = context.state\n return await getRepository(ExpenditureRequest).findOne({ where: { id, domain: { id: domain.id }, requester: { id: user.id } } as any })\n }\n\n /** Every request of the domain - what finance sees. */\n /*\n * Every request, one by one - who spent what, the receipts, the queue to pay - is the paying seat's: `expenditure`\n * (the user, 2026-10-18). The month's summary stays `accounting`, which the executives read.\n */\n @Directive('@privilege(category: \"expenditure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequestList, { description: 'Every expenditure request of the domain' })\n async expenditureRequests(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ExpenditureRequestList> {\n const { domain } = context.state\n const queryBuilder = getQueryBuilderFromListParams({ domain, params, repository: getRepository(ExpenditureRequest), searchables: ['title', 'notes'], alias: 'request' })\n queryBuilder.addOrderBy('request.createdAt', 'DESC')\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n @Directive('@privilege(category: \"expenditure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequest, { nullable: true, description: 'One expenditure request of the domain' })\n async expenditureRequest(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest | null> {\n return await getRepository(ExpenditureRequest).findOne({ where: { id, domain: { id: context.state.domain.id } } as any })\n }\n\n /**\n * One request as its approvers read it - the lines and their files. Open to whoever may open those files: its writer,\n * whoever takes part in its approval, and the paying seat (§`receipt-reader.ts`). The approval card links to it.\n * Anyone else is refused as the paying seat's door refuses them, so the 360 says 「볼 수 없음」, not 「없음」.\n */\n @Directive('@privilege(category: \"accounting-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureRequest, { nullable: true, description: 'One expenditure request, for its writer, its approvers and the paying seat' })\n async expenditureRequestForReview(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ExpenditureRequest | null> {\n const request = await getRepository(ExpenditureRequest).findOne({ where: { id, domain: { id: context.state.domain.id } } as any })\n if (!request) return null\n if (!(await mayReadRequest(request, context, REQUEST_READ_FACTS))) throw privilegeRejection(context, 'expenditure', 'query', 'role', 'query')\n return request\n }\n\n /**\n * The payment queue (지급 대기) - approved requests still to pay, by the day they are to be paid, and the paid ones\n * whose bank line no statement has matched yet.\n */\n @Directive('@privilege(category: \"expenditure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureQueue, { description: 'Approved requests still to pay, and paid ones not yet matched to the bank' })\n async expenditureQueue(@Ctx() context: ResolverContext): Promise<ExpenditureQueue> {\n const { domain } = context.state\n const manager = getRepository(ExpenditureRequest).manager\n const { requests, states } = await approvedWithStates(manager, domain)\n\n const rows: ExpenditureQueueRow[] = []\n for (const request of requests) {\n const payment = states.get(request.id)!\n if (payment.state === ExpenditurePaymentState.NOTHING_TO_PAY) continue\n rows.push({\n request,\n payment,\n payeeName: (request.kind === ExpenditureKind.VENDOR ? request.counterparty?.name : request.requester?.name) ?? undefined,\n payeeAccountDrift: payment.outstanding > 0 ? await driftOf(manager, request) : undefined\n })\n }\n const due = (row: ExpenditureQueueRow) => row.request.dueDate ?? '9999-12-31'\n const waiting = rows\n .filter(row => row.payment.outstanding > 0)\n .sort((a, b) => due(a).localeCompare(due(b)) || String(a.request.decidedAt ?? '').localeCompare(String(b.request.decidedAt ?? '')))\n const unreconciled = rows.filter(row => row.payment.outstanding <= 0 && !row.payment.reconciled)\n return { waiting, unreconciled }\n }\n\n @Directive('@privilege(category: \"accounting\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureSummary, { description: 'Approved reimbursements per month, requester and category, with requests per status' })\n async expenditureSummary(\n @Arg('year', type => Int) year: number,\n @Arg('month', type => Int, { nullable: true }) month: number,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureSummary> {\n return await summaryOf(context.state.domain, year, month || undefined)\n }\n\n @Directive('@privilege(category: \"accounting-self\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ExpenditureSummary, { description: \"The caller's own monthly summary of reimbursements\" })\n async myExpenditureSummary(\n @Arg('year', type => Int) year: number,\n @Arg('month', type => Int, { nullable: true }) month: number,\n @Ctx() context: ResolverContext\n ): Promise<ExpenditureSummary> {\n return await summaryOf(context.state.domain, year, month || undefined, context.state.user.id)\n }\n\n /** How far it is paid - read from its payments (ADR-0135 §2-4). */\n @FieldResolver(type => ExpenditurePayment, { nullable: true })\n async payment(@Root() request: ExpenditureRequest): Promise<ExpenditurePayment | null> {\n if (request.status !== ExpenditureRequestStatus.APPROVED) return null\n const items = await getRepository(ExpenditureRequestItem).find({ where: { request: { id: request.id } } as any })\n const states = await paymentStatesOf(getRepository(ExpenditureRequest).manager, { id: request.domainId! }, [{ id: request.id, items }])\n return states.get(request.id) ?? null\n }\n\n @FieldResolver(type => [ExpenditureRequestItem])\n async items(@Root() request: ExpenditureRequest): Promise<ExpenditureRequestItem[]> {\n if (request.items) return request.items.filter(item => !item.deletedAt)\n return await getRepository(ExpenditureRequestItem).find({ where: { request: { id: request.id } } as any, order: { spentDate: 'ASC', createdAt: 'ASC' } as any })\n }\n\n @FieldResolver(type => User, { nullable: true })\n async requester(@Root() request: ExpenditureRequest): Promise<User | null> {\n return request.requester ?? (await byId(User, request.requesterId))\n }\n\n @FieldResolver(type => Department, { nullable: true })\n async department(@Root() request: ExpenditureRequest): Promise<Department | null> {\n return request.department ?? (await byId(Department, request.departmentId))\n }\n\n @FieldResolver(type => Counterparty, { nullable: true })\n async counterparty(@Root() request: ExpenditureRequest): Promise<Counterparty | null> {\n return request.counterparty ?? (await byId(Counterparty, request.counterpartyId, true))\n }\n\n @FieldResolver(type => CounterpartyBankAccount, { nullable: true })\n async payeeAccount(@Root() request: ExpenditureRequest): Promise<CounterpartyBankAccount | null> {\n return request.payeeAccount ?? (await byId(CounterpartyBankAccount, request.payeeAccountId, true))\n }\n\n @FieldResolver(type => User, { nullable: true })\n async decidedBy(@Root() request: ExpenditureRequest): Promise<User | null> {\n return request.decidedBy ?? (await byId(User, request.decidedById))\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() request: ExpenditureRequest): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: request.domainId })\n }\n\n @FieldResolver(type => User, { nullable: true })\n async creator(@Root() request: ExpenditureRequest): Promise<User | null> {\n return await byId(User, request.creatorId)\n }\n\n @FieldResolver(type => User, { nullable: true })\n async updater(@Root() request: ExpenditureRequest): Promise<User | null> {\n return await byId(User, request.updaterId)\n }\n}\n\n@Resolver(ExpenditureRequestItem)\nexport class ExpenditureRequestItemQuery {\n @FieldResolver(type => ExpenditureRequest, { nullable: true })\n async request(@Root() item: ExpenditureRequestItem): Promise<ExpenditureRequest | null> {\n return item.request ?? (await byId(ExpenditureRequest, item.requestId))\n }\n\n @FieldResolver(type => Account, { nullable: true })\n async account(@Root() item: ExpenditureRequestItem): Promise<Account | null> {\n return item.account ?? (await byId(Account, item.accountId))\n }\n\n @FieldResolver(type => TaxInvoice, { nullable: true })\n async taxInvoice(@Root() item: ExpenditureRequestItem): Promise<TaxInvoice | null> {\n return item.taxInvoice ?? (await byId(TaxInvoice, item.taxInvoiceId, true))\n }\n\n /** The line's receipts and papers - so an approver sees what was spent. */\n @FieldResolver(type => [Attachment])\n async files(@Root() item: ExpenditureRequestItem): Promise<Attachment[]> {\n return await getRepository(Attachment).find({ where: { domain: { id: item.domainId }, refType: RECEIPT_REF_TYPE, refBy: item.id } as any, order: { createdAt: 'ASC' } as any })\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() item: ExpenditureRequestItem): Promise<Domain> {\n return await getRepository(Domain).findOneBy({ id: item.domainId })\n }\n\n @FieldResolver(type => User, { nullable: true })\n async creator(@Root() item: ExpenditureRequestItem): Promise<User | null> {\n return await byId(User, item.creatorId)\n }\n\n @FieldResolver(type => User, { nullable: true })\n async updater(@Root() item: ExpenditureRequestItem): Promise<User | null> {\n return await byId(User, item.updaterId)\n }\n}\n"]}
|
|
@@ -50,6 +50,8 @@ export declare function ownRequest(tx: EntityManager, id: string, domain: {
|
|
|
50
50
|
*/
|
|
51
51
|
export interface Citing {
|
|
52
52
|
taxInvoices: boolean;
|
|
53
|
+
/** Bulk preparation refuses partial/complete payments and amended evidence for individual review. */
|
|
54
|
+
unpaidInvoicesOnly?: boolean;
|
|
53
55
|
}
|
|
54
56
|
/**
|
|
55
57
|
* Save a request and its lines in one go - the head, then the lines. A new request belongs to the caller; an existing
|
|
@@ -64,14 +66,22 @@ export declare function withdrawRequest(tx: EntityManager, domain: any, user: an
|
|
|
64
66
|
export declare function deleteRequest(tx: EntityManager, domain: any, user: any, id: string): Promise<boolean>;
|
|
65
67
|
/**
|
|
66
68
|
* Add one line from the phone. It joins the caller's editable reimbursement of that month (§`requestForLine`), or
|
|
67
|
-
* starts one. The receipt
|
|
69
|
+
* starts one. The receipt photos and files picked with it are attached to the line.
|
|
68
70
|
*/
|
|
69
71
|
export declare function addLine(tx: EntityManager, domain: any, user: any, line: ItemPatch & {
|
|
70
72
|
month?: string;
|
|
71
|
-
|
|
73
|
+
files?: any[];
|
|
72
74
|
}, context: ResolverContext): Promise<ExpenditureRequest>;
|
|
73
|
-
/**
|
|
74
|
-
export declare function
|
|
75
|
+
/** A line of the caller's own request, while the request can still be changed. */
|
|
76
|
+
export declare function editableLine(tx: EntityManager, domain: any, user: any, itemId: string): Promise<ExpenditureRequestItem>;
|
|
77
|
+
/**
|
|
78
|
+
* Attach files to a line and take others off it, in one go - only the requester, only while editable. A file taken
|
|
79
|
+
* off is deleted: what approvers judge is what the line has when it is submitted.
|
|
80
|
+
*/
|
|
81
|
+
export declare function saveLineFiles(tx: EntityManager, domain: any, user: any, itemId: string, change: {
|
|
82
|
+
attach?: any[];
|
|
83
|
+
remove?: string[];
|
|
84
|
+
}, context: ResolverContext): Promise<ExpenditureRequestItem>;
|
|
75
85
|
/** Approved requests with their lines and how far each is paid - what the payment queue and payments are made of. */
|
|
76
86
|
export declare function approvedWithStates(tx: EntityManager, domain: {
|
|
77
87
|
id: string;
|
|
@@ -7,7 +7,8 @@ exports.submitRequest = submitRequest;
|
|
|
7
7
|
exports.withdrawRequest = withdrawRequest;
|
|
8
8
|
exports.deleteRequest = deleteRequest;
|
|
9
9
|
exports.addLine = addLine;
|
|
10
|
-
exports.
|
|
10
|
+
exports.editableLine = editableLine;
|
|
11
|
+
exports.saveLineFiles = saveLineFiles;
|
|
11
12
|
exports.approvedWithStates = approvedWithStates;
|
|
12
13
|
exports.driftOf = driftOf;
|
|
13
14
|
exports.payRequests = payRequests;
|
|
@@ -130,12 +131,29 @@ async function saveItems(tx, domain, user, request, patches, citing) {
|
|
|
130
131
|
if ('taxInvoice' in patch) {
|
|
131
132
|
if (patch.taxInvoice?.id && !citing.taxInvoices)
|
|
132
133
|
throw new shell_1.Refusal('expenditure-invoice-not-readable', {}, 'citing a tax invoice needs the tax-invoice ledger');
|
|
134
|
+
// Serialize citation checks on PostgreSQL; SQLite already has the request write in this transaction.
|
|
135
|
+
if (patch.taxInvoice?.id && tx.connection.options.type === 'postgres') {
|
|
136
|
+
await tx.getRepository(tax_invoice_1.TaxInvoice).findOne({ where: { id: patch.taxInvoice.id, domain: { id: domain.id } }, lock: { mode: 'pessimistic_write' } });
|
|
137
|
+
}
|
|
133
138
|
const invoice = await inDomain(tx, tax_invoice_1.TaxInvoice, domain, patch.taxInvoice, 'taxInvoice');
|
|
134
139
|
if (invoice) {
|
|
135
140
|
if (request.kind !== expenditure_request_1.ExpenditureKind.VENDOR)
|
|
136
141
|
throw new shell_1.Refusal('expenditure-invoice-on-reimbursement', {}, 'a reimbursement cites receipts, not tax invoices');
|
|
137
142
|
if (invoice.category !== tax_invoice_1.Category.IMPORT)
|
|
138
143
|
throw new shell_1.Refusal('expenditure-invoice-not-purchase', {}, 'cite a purchase tax invoice');
|
|
144
|
+
if (citing.unpaidInvoicesOnly) {
|
|
145
|
+
const party = await tx.getRepository(biz_base_1.Counterparty).findOne({ where: { id: request.counterpartyId, domain: { id: domain.id } } });
|
|
146
|
+
const digits = (value) => String(value ?? '').replace(/\D/g, '');
|
|
147
|
+
if (!party || !digits(party.businessNumber) || digits(party.businessNumber) !== digits(invoice.supplierBusinessRegistrationNumber))
|
|
148
|
+
throw new shell_1.Refusal('expenditure-bulk-party', {}, 'The supplier must match the selected counterparty; review this invoice individually');
|
|
149
|
+
const payments = await tx.getRepository(payment_1.Payment).find({ where: { domain: { id: domain.id }, targetType: document_targets_1.TAX_INVOICE_TARGET, targetId: invoice.id } });
|
|
150
|
+
if (payments.length)
|
|
151
|
+
throw new shell_1.Refusal('expenditure-bulk-paid', {}, 'This invoice already has payment links; review partial or completed payments individually');
|
|
152
|
+
const negatives = await tx.getRepository(tax_invoice_1.TaxInvoice).find({ where: { domain: { id: domain.id }, totalAmount: (0, typeorm_1.LessThan)(0) } });
|
|
153
|
+
const amended = negatives.some(one => one.originalApprovalNo === invoice.approvalNo || (invoice.approvalNo && [one.remark0, one.remark1, one.remark2].some(text => text?.includes(invoice.approvalNo))));
|
|
154
|
+
if (!(Number(invoice.totalAmount) > 0) || invoice.originalApprovalNo || invoice.invoiceType?.startsWith('02') || amended)
|
|
155
|
+
throw new shell_1.Refusal('expenditure-bulk-amended', {}, 'Review amended or non-positive invoices individually before requesting payment');
|
|
156
|
+
}
|
|
139
157
|
const elsewhere = await repo.find({ where: { domain: { id: domain.id }, taxInvoice: { id: invoice.id } }, relations: ['request'] });
|
|
140
158
|
if (elsewhere.some(one => one.id !== current?.id && one.request && !one.request.deletedAt))
|
|
141
159
|
throw new shell_1.Refusal('expenditure-invoice-cited-twice', { issueDate: invoice.issueDate }, 'another request already pays this tax invoice');
|
|
@@ -292,6 +310,8 @@ async function submitRequest(tx, domain, user, id, context) {
|
|
|
292
310
|
paidTo: vendor
|
|
293
311
|
? { __typename: 'Counterparty', id: request.counterpartyId, name: payee }
|
|
294
312
|
: { __typename: 'User', id: user.id, name: who },
|
|
313
|
+
/* The request itself, as a reference: the approval card opens it - the lines and their receipts and papers. */
|
|
314
|
+
request: { __typename: 'ExpenditureRequest', id: request.id, name: request.title },
|
|
295
315
|
headline: vendor
|
|
296
316
|
? `${payee} · ${request.title} ${won(totals.payable)}${request.dueDate ? ` — ${request.dueDate} 지급` : ''}`
|
|
297
317
|
: `${who} · ${request.month} 경비 ${won(totals.total)} (${totals.count}건)`,
|
|
@@ -339,7 +359,7 @@ async function deleteRequest(tx, domain, user, id) {
|
|
|
339
359
|
}
|
|
340
360
|
/**
|
|
341
361
|
* Add one line from the phone. It joins the caller's editable reimbursement of that month (§`requestForLine`), or
|
|
342
|
-
* starts one. The receipt
|
|
362
|
+
* starts one. The receipt photos and files picked with it are attached to the line.
|
|
343
363
|
*/
|
|
344
364
|
async function addLine(tx, domain, user, line, context) {
|
|
345
365
|
const spentDate = (0, expenditure_request_rules_1.dayOf)(line.spentDate);
|
|
@@ -350,27 +370,45 @@ async function addLine(tx, domain, user, line, context) {
|
|
|
350
370
|
where: { domain: { id: domain.id }, requester: { id: user.id }, kind: expenditure_request_1.ExpenditureKind.REIMBURSEMENT, month }
|
|
351
371
|
});
|
|
352
372
|
const joinId = (0, expenditure_request_rules_1.requestForLine)(mine.map(one => ({ id: one.id, status: one.status, month: one.month, updatedAt: one.updatedAt })), month);
|
|
353
|
-
const {
|
|
373
|
+
const { files, month: _month, ...fields } = line;
|
|
354
374
|
const request = await saveRequest(tx, domain, user, joinId ? { id: joinId } : { kind: expenditure_request_1.ExpenditureKind.REIMBURSEMENT, month }, [{ ...fields, spentDate, cuFlag: '+' }], { taxInvoices: false });
|
|
355
|
-
if (
|
|
375
|
+
if (files?.length) {
|
|
356
376
|
const [latest] = await tx.getRepository(expenditure_request_item_1.ExpenditureRequestItem).find({ where: { request: { id: request.id } }, order: { createdAt: 'DESC' }, take: 1 });
|
|
357
377
|
if (latest)
|
|
358
|
-
|
|
378
|
+
for (const file of files)
|
|
379
|
+
await attachFile(latest.id, file, context);
|
|
359
380
|
}
|
|
360
381
|
return request;
|
|
361
382
|
}
|
|
362
|
-
/**
|
|
363
|
-
async function
|
|
383
|
+
/** A line of the caller's own request, while the request can still be changed. */
|
|
384
|
+
async function editableLine(tx, domain, user, itemId) {
|
|
364
385
|
const item = await tx.getRepository(expenditure_request_item_1.ExpenditureRequestItem).findOne({ where: { id: itemId, domain: { id: domain.id } }, relations: ['request'] });
|
|
365
386
|
if (!item?.request)
|
|
366
387
|
throw new shell_1.Refusal('expenditure-line-not-found', {}, 'a line was not found - reload and try again');
|
|
367
388
|
const request = await ownRequest(tx, item.request.id, domain, user);
|
|
368
389
|
if (!(0, expenditure_request_rules_1.canEdit)(request.status))
|
|
369
390
|
throw (0, exports.lockedRequest)(request.status);
|
|
370
|
-
await (0, attachment_base_1.replaceAttachment)({ file, refType: exports.RECEIPT_REF_TYPE, refBy: item.id, category: 'receipt' }, context);
|
|
371
391
|
return item;
|
|
372
392
|
}
|
|
373
|
-
|
|
393
|
+
/**
|
|
394
|
+
* Attach files to a line and take others off it, in one go - only the requester, only while editable. A file taken
|
|
395
|
+
* off is deleted: what approvers judge is what the line has when it is submitted.
|
|
396
|
+
*/
|
|
397
|
+
async function saveLineFiles(tx, domain, user, itemId, change, context) {
|
|
398
|
+
const item = await editableLine(tx, domain, user, itemId);
|
|
399
|
+
const remove = [...new Set(change.remove ?? [])];
|
|
400
|
+
if (remove.length) {
|
|
401
|
+
const onLine = await tx.getRepository(attachment_base_1.Attachment).find({ where: { domain: { id: domain.id }, refType: exports.RECEIPT_REF_TYPE, refBy: item.id, id: (0, typeorm_1.In)(remove) } });
|
|
402
|
+
if (onLine.length !== remove.length)
|
|
403
|
+
throw new shell_1.Refusal('expenditure-file-not-on-line', {}, 'a file is not on this line - reload and try again');
|
|
404
|
+
for (const one of onLine)
|
|
405
|
+
await (0, attachment_base_1.deleteAttachment)(null, { id: one.id }, context);
|
|
406
|
+
}
|
|
407
|
+
for (const file of change.attach ?? [])
|
|
408
|
+
await attachFile(item.id, file, context);
|
|
409
|
+
return item;
|
|
410
|
+
}
|
|
411
|
+
async function attachFile(itemId, file, context) {
|
|
374
412
|
await (0, attachment_base_1.createAttachment)(null, { attachment: { file, refType: exports.RECEIPT_REF_TYPE, refBy: itemId, category: 'receipt' } }, context);
|
|
375
413
|
}
|
|
376
414
|
/** Approved requests with their lines and how far each is paid - what the payment queue and payments are made of. */
|