@things-factory/accounting 10.1.155 → 10.1.157
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/activities/activity-expenditure.d.ts +186 -0
- package/dist-server/activities/activity-expenditure.js +122 -0
- package/dist-server/activities/activity-expenditure.js.map +1 -0
- package/dist-server/activities/expenditure-activity-names.d.ts +4 -0
- package/dist-server/activities/expenditure-activity-names.js +13 -0
- package/dist-server/activities/expenditure-activity-names.js.map +1 -0
- package/dist-server/activities/index.d.ts +2 -1
- package/dist-server/activities/index.js +19 -12
- package/dist-server/activities/index.js.map +1 -1
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +1 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/service/account/account-match.d.ts +5 -3
- package/dist-server/service/account/account-match.js +7 -3
- package/dist-server/service/account/account-match.js.map +1 -1
- package/dist-server/service/bank-statement/bank-import.js +9 -3
- package/dist-server/service/bank-statement/bank-import.js.map +1 -1
- package/dist-server/service/bank-statement/bank-source.js +2 -1
- package/dist-server/service/bank-statement/bank-source.js.map +1 -1
- package/dist-server/service/counterparty-account/counterparty-account-query.d.ts +6 -0
- package/dist-server/service/counterparty-account/counterparty-account-query.js +48 -0
- package/dist-server/service/counterparty-account/counterparty-account-query.js.map +1 -0
- package/dist-server/service/counterparty-account/counterparty-account-rules.d.ts +46 -0
- package/dist-server/service/counterparty-account/counterparty-account-rules.js +76 -0
- package/dist-server/service/counterparty-account/counterparty-account-rules.js.map +1 -0
- package/dist-server/service/counterparty-account/counterparty-account-service.d.ts +22 -0
- package/dist-server/service/counterparty-account/counterparty-account-service.js +66 -0
- package/dist-server/service/counterparty-account/counterparty-account-service.js.map +1 -0
- package/dist-server/service/counterparty-account/counterparty-account-type.d.ts +9 -0
- package/dist-server/service/counterparty-account/counterparty-account-type.js +40 -0
- package/dist-server/service/counterparty-account/counterparty-account-type.js.map +1 -0
- package/dist-server/service/counterparty-account/index.d.ts +4 -0
- package/dist-server/service/counterparty-account/index.js +8 -0
- package/dist-server/service/counterparty-account/index.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-payment-state.d.ts +52 -0
- package/dist-server/service/expenditure-request/expenditure-payment-state.js +100 -0
- package/dist-server/service/expenditure-request/expenditure-payment-state.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-request-item.d.ts +41 -0
- package/dist-server/service/expenditure-request/expenditure-request-item.js +149 -0
- package/dist-server/service/expenditure-request/expenditure-request-item.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-request-mutation.d.ts +18 -0
- package/dist-server/service/expenditure-request/expenditure-request-mutation.js +140 -0
- package/dist-server/service/expenditure-request/expenditure-request-mutation.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-request-query.d.ts +46 -0
- package/dist-server/service/expenditure-request/expenditure-request-query.js +365 -0
- package/dist-server/service/expenditure-request/expenditure-request-query.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-request-rules.d.ts +128 -0
- package/dist-server/service/expenditure-request/expenditure-request-rules.js +183 -0
- package/dist-server/service/expenditure-request/expenditure-request-rules.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-request-service.d.ts +92 -0
- package/dist-server/service/expenditure-request/expenditure-request-service.js +488 -0
- package/dist-server/service/expenditure-request/expenditure-request-service.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-request-type.d.ts +85 -0
- package/dist-server/service/expenditure-request/expenditure-request-type.js +312 -0
- package/dist-server/service/expenditure-request/expenditure-request-type.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-request.d.ts +67 -0
- package/dist-server/service/expenditure-request/expenditure-request.js +228 -0
- package/dist-server/service/expenditure-request/expenditure-request.js.map +1 -0
- package/dist-server/service/expenditure-request/expenditure-target.d.ts +1 -0
- package/dist-server/service/expenditure-request/expenditure-target.js +55 -0
- package/dist-server/service/expenditure-request/expenditure-target.js.map +1 -0
- package/dist-server/service/expenditure-request/index.d.ts +8 -0
- package/dist-server/service/expenditure-request/index.js +12 -0
- package/dist-server/service/expenditure-request/index.js.map +1 -0
- package/dist-server/service/index.d.ts +9 -2
- package/dist-server/service/index.js +18 -3
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -9
- package/translations/en.json +58 -1
- package/translations/es.json +17 -1
- package/translations/ja.json +17 -1
- package/translations/ko.json +58 -1
- package/translations/ms.json +17 -1
- package/translations/zh.json +17 -1
- package/dist-client/activities/activity-expense-edit.d.ts +0 -14
- package/dist-client/activities/activity-expense-edit.js +0 -85
- package/dist-client/activities/activity-expense-edit.js.map +0 -1
- package/dist-client/activities/activity-expense-view.d.ts +0 -14
- package/dist-client/activities/activity-expense-view.js +0 -85
- package/dist-client/activities/activity-expense-view.js.map +0 -1
- package/dist-server/activities/activity-expense.d.ts +0 -58
- package/dist-server/activities/activity-expense.js +0 -150
- package/dist-server/activities/activity-expense.js.map +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpenditurePaymentState = exports.EXPENDITURE_TARGET = void 0;
|
|
4
|
+
exports.paymentStateFrom = paymentStateFrom;
|
|
5
|
+
exports.paymentStatesOf = paymentStatesOf;
|
|
6
|
+
const typeorm_1 = require("typeorm");
|
|
7
|
+
const type_graphql_1 = require("type-graphql");
|
|
8
|
+
const payment_1 = require("../payment/payment");
|
|
9
|
+
const document_targets_1 = require("../payment/document-targets");
|
|
10
|
+
const expenditure_request_rules_1 = require("./expenditure-request-rules");
|
|
11
|
+
/** The payment target kind of an expenditure request - the money paid on it directly, with no document between. */
|
|
12
|
+
exports.EXPENDITURE_TARGET = 'ExpenditureRequest';
|
|
13
|
+
var ExpenditurePaymentState;
|
|
14
|
+
(function (ExpenditurePaymentState) {
|
|
15
|
+
/** Only corporate-card lines - the company already paid. */
|
|
16
|
+
ExpenditurePaymentState["NOTHING_TO_PAY"] = "NOTHING_TO_PAY";
|
|
17
|
+
ExpenditurePaymentState["UNPAID"] = "UNPAID";
|
|
18
|
+
ExpenditurePaymentState["PARTLY_PAID"] = "PARTLY_PAID";
|
|
19
|
+
ExpenditurePaymentState["PAID"] = "PAID";
|
|
20
|
+
})(ExpenditurePaymentState || (exports.ExpenditurePaymentState = ExpenditurePaymentState = {}));
|
|
21
|
+
(0, type_graphql_1.registerEnumType)(ExpenditurePaymentState, {
|
|
22
|
+
name: 'ExpenditurePaymentState',
|
|
23
|
+
description: 'How much of an expenditure request the bank lines that paid it cover'
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* How far a request is paid (ADR-0135 §2-4, §2-5). Pure.
|
|
27
|
+
*
|
|
28
|
+
* A payable line that cites a purchase tax invoice is paid when that invoice is - the bank line pays the invoice, and
|
|
29
|
+
* the request reads it (ADR-0122 §3-3: one path for one fact). The rest of the request is paid by the payments on the
|
|
30
|
+
* request itself.
|
|
31
|
+
*/
|
|
32
|
+
function paymentStateFrom(lines, settlements, invoicePayments) {
|
|
33
|
+
const payableLines = lines.filter(expenditure_request_rules_1.isPayable);
|
|
34
|
+
const payable = payableLines.reduce((sum, line) => sum + (line.amount || 0), 0);
|
|
35
|
+
let citedTotal = 0;
|
|
36
|
+
let paidByInvoices = 0;
|
|
37
|
+
const cited = [];
|
|
38
|
+
const parts = [...settlements];
|
|
39
|
+
for (const line of payableLines.filter(one => one.taxInvoiceId)) {
|
|
40
|
+
citedTotal += line.amount || 0;
|
|
41
|
+
const ofInvoice = invoicePayments.get(line.taxInvoiceId) ?? [];
|
|
42
|
+
const paidOfLine = Math.min(line.amount || 0, ofInvoice.reduce((sum, one) => sum + one.amount, 0));
|
|
43
|
+
paidByInvoices += paidOfLine;
|
|
44
|
+
cited.push({ taxInvoiceId: line.taxInvoiceId, outstanding: (line.amount || 0) - paidOfLine });
|
|
45
|
+
parts.push(...ofInvoice);
|
|
46
|
+
}
|
|
47
|
+
const settled = settlements.reduce((sum, one) => sum + one.amount, 0);
|
|
48
|
+
const paid = paidByInvoices + settled;
|
|
49
|
+
const outstanding = Math.max(0, payable - paid);
|
|
50
|
+
const state = payable <= 0
|
|
51
|
+
? ExpenditurePaymentState.NOTHING_TO_PAY
|
|
52
|
+
: paid <= 0
|
|
53
|
+
? ExpenditurePaymentState.UNPAID
|
|
54
|
+
: outstanding > 0
|
|
55
|
+
? ExpenditurePaymentState.PARTLY_PAID
|
|
56
|
+
: ExpenditurePaymentState.PAID;
|
|
57
|
+
return {
|
|
58
|
+
state,
|
|
59
|
+
payable,
|
|
60
|
+
paid,
|
|
61
|
+
outstanding,
|
|
62
|
+
settleable: payable - citedTotal,
|
|
63
|
+
settled,
|
|
64
|
+
reconciled: parts.length > 0 && parts.every(one => one.reconciled),
|
|
65
|
+
transactionIds: [...new Set(parts.map(one => one.transactionId))],
|
|
66
|
+
cited
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const partOf = (payment, amount) => ({
|
|
70
|
+
amount,
|
|
71
|
+
transactionId: payment.transaction.id,
|
|
72
|
+
reconciled: !!payment.transaction.bankFingerprint
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* **The one reader of whether requests were paid and reconciled** - the payment queue, the forecast of what is to go
|
|
76
|
+
* out, the AI and every 360 read it from here, never each on their own.
|
|
77
|
+
*/
|
|
78
|
+
async function paymentStatesOf(tx, domain, requests) {
|
|
79
|
+
const states = new Map();
|
|
80
|
+
if (!requests.length)
|
|
81
|
+
return states;
|
|
82
|
+
const repo = tx.getRepository(payment_1.Payment);
|
|
83
|
+
const direct = await repo.find({
|
|
84
|
+
where: { domain: { id: domain.id }, targetType: exports.EXPENDITURE_TARGET, targetId: (0, typeorm_1.In)(requests.map(one => one.id)) },
|
|
85
|
+
relations: ['transaction']
|
|
86
|
+
});
|
|
87
|
+
const invoiceIds = [...new Set(requests.flatMap(one => (one.items ?? []).map(item => item.taxInvoiceId).filter(Boolean)))];
|
|
88
|
+
const onInvoices = invoiceIds.length
|
|
89
|
+
? await repo.find({ where: { domain: { id: domain.id }, targetType: document_targets_1.TAX_INVOICE_TARGET, targetId: (0, typeorm_1.In)(invoiceIds) }, relations: ['transaction'] })
|
|
90
|
+
: [];
|
|
91
|
+
const invoicePayments = new Map();
|
|
92
|
+
for (const one of onInvoices)
|
|
93
|
+
invoicePayments.set(one.targetId, [...(invoicePayments.get(one.targetId) ?? []), partOf(one, (0, document_targets_1.paidOfDocument)(one))]);
|
|
94
|
+
for (const request of requests) {
|
|
95
|
+
const settlements = direct.filter(one => one.targetId === request.id).map(one => partOf(one, Number(one.amount)));
|
|
96
|
+
states.set(request.id, paymentStateFrom(request.items ?? [], settlements, invoicePayments));
|
|
97
|
+
}
|
|
98
|
+
return states;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=expenditure-payment-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expenditure-payment-state.js","sourceRoot":"","sources":["../../../server/service/expenditure-request/expenditure-payment-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In } from 'typeorm'\nimport { registerEnumType } from 'type-graphql'\n\nimport { Payment } from '../payment/payment'\nimport { paidOfDocument, TAX_INVOICE_TARGET } from '../payment/document-targets'\nimport { isPayable, type RequestLine } from './expenditure-request-rules'\n\n/** The payment target kind of an expenditure request - the money paid on it directly, with no document between. */\nexport const EXPENDITURE_TARGET = 'ExpenditureRequest'\n\nexport enum ExpenditurePaymentState {\n /** Only corporate-card lines - the company already paid. */\n NOTHING_TO_PAY = 'NOTHING_TO_PAY',\n UNPAID = 'UNPAID',\n PARTLY_PAID = 'PARTLY_PAID',\n PAID = 'PAID'\n}\n\nregisterEnumType(ExpenditurePaymentState, {\n name: 'ExpenditurePaymentState',\n description: 'How much of an expenditure request the bank lines that paid it cover'\n})\n\nexport interface PaidPart {\n amount: number\n transactionId: string\n /** The line was matched to the bank statement (it carries the statement's fingerprint). */\n reconciled: boolean\n}\n\nexport interface PaymentState {\n state: ExpenditurePaymentState\n payable: number\n paid: number\n outstanding: number\n /** What is paid on the request directly - the payable part not cited from a tax invoice. */\n settleable: number\n settled: number\n /** Every bank line that paid it was matched to the bank statement. */\n reconciled: boolean\n transactionIds: string[]\n /** What is still to pay of each tax invoice a payable line cites - a reader that counts the invoice elsewhere takes it off. */\n cited: { taxInvoiceId: string; outstanding: number }[]\n}\n\n/**\n * How far a request is paid (ADR-0135 §2-4, §2-5). Pure.\n *\n * A payable line that cites a purchase tax invoice is paid when that invoice is - the bank line pays the invoice, and\n * the request reads it (ADR-0122 §3-3: one path for one fact). The rest of the request is paid by the payments on the\n * request itself.\n */\nexport function paymentStateFrom(\n lines: readonly RequestLine[],\n settlements: readonly PaidPart[],\n invoicePayments: ReadonlyMap<string, readonly PaidPart[]>\n): PaymentState {\n const payableLines = lines.filter(isPayable)\n const payable = payableLines.reduce((sum, line) => sum + (line.amount || 0), 0)\n\n let citedTotal = 0\n let paidByInvoices = 0\n const cited: PaymentState['cited'] = []\n const parts: PaidPart[] = [...settlements]\n for (const line of payableLines.filter(one => one.taxInvoiceId)) {\n citedTotal += line.amount || 0\n const ofInvoice = invoicePayments.get(line.taxInvoiceId!) ?? []\n const paidOfLine = Math.min(line.amount || 0, ofInvoice.reduce((sum, one) => sum + one.amount, 0))\n paidByInvoices += paidOfLine\n cited.push({ taxInvoiceId: line.taxInvoiceId!, outstanding: (line.amount || 0) - paidOfLine })\n parts.push(...ofInvoice)\n }\n const settled = settlements.reduce((sum, one) => sum + one.amount, 0)\n const paid = paidByInvoices + settled\n const outstanding = Math.max(0, payable - paid)\n\n const state =\n payable <= 0\n ? ExpenditurePaymentState.NOTHING_TO_PAY\n : paid <= 0\n ? ExpenditurePaymentState.UNPAID\n : outstanding > 0\n ? ExpenditurePaymentState.PARTLY_PAID\n : ExpenditurePaymentState.PAID\n\n return {\n state,\n payable,\n paid,\n outstanding,\n settleable: payable - citedTotal,\n settled,\n reconciled: parts.length > 0 && parts.every(one => one.reconciled),\n transactionIds: [...new Set(parts.map(one => one.transactionId))],\n cited\n }\n}\n\nconst partOf = (payment: Payment, amount: number): PaidPart => ({\n amount,\n transactionId: payment.transaction.id,\n reconciled: !!payment.transaction.bankFingerprint\n})\n\n/**\n * **The one reader of whether requests were paid and reconciled** - the payment queue, the forecast of what is to go\n * out, the AI and every 360 read it from here, never each on their own.\n */\nexport async function paymentStatesOf(\n tx: EntityManager,\n domain: { id: string },\n requests: readonly { id: string; items?: readonly RequestLine[] | null }[]\n): Promise<Map<string, PaymentState>> {\n const states = new Map<string, PaymentState>()\n if (!requests.length) return states\n\n const repo = tx.getRepository(Payment)\n const direct = await repo.find({\n where: { domain: { id: domain.id }, targetType: EXPENDITURE_TARGET, targetId: In(requests.map(one => one.id)) } as any,\n relations: ['transaction']\n })\n const invoiceIds = [...new Set(requests.flatMap(one => (one.items ?? []).map(item => item.taxInvoiceId).filter(Boolean) as string[]))]\n const onInvoices = invoiceIds.length\n ? await repo.find({ where: { domain: { id: domain.id }, targetType: TAX_INVOICE_TARGET, targetId: In(invoiceIds) } as any, relations: ['transaction'] })\n : []\n\n const invoicePayments = new Map<string, PaidPart[]>()\n for (const one of onInvoices) invoicePayments.set(one.targetId, [...(invoicePayments.get(one.targetId) ?? []), partOf(one, paidOfDocument(one))])\n\n for (const request of requests) {\n const settlements = direct.filter(one => one.targetId === request.id).map(one => partOf(one, Number(one.amount)))\n states.set(request.id, paymentStateFrom(request.items ?? [], settlements, invoicePayments))\n }\n return states\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Domain } from '@things-factory/shell';
|
|
2
|
+
import { User } from '@things-factory/auth-base';
|
|
3
|
+
import { TaxInvoice } from '@things-factory/tax-invoice';
|
|
4
|
+
import { Account } from '../account/account';
|
|
5
|
+
import { ExpenditureRequest } from './expenditure-request';
|
|
6
|
+
export declare enum ExpenditurePaymentMethod {
|
|
7
|
+
PERSONAL_CARD = "PERSONAL_CARD",
|
|
8
|
+
CORPORATE_CARD = "CORPORATE_CARD",
|
|
9
|
+
CASH = "CASH",
|
|
10
|
+
TRANSFER = "TRANSFER"
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* One thing a request pays for - a meal, a taxi, a supplier's invoice. A receipt is attached to it by id; a purchase
|
|
14
|
+
* tax invoice it pays is cited, and then the bank line pays that invoice (ADR-0135 §2-5).
|
|
15
|
+
*/
|
|
16
|
+
export declare class ExpenditureRequestItem {
|
|
17
|
+
readonly id: string;
|
|
18
|
+
domain?: Domain;
|
|
19
|
+
domainId?: string;
|
|
20
|
+
request?: ExpenditureRequest;
|
|
21
|
+
requestId?: string;
|
|
22
|
+
spentDate?: string;
|
|
23
|
+
category?: string;
|
|
24
|
+
account?: Account;
|
|
25
|
+
accountId?: string;
|
|
26
|
+
merchant?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
amount: number;
|
|
29
|
+
vatAmount?: number;
|
|
30
|
+
paymentMethod: ExpenditurePaymentMethod;
|
|
31
|
+
taxInvoice?: TaxInvoice;
|
|
32
|
+
taxInvoiceId?: string;
|
|
33
|
+
receiptUrl?: string;
|
|
34
|
+
createdAt?: Date;
|
|
35
|
+
updatedAt?: Date;
|
|
36
|
+
deletedAt?: Date;
|
|
37
|
+
creator?: User;
|
|
38
|
+
creatorId?: string;
|
|
39
|
+
updater?: User;
|
|
40
|
+
updaterId?: string;
|
|
41
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpenditureRequestItem = exports.ExpenditurePaymentMethod = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const auth_base_1 = require("@things-factory/auth-base");
|
|
9
|
+
const tax_invoice_1 = require("@things-factory/tax-invoice");
|
|
10
|
+
const account_1 = require("../account/account");
|
|
11
|
+
const expenditure_request_1 = require("./expenditure-request");
|
|
12
|
+
var ExpenditurePaymentMethod;
|
|
13
|
+
(function (ExpenditurePaymentMethod) {
|
|
14
|
+
ExpenditurePaymentMethod["PERSONAL_CARD"] = "PERSONAL_CARD";
|
|
15
|
+
ExpenditurePaymentMethod["CORPORATE_CARD"] = "CORPORATE_CARD";
|
|
16
|
+
ExpenditurePaymentMethod["CASH"] = "CASH";
|
|
17
|
+
ExpenditurePaymentMethod["TRANSFER"] = "TRANSFER";
|
|
18
|
+
})(ExpenditurePaymentMethod || (exports.ExpenditurePaymentMethod = ExpenditurePaymentMethod = {}));
|
|
19
|
+
(0, type_graphql_1.registerEnumType)(ExpenditurePaymentMethod, {
|
|
20
|
+
name: 'ExpenditurePaymentMethod',
|
|
21
|
+
description: 'How a line was paid - the corporate card is reported and approved, but the company already paid it'
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* One thing a request pays for - a meal, a taxi, a supplier's invoice. A receipt is attached to it by id; a purchase
|
|
25
|
+
* tax invoice it pays is cited, and then the bank line pays that invoice (ADR-0135 §2-5).
|
|
26
|
+
*/
|
|
27
|
+
let ExpenditureRequestItem = class ExpenditureRequestItem {
|
|
28
|
+
};
|
|
29
|
+
exports.ExpenditureRequestItem = ExpenditureRequestItem;
|
|
30
|
+
tslib_1.__decorate([
|
|
31
|
+
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
|
32
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.ID, { description: 'Unique identifier' }),
|
|
33
|
+
tslib_1.__metadata("design:type", String)
|
|
34
|
+
], ExpenditureRequestItem.prototype, "id", void 0);
|
|
35
|
+
tslib_1.__decorate([
|
|
36
|
+
(0, typeorm_1.ManyToOne)(type => shell_1.Domain),
|
|
37
|
+
(0, type_graphql_1.Field)(type => shell_1.Domain, { nullable: true, description: 'The domain it belongs to' }),
|
|
38
|
+
tslib_1.__metadata("design:type", shell_1.Domain)
|
|
39
|
+
], ExpenditureRequestItem.prototype, "domain", void 0);
|
|
40
|
+
tslib_1.__decorate([
|
|
41
|
+
(0, typeorm_1.RelationId)((item) => item.domain),
|
|
42
|
+
tslib_1.__metadata("design:type", String)
|
|
43
|
+
], ExpenditureRequestItem.prototype, "domainId", void 0);
|
|
44
|
+
tslib_1.__decorate([
|
|
45
|
+
(0, typeorm_1.ManyToOne)(type => expenditure_request_1.ExpenditureRequest, request => request.items, { nullable: false, onDelete: 'CASCADE' }),
|
|
46
|
+
(0, type_graphql_1.Field)(type => expenditure_request_1.ExpenditureRequest, { nullable: true, description: 'The request the line is on' }),
|
|
47
|
+
tslib_1.__metadata("design:type", expenditure_request_1.ExpenditureRequest)
|
|
48
|
+
], ExpenditureRequestItem.prototype, "request", void 0);
|
|
49
|
+
tslib_1.__decorate([
|
|
50
|
+
(0, typeorm_1.RelationId)((item) => item.request),
|
|
51
|
+
tslib_1.__metadata("design:type", String)
|
|
52
|
+
], ExpenditureRequestItem.prototype, "requestId", void 0);
|
|
53
|
+
tslib_1.__decorate([
|
|
54
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
55
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'YYYY-MM-DD it was spent, or the day of the invoice' }),
|
|
56
|
+
tslib_1.__metadata("design:type", String)
|
|
57
|
+
], ExpenditureRequestItem.prototype, "spentDate", void 0);
|
|
58
|
+
tslib_1.__decorate([
|
|
59
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
60
|
+
(0, type_graphql_1.Field)({ nullable: true, description: "What the requester called it - '식대', '교통비' - until an account is chosen" }),
|
|
61
|
+
tslib_1.__metadata("design:type", String)
|
|
62
|
+
], ExpenditureRequestItem.prototype, "category", void 0);
|
|
63
|
+
tslib_1.__decorate([
|
|
64
|
+
(0, typeorm_1.ManyToOne)(type => account_1.Account, { nullable: true, onDelete: 'SET NULL' }),
|
|
65
|
+
(0, type_graphql_1.Field)(type => account_1.Account, { nullable: true, description: '계정과목' }),
|
|
66
|
+
tslib_1.__metadata("design:type", account_1.Account)
|
|
67
|
+
], ExpenditureRequestItem.prototype, "account", void 0);
|
|
68
|
+
tslib_1.__decorate([
|
|
69
|
+
(0, typeorm_1.RelationId)((item) => item.account),
|
|
70
|
+
tslib_1.__metadata("design:type", String)
|
|
71
|
+
], ExpenditureRequestItem.prototype, "accountId", void 0);
|
|
72
|
+
tslib_1.__decorate([
|
|
73
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
74
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Where - the shop or company on the receipt' }),
|
|
75
|
+
tslib_1.__metadata("design:type", String)
|
|
76
|
+
], ExpenditureRequestItem.prototype, "merchant", void 0);
|
|
77
|
+
tslib_1.__decorate([
|
|
78
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
79
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'What for - the purpose an approver judges' }),
|
|
80
|
+
tslib_1.__metadata("design:type", String)
|
|
81
|
+
], ExpenditureRequestItem.prototype, "description", void 0);
|
|
82
|
+
tslib_1.__decorate([
|
|
83
|
+
(0, typeorm_1.Column)((0, shell_1.moneyColumn)()),
|
|
84
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Float, { description: 'Amount paid, VAT included' }),
|
|
85
|
+
tslib_1.__metadata("design:type", Number)
|
|
86
|
+
], ExpenditureRequestItem.prototype, "amount", void 0);
|
|
87
|
+
tslib_1.__decorate([
|
|
88
|
+
(0, typeorm_1.Column)((0, shell_1.moneyColumn)({ nullable: true, default: null })),
|
|
89
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Float, { nullable: true, description: 'VAT in the amount, when the receipt shows it' }),
|
|
90
|
+
tslib_1.__metadata("design:type", Number)
|
|
91
|
+
], ExpenditureRequestItem.prototype, "vatAmount", void 0);
|
|
92
|
+
tslib_1.__decorate([
|
|
93
|
+
(0, typeorm_1.Column)({ default: ExpenditurePaymentMethod.PERSONAL_CARD }),
|
|
94
|
+
(0, type_graphql_1.Field)(type => ExpenditurePaymentMethod, { description: 'How it was paid' }),
|
|
95
|
+
tslib_1.__metadata("design:type", String)
|
|
96
|
+
], ExpenditureRequestItem.prototype, "paymentMethod", void 0);
|
|
97
|
+
tslib_1.__decorate([
|
|
98
|
+
(0, typeorm_1.ManyToOne)(type => tax_invoice_1.TaxInvoice, { nullable: true }),
|
|
99
|
+
(0, type_graphql_1.Field)(type => tax_invoice_1.TaxInvoice, { nullable: true, description: 'The purchase tax invoice this line pays' }),
|
|
100
|
+
tslib_1.__metadata("design:type", tax_invoice_1.TaxInvoice)
|
|
101
|
+
], ExpenditureRequestItem.prototype, "taxInvoice", void 0);
|
|
102
|
+
tslib_1.__decorate([
|
|
103
|
+
(0, typeorm_1.RelationId)((item) => item.taxInvoice),
|
|
104
|
+
tslib_1.__metadata("design:type", String)
|
|
105
|
+
], ExpenditureRequestItem.prototype, "taxInvoiceId", void 0);
|
|
106
|
+
tslib_1.__decorate([
|
|
107
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Where the receipt is' }),
|
|
108
|
+
tslib_1.__metadata("design:type", String)
|
|
109
|
+
], ExpenditureRequestItem.prototype, "receiptUrl", void 0);
|
|
110
|
+
tslib_1.__decorate([
|
|
111
|
+
(0, typeorm_1.CreateDateColumn)(),
|
|
112
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When it was written' }),
|
|
113
|
+
tslib_1.__metadata("design:type", Date)
|
|
114
|
+
], ExpenditureRequestItem.prototype, "createdAt", void 0);
|
|
115
|
+
tslib_1.__decorate([
|
|
116
|
+
(0, typeorm_1.UpdateDateColumn)(),
|
|
117
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When it was last changed' }),
|
|
118
|
+
tslib_1.__metadata("design:type", Date)
|
|
119
|
+
], ExpenditureRequestItem.prototype, "updatedAt", void 0);
|
|
120
|
+
tslib_1.__decorate([
|
|
121
|
+
(0, typeorm_1.DeleteDateColumn)(),
|
|
122
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When it was deleted - financial rows are kept, not erased' }),
|
|
123
|
+
tslib_1.__metadata("design:type", Date)
|
|
124
|
+
], ExpenditureRequestItem.prototype, "deletedAt", void 0);
|
|
125
|
+
tslib_1.__decorate([
|
|
126
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
127
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true, description: 'Who wrote it' }),
|
|
128
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
129
|
+
], ExpenditureRequestItem.prototype, "creator", void 0);
|
|
130
|
+
tslib_1.__decorate([
|
|
131
|
+
(0, typeorm_1.RelationId)((item) => item.creator),
|
|
132
|
+
tslib_1.__metadata("design:type", String)
|
|
133
|
+
], ExpenditureRequestItem.prototype, "creatorId", void 0);
|
|
134
|
+
tslib_1.__decorate([
|
|
135
|
+
(0, typeorm_1.ManyToOne)(type => auth_base_1.User, { nullable: true }),
|
|
136
|
+
(0, type_graphql_1.Field)(type => auth_base_1.User, { nullable: true, description: 'Who changed it last' }),
|
|
137
|
+
tslib_1.__metadata("design:type", auth_base_1.User)
|
|
138
|
+
], ExpenditureRequestItem.prototype, "updater", void 0);
|
|
139
|
+
tslib_1.__decorate([
|
|
140
|
+
(0, typeorm_1.RelationId)((item) => item.updater),
|
|
141
|
+
tslib_1.__metadata("design:type", String)
|
|
142
|
+
], ExpenditureRequestItem.prototype, "updaterId", void 0);
|
|
143
|
+
exports.ExpenditureRequestItem = ExpenditureRequestItem = tslib_1.__decorate([
|
|
144
|
+
(0, typeorm_1.Entity)(),
|
|
145
|
+
(0, typeorm_1.Index)('ix_expenditure_request_item_0', (item) => [item.domain, item.request]),
|
|
146
|
+
(0, typeorm_1.Index)('ix_expenditure_request_item_1', (item) => [item.domain, item.taxInvoice]),
|
|
147
|
+
(0, type_graphql_1.ObjectType)({ description: 'One thing an expenditure request pays for' })
|
|
148
|
+
], ExpenditureRequestItem);
|
|
149
|
+
//# sourceMappingURL=expenditure-request-item.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expenditure-request-item.js","sourceRoot":"","sources":["../../../server/service/expenditure-request/expenditure-request-item.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n DeleteDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, Float, ID, ObjectType, registerEnumType } from 'type-graphql'\n\nimport { Domain, moneyColumn } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { TaxInvoice } from '@things-factory/tax-invoice'\n\nimport { Account } from '../account/account'\nimport { ExpenditureRequest } from './expenditure-request'\n\nexport enum ExpenditurePaymentMethod {\n PERSONAL_CARD = 'PERSONAL_CARD',\n CORPORATE_CARD = 'CORPORATE_CARD',\n CASH = 'CASH',\n TRANSFER = 'TRANSFER'\n}\n\nregisterEnumType(ExpenditurePaymentMethod, {\n name: 'ExpenditurePaymentMethod',\n description: 'How a line was paid - the corporate card is reported and approved, but the company already paid it'\n})\n\n/**\n * One thing a request pays for - a meal, a taxi, a supplier's invoice. A receipt is attached to it by id; a purchase\n * tax invoice it pays is cited, and then the bank line pays that invoice (ADR-0135 §2-5).\n */\n@Entity()\n@Index('ix_expenditure_request_item_0', (item: ExpenditureRequestItem) => [item.domain, item.request])\n@Index('ix_expenditure_request_item_1', (item: ExpenditureRequestItem) => [item.domain, item.taxInvoice])\n@ObjectType({ description: 'One thing an expenditure request pays for' })\nexport class ExpenditureRequestItem {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'The domain it belongs to' })\n domain?: Domain\n\n @RelationId((item: ExpenditureRequestItem) => item.domain)\n domainId?: string\n\n @ManyToOne(type => ExpenditureRequest, request => request.items, { nullable: false, onDelete: 'CASCADE' })\n @Field(type => ExpenditureRequest, { nullable: true, description: 'The request the line is on' })\n request?: ExpenditureRequest\n\n @RelationId((item: ExpenditureRequestItem) => item.request)\n requestId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'YYYY-MM-DD it was spent, or the day of the invoice' })\n spentDate?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: \"What the requester called it - '식대', '교통비' - until an account is chosen\" })\n category?: string\n\n @ManyToOne(type => Account, { nullable: true, onDelete: 'SET NULL' })\n @Field(type => Account, { nullable: true, description: '계정과목' })\n account?: Account\n\n @RelationId((item: ExpenditureRequestItem) => item.account)\n accountId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Where - the shop or company on the receipt' })\n merchant?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'What for - the purpose an approver judges' })\n description?: string\n\n @Column(moneyColumn())\n @Field(type => Float, { description: 'Amount paid, VAT included' })\n amount: number\n\n @Column(moneyColumn({ nullable: true, default: null }))\n @Field(type => Float, { nullable: true, description: 'VAT in the amount, when the receipt shows it' })\n vatAmount?: number\n\n @Column({ default: ExpenditurePaymentMethod.PERSONAL_CARD })\n @Field(type => ExpenditurePaymentMethod, { description: 'How it was paid' })\n paymentMethod: ExpenditurePaymentMethod\n\n @ManyToOne(type => TaxInvoice, { nullable: true })\n @Field(type => TaxInvoice, { nullable: true, description: 'The purchase tax invoice this line pays' })\n taxInvoice?: TaxInvoice\n\n @RelationId((item: ExpenditureRequestItem) => item.taxInvoice)\n taxInvoiceId?: string\n\n @Field({ nullable: true, description: 'Where the receipt is' })\n receiptUrl?: string\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'When it was written' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'When it was last changed' })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true, description: 'When it was deleted - financial rows are kept, not erased' })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'Who wrote it' })\n creator?: User\n\n @RelationId((item: ExpenditureRequestItem) => item.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'Who changed it last' })\n updater?: User\n\n @RelationId((item: ExpenditureRequestItem) => item.updater)\n updaterId?: string\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { FileUpload } from 'graphql-upload/GraphQLUpload.js';
|
|
2
|
+
import { ExpenditureRequest } from './expenditure-request';
|
|
3
|
+
import { ExpenditureRequestItem } from './expenditure-request-item';
|
|
4
|
+
import { ExpenditurePaymentInput, ExpenditureRequestInput, ExpenditureRequestItemPatch, NewExpenditureLine } from './expenditure-request-type';
|
|
5
|
+
export declare class ExpenditureRequestMutation {
|
|
6
|
+
/** Write a request and its lines. A new request is the caller's; an existing one only its requester's, while editable. */
|
|
7
|
+
saveExpenditureRequest(request: ExpenditureRequestInput, items: ExpenditureRequestItemPatch[], context: ResolverContext): Promise<ExpenditureRequest>;
|
|
8
|
+
/** One line from the phone - it joins this month's editable reimbursement, or starts one. */
|
|
9
|
+
addExpenditureLine(line: NewExpenditureLine, context: ResolverContext): Promise<ExpenditureRequest>;
|
|
10
|
+
attachExpenditureReceipt(itemId: string, file: FileUpload, context: ResolverContext): Promise<ExpenditureRequestItem>;
|
|
11
|
+
submitExpenditureRequest(id: string, context: ResolverContext): Promise<ExpenditureRequest>;
|
|
12
|
+
withdrawExpenditureRequest(id: string, context: ResolverContext): Promise<ExpenditureRequest>;
|
|
13
|
+
deleteExpenditureRequest(id: string, context: ResolverContext): Promise<boolean>;
|
|
14
|
+
/** Finance paid approved requests at the bank; each becomes a withdrawal that the next statement import matches. */
|
|
15
|
+
payExpenditureRequests(ids: string[], payment: ExpenditurePaymentInput, context: ResolverContext): Promise<ExpenditureRequest[]>;
|
|
16
|
+
/** Pay a request with a withdrawal already in the books - a bank statement brought it in first. */
|
|
17
|
+
payExpenditureRequestWithLine(id: string, transactionId: string, amount: number, context: ResolverContext): Promise<ExpenditureRequest>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpenditureRequestMutation = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const GraphQLUpload_js_1 = tslib_1.__importDefault(require("graphql-upload/GraphQLUpload.js"));
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const expenditure_request_1 = require("./expenditure-request");
|
|
9
|
+
const expenditure_request_item_1 = require("./expenditure-request-item");
|
|
10
|
+
const expenditure_request_service_1 = require("./expenditure-request-service");
|
|
11
|
+
const expenditure_request_type_1 = require("./expenditure-request-type");
|
|
12
|
+
let ExpenditureRequestMutation = class ExpenditureRequestMutation {
|
|
13
|
+
/** Write a request and its lines. A new request is the caller's; an existing one only its requester's, while editable. */
|
|
14
|
+
async saveExpenditureRequest(request, items, context) {
|
|
15
|
+
const { domain, user, tx } = context.state;
|
|
16
|
+
return await (0, expenditure_request_service_1.saveRequest)(tx, domain, user, request, items ?? []);
|
|
17
|
+
}
|
|
18
|
+
/** One line from the phone - it joins this month's editable reimbursement, or starts one. */
|
|
19
|
+
async addExpenditureLine(line, context) {
|
|
20
|
+
const { domain, user, tx } = context.state;
|
|
21
|
+
return await (0, expenditure_request_service_1.addLine)(tx, domain, user, line, context);
|
|
22
|
+
}
|
|
23
|
+
async attachExpenditureReceipt(itemId, file, context) {
|
|
24
|
+
const { domain, user, tx } = context.state;
|
|
25
|
+
return await (0, expenditure_request_service_1.replaceReceipt)(tx, domain, user, itemId, file, context);
|
|
26
|
+
}
|
|
27
|
+
async submitExpenditureRequest(id, context) {
|
|
28
|
+
const { domain, user, tx } = context.state;
|
|
29
|
+
return await (0, expenditure_request_service_1.submitRequest)(tx, domain, user, id, context);
|
|
30
|
+
}
|
|
31
|
+
async withdrawExpenditureRequest(id, context) {
|
|
32
|
+
const { domain, user, tx } = context.state;
|
|
33
|
+
return await (0, expenditure_request_service_1.withdrawRequest)(tx, domain, user, id, context);
|
|
34
|
+
}
|
|
35
|
+
async deleteExpenditureRequest(id, context) {
|
|
36
|
+
const { domain, user, tx } = context.state;
|
|
37
|
+
return await (0, expenditure_request_service_1.deleteRequest)(tx, domain, user, id);
|
|
38
|
+
}
|
|
39
|
+
/** Finance paid approved requests at the bank; each becomes a withdrawal that the next statement import matches. */
|
|
40
|
+
async payExpenditureRequests(ids, payment, context) {
|
|
41
|
+
const { domain, user, tx } = context.state;
|
|
42
|
+
return await (0, expenditure_request_service_1.payRequests)(tx, domain, user, ids, payment);
|
|
43
|
+
}
|
|
44
|
+
/** Pay a request with a withdrawal already in the books - a bank statement brought it in first. */
|
|
45
|
+
async payExpenditureRequestWithLine(id, transactionId, amount, context) {
|
|
46
|
+
const { domain, user, tx } = context.state;
|
|
47
|
+
return await (0, expenditure_request_service_1.payWithLine)(tx, domain, user, id, transactionId, amount);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
exports.ExpenditureRequestMutation = ExpenditureRequestMutation;
|
|
51
|
+
tslib_1.__decorate([
|
|
52
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
53
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "mutation", domainOwnerGranted: true)'),
|
|
54
|
+
(0, type_graphql_1.Mutation)(returns => expenditure_request_1.ExpenditureRequest, { description: 'Save an expenditure request and its lines' }),
|
|
55
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('request', type => expenditure_request_type_1.ExpenditureRequestInput)),
|
|
56
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('items', type => [expenditure_request_type_1.ExpenditureRequestItemPatch], { nullable: true })),
|
|
57
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
58
|
+
tslib_1.__metadata("design:type", Function),
|
|
59
|
+
tslib_1.__metadata("design:paramtypes", [expenditure_request_type_1.ExpenditureRequestInput, Array, Object]),
|
|
60
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
61
|
+
], ExpenditureRequestMutation.prototype, "saveExpenditureRequest", null);
|
|
62
|
+
tslib_1.__decorate([
|
|
63
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
64
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "mutation", domainOwnerGranted: true)'),
|
|
65
|
+
(0, type_graphql_1.Mutation)(returns => expenditure_request_1.ExpenditureRequest, { description: "Add one expense line to the caller's reimbursement of that month" }),
|
|
66
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('line', type => expenditure_request_type_1.NewExpenditureLine)),
|
|
67
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
68
|
+
tslib_1.__metadata("design:type", Function),
|
|
69
|
+
tslib_1.__metadata("design:paramtypes", [expenditure_request_type_1.NewExpenditureLine, Object]),
|
|
70
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
71
|
+
], ExpenditureRequestMutation.prototype, "addExpenditureLine", null);
|
|
72
|
+
tslib_1.__decorate([
|
|
73
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
74
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "mutation", domainOwnerGranted: true)'),
|
|
75
|
+
(0, type_graphql_1.Mutation)(returns => expenditure_request_item_1.ExpenditureRequestItem, { description: 'Put (or replace) the receipt of a line' }),
|
|
76
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('itemId')),
|
|
77
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('file', type => GraphQLUpload_js_1.default)),
|
|
78
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
79
|
+
tslib_1.__metadata("design:type", Function),
|
|
80
|
+
tslib_1.__metadata("design:paramtypes", [String, Object, Object]),
|
|
81
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
82
|
+
], ExpenditureRequestMutation.prototype, "attachExpenditureReceipt", null);
|
|
83
|
+
tslib_1.__decorate([
|
|
84
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
85
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "mutation", domainOwnerGranted: true)'),
|
|
86
|
+
(0, type_graphql_1.Mutation)(returns => expenditure_request_1.ExpenditureRequest, { description: 'Put an expenditure request up for approval (상신)' }),
|
|
87
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
88
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
89
|
+
tslib_1.__metadata("design:type", Function),
|
|
90
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
91
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
92
|
+
], ExpenditureRequestMutation.prototype, "submitExpenditureRequest", null);
|
|
93
|
+
tslib_1.__decorate([
|
|
94
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
95
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "mutation", domainOwnerGranted: true)'),
|
|
96
|
+
(0, type_graphql_1.Mutation)(returns => expenditure_request_1.ExpenditureRequest, { description: 'Take a submitted request back from its approvers (회수)' }),
|
|
97
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
98
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
99
|
+
tslib_1.__metadata("design:type", Function),
|
|
100
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
101
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
102
|
+
], ExpenditureRequestMutation.prototype, "withdrawExpenditureRequest", null);
|
|
103
|
+
tslib_1.__decorate([
|
|
104
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
105
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting-self", privilege: "mutation", domainOwnerGranted: true)'),
|
|
106
|
+
(0, type_graphql_1.Mutation)(returns => Boolean, { description: 'Delete an editable expenditure request of the caller' }),
|
|
107
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
108
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
109
|
+
tslib_1.__metadata("design:type", Function),
|
|
110
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
111
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
112
|
+
], ExpenditureRequestMutation.prototype, "deleteExpenditureRequest", null);
|
|
113
|
+
tslib_1.__decorate([
|
|
114
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
115
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting", privilege: "mutation", domainOwnerGranted: true)'),
|
|
116
|
+
(0, type_graphql_1.Mutation)(returns => [expenditure_request_1.ExpenditureRequest], { description: 'Record that approved expenditure requests were paid' }),
|
|
117
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('ids', type => [String])),
|
|
118
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('payment', type => expenditure_request_type_1.ExpenditurePaymentInput)),
|
|
119
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
120
|
+
tslib_1.__metadata("design:type", Function),
|
|
121
|
+
tslib_1.__metadata("design:paramtypes", [Array, expenditure_request_type_1.ExpenditurePaymentInput, Object]),
|
|
122
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
123
|
+
], ExpenditureRequestMutation.prototype, "payExpenditureRequests", null);
|
|
124
|
+
tslib_1.__decorate([
|
|
125
|
+
(0, type_graphql_1.Directive)('@transaction'),
|
|
126
|
+
(0, type_graphql_1.Directive)('@privilege(category: "accounting", privilege: "mutation", domainOwnerGranted: true)'),
|
|
127
|
+
(0, type_graphql_1.Mutation)(returns => expenditure_request_1.ExpenditureRequest, { description: 'Put a withdrawal already in the books on an approved expenditure request' }),
|
|
128
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
|
|
129
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('transactionId')),
|
|
130
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('amount', type => type_graphql_1.Float, { nullable: true })),
|
|
131
|
+
tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
|
|
132
|
+
tslib_1.__metadata("design:type", Function),
|
|
133
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Number, Object]),
|
|
134
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
135
|
+
], ExpenditureRequestMutation.prototype, "payExpenditureRequestWithLine", null);
|
|
136
|
+
exports.ExpenditureRequestMutation = ExpenditureRequestMutation = tslib_1.__decorate([
|
|
137
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
|
|
138
|
+
(0, type_graphql_1.Resolver)(expenditure_request_1.ExpenditureRequest)
|
|
139
|
+
], ExpenditureRequestMutation);
|
|
140
|
+
//# sourceMappingURL=expenditure-request-mutation.js.map
|
|
@@ -0,0 +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 { 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 } = context.state\n return await saveRequest(tx, domain, user, request, items ?? [])\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: \"accounting\", 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: \"accounting\", 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"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Domain, ListParam } from '@things-factory/shell';
|
|
2
|
+
import { User } from '@things-factory/auth-base';
|
|
3
|
+
import { Counterparty, CounterpartyBankAccount } from '@things-factory/biz-base';
|
|
4
|
+
import { Department } from '@things-factory/organization';
|
|
5
|
+
import { TaxInvoice } from '@things-factory/tax-invoice';
|
|
6
|
+
import { Account } from '../account/account';
|
|
7
|
+
import { ExpenditureRequest } from './expenditure-request';
|
|
8
|
+
import { ExpenditureRequestItem } from './expenditure-request-item';
|
|
9
|
+
import { ExpenditurePayment, ExpenditureQueue, ExpenditureRequestList, ExpenditureSummary } from './expenditure-request-type';
|
|
10
|
+
export declare class ExpenditureRequestQuery {
|
|
11
|
+
/** The caller's own requests - what an employee sees. */
|
|
12
|
+
myExpenditureRequests(params: ListParam, context: ResolverContext): Promise<ExpenditureRequestList>;
|
|
13
|
+
/** One of the caller's own requests, with its lines. */
|
|
14
|
+
myExpenditureRequest(id: string, context: ResolverContext): Promise<ExpenditureRequest | null>;
|
|
15
|
+
/** Every request of the domain - what finance sees. */
|
|
16
|
+
expenditureRequests(params: ListParam, context: ResolverContext): Promise<ExpenditureRequestList>;
|
|
17
|
+
expenditureRequest(id: string, context: ResolverContext): Promise<ExpenditureRequest | null>;
|
|
18
|
+
/**
|
|
19
|
+
* The payment queue (지급 대기) - approved requests still to pay, by the day they are to be paid, and the paid ones
|
|
20
|
+
* whose bank line no statement has matched yet.
|
|
21
|
+
*/
|
|
22
|
+
expenditureQueue(context: ResolverContext): Promise<ExpenditureQueue>;
|
|
23
|
+
expenditureSummary(year: number, month: number, context: ResolverContext): Promise<ExpenditureSummary>;
|
|
24
|
+
myExpenditureSummary(year: number, month: number, context: ResolverContext): Promise<ExpenditureSummary>;
|
|
25
|
+
/** How far it is paid - read from its payments (ADR-0135 §2-4). */
|
|
26
|
+
payment(request: ExpenditureRequest): Promise<ExpenditurePayment | null>;
|
|
27
|
+
items(request: ExpenditureRequest): Promise<ExpenditureRequestItem[]>;
|
|
28
|
+
requester(request: ExpenditureRequest): Promise<User | null>;
|
|
29
|
+
department(request: ExpenditureRequest): Promise<Department | null>;
|
|
30
|
+
counterparty(request: ExpenditureRequest): Promise<Counterparty | null>;
|
|
31
|
+
payeeAccount(request: ExpenditureRequest): Promise<CounterpartyBankAccount | null>;
|
|
32
|
+
decidedBy(request: ExpenditureRequest): Promise<User | null>;
|
|
33
|
+
domain(request: ExpenditureRequest): Promise<Domain>;
|
|
34
|
+
creator(request: ExpenditureRequest): Promise<User | null>;
|
|
35
|
+
updater(request: ExpenditureRequest): Promise<User | null>;
|
|
36
|
+
}
|
|
37
|
+
export declare class ExpenditureRequestItemQuery {
|
|
38
|
+
request(item: ExpenditureRequestItem): Promise<ExpenditureRequest | null>;
|
|
39
|
+
account(item: ExpenditureRequestItem): Promise<Account | null>;
|
|
40
|
+
taxInvoice(item: ExpenditureRequestItem): Promise<TaxInvoice | null>;
|
|
41
|
+
/** Where the receipt is, or null - so an approver can see what was spent. */
|
|
42
|
+
receiptUrl(item: ExpenditureRequestItem): Promise<string | null>;
|
|
43
|
+
domain(item: ExpenditureRequestItem): Promise<Domain>;
|
|
44
|
+
creator(item: ExpenditureRequestItem): Promise<User | null>;
|
|
45
|
+
updater(item: ExpenditureRequestItem): Promise<User | null>;
|
|
46
|
+
}
|