@things-factory/accounting 10.1.233 → 10.1.234

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.
Files changed (90) hide show
  1. package/dist-client/tsconfig.tsbuildinfo +1 -1
  2. package/dist-server/service/account/account-mutation.js +7 -53
  3. package/dist-server/service/account/account-mutation.js.map +1 -1
  4. package/dist-server/service/account/account-service.d.ts +15 -0
  5. package/dist-server/service/account/account-service.js +40 -0
  6. package/dist-server/service/account/account-service.js.map +1 -1
  7. package/dist-server/service/bank-account/bank-account-history.d.ts +7 -0
  8. package/dist-server/service/bank-account/bank-account-history.js +29 -0
  9. package/dist-server/service/bank-account/bank-account-history.js.map +1 -1
  10. package/dist-server/service/bank-account/bank-account-mutation.js +4 -4
  11. package/dist-server/service/bank-account/bank-account-mutation.js.map +1 -1
  12. package/dist-server/service/bank-account/bank-account-query.d.ts +3 -0
  13. package/dist-server/service/bank-account/bank-account-query.js +23 -0
  14. package/dist-server/service/bank-account/bank-account-query.js.map +1 -1
  15. package/dist-server/service/bank-account/bank-account-service.d.ts +27 -0
  16. package/dist-server/service/bank-account/bank-account-service.js +55 -0
  17. package/dist-server/service/bank-account/bank-account-service.js.map +1 -1
  18. package/dist-server/service/bank-account/bank-account-type.d.ts +9 -0
  19. package/dist-server/service/bank-account/bank-account-type.js +33 -0
  20. package/dist-server/service/bank-account/bank-account-type.js.map +1 -1
  21. package/dist-server/service/bank-account/bank-account.d.ts +7 -0
  22. package/dist-server/service/bank-account/bank-account.js +29 -0
  23. package/dist-server/service/bank-account/bank-account.js.map +1 -1
  24. package/dist-server/service/bank-account/card-query.d.ts +24 -0
  25. package/dist-server/service/bank-account/card-query.js +140 -0
  26. package/dist-server/service/bank-account/card-query.js.map +1 -0
  27. package/dist-server/service/bank-account/card-rules.d.ts +21 -0
  28. package/dist-server/service/bank-account/card-rules.js +30 -0
  29. package/dist-server/service/bank-account/card-rules.js.map +1 -0
  30. package/dist-server/service/bank-account/card-summary.d.ts +29 -0
  31. package/dist-server/service/bank-account/card-summary.js +42 -0
  32. package/dist-server/service/bank-account/card-summary.js.map +1 -0
  33. package/dist-server/service/bank-account/index.d.ts +2 -1
  34. package/dist-server/service/bank-account/index.js +2 -1
  35. package/dist-server/service/bank-account/index.js.map +1 -1
  36. package/dist-server/service/expenditure-request/card-charge-query.d.ts +10 -0
  37. package/dist-server/service/expenditure-request/card-charge-query.js +54 -0
  38. package/dist-server/service/expenditure-request/card-charge-query.js.map +1 -0
  39. package/dist-server/service/expenditure-request/expenditure-request-item.d.ts +4 -0
  40. package/dist-server/service/expenditure-request/expenditure-request-item.js +19 -1
  41. package/dist-server/service/expenditure-request/expenditure-request-item.js.map +1 -1
  42. package/dist-server/service/expenditure-request/expenditure-request-mutation.js +2 -1
  43. package/dist-server/service/expenditure-request/expenditure-request-mutation.js.map +1 -1
  44. package/dist-server/service/expenditure-request/expenditure-request-rules.d.ts +26 -2
  45. package/dist-server/service/expenditure-request/expenditure-request-rules.js +19 -2
  46. package/dist-server/service/expenditure-request/expenditure-request-rules.js.map +1 -1
  47. package/dist-server/service/expenditure-request/expenditure-request-service.d.ts +6 -0
  48. package/dist-server/service/expenditure-request/expenditure-request-service.js +35 -1
  49. package/dist-server/service/expenditure-request/expenditure-request-service.js.map +1 -1
  50. package/dist-server/service/expenditure-request/expenditure-request-type.d.ts +2 -0
  51. package/dist-server/service/expenditure-request/expenditure-request-type.js +8 -0
  52. package/dist-server/service/expenditure-request/expenditure-request-type.js.map +1 -1
  53. package/dist-server/service/expenditure-request/index.d.ts +2 -1
  54. package/dist-server/service/expenditure-request/index.js +2 -1
  55. package/dist-server/service/expenditure-request/index.js.map +1 -1
  56. package/dist-server/service/index.d.ts +4 -1
  57. package/dist-server/service/index.js +3 -0
  58. package/dist-server/service/index.js.map +1 -1
  59. package/dist-server/service/payment/card-bill-target.d.ts +2 -0
  60. package/dist-server/service/payment/card-bill-target.js +37 -0
  61. package/dist-server/service/payment/card-bill-target.js.map +1 -0
  62. package/dist-server/service/payment/index.d.ts +1 -0
  63. package/dist-server/service/payment/index.js +1 -0
  64. package/dist-server/service/payment/index.js.map +1 -1
  65. package/dist-server/service/recurring-cash-item/recurring-cash-item-query.d.ts +2 -0
  66. package/dist-server/service/recurring-cash-item/recurring-cash-item-query.js +14 -0
  67. package/dist-server/service/recurring-cash-item/recurring-cash-item-query.js.map +1 -1
  68. package/dist-server/service/recurring-cash-item/recurring-cash-item-service.d.ts +5 -0
  69. package/dist-server/service/recurring-cash-item/recurring-cash-item-service.js +22 -1
  70. package/dist-server/service/recurring-cash-item/recurring-cash-item-service.js.map +1 -1
  71. package/dist-server/service/recurring-cash-item/recurring-schedule.d.ts +5 -1
  72. package/dist-server/service/recurring-cash-item/recurring-schedule.js +10 -2
  73. package/dist-server/service/recurring-cash-item/recurring-schedule.js.map +1 -1
  74. package/dist-server/service/transaction/transaction-query.d.ts +5 -0
  75. package/dist-server/service/transaction/transaction-query.js +3 -3
  76. package/dist-server/service/transaction/transaction-query.js.map +1 -1
  77. package/dist-server/service/transaction/transaction-service.d.ts +5 -1
  78. package/dist-server/service/transaction/transaction-service.js +15 -10
  79. package/dist-server/service/transaction/transaction-service.js.map +1 -1
  80. package/dist-server/service/transaction/transaction.d.ts +5 -3
  81. package/dist-server/service/transaction/transaction.js +6 -4
  82. package/dist-server/service/transaction/transaction.js.map +1 -1
  83. package/dist-server/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +11 -10
  85. package/translations/en.json +30 -1
  86. package/translations/es.json +30 -1
  87. package/translations/ja.json +30 -1
  88. package/translations/ko.json +30 -1
  89. package/translations/ms.json +30 -1
  90. package/translations/zh.json +30 -1
@@ -1 +1 @@
1
- {"version":3,"file":"bank-account-service.js","sourceRoot":"","sources":["../../../server/service/bank-account/bank-account-service.ts"],"names":[],"mappings":";;AAWA,gDAgBC;AA3BD,qCAA2C;AAE3C,iDAA+D;AAE/D,4DAAwD;AACxD,iDAA4C;AAE5C;;;GAGG;AACI,KAAK,UAAU,kBAAkB,CAAC,EAAiB,EAAE,MAAsB,EAAE,GAAa;IAC/F,MAAM,IAAI,GAAG,EAAE,CAAC,aAAa,CAAC,0BAAW,CAAC,CAAA;IAC1C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAA,YAAE,EAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAA;IACpF,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI;QACpC,MAAM,IAAI,eAAO,CAAC,wBAAwB,EAAE,EAAE,EAAE,qDAAqD,CAAC,CAAA;IACxG,MAAM,IAAI,GAAG,MAAM,EAAE;SAClB,aAAa,CAAC,yBAAW,CAAC;SAC1B,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,IAAA,YAAE,EAAC,GAAG,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;IACnG,IAAI,IAAI;QACN,MAAM,IAAI,eAAO,CACf,+BAA+B,EAC/B,EAAE,EACF,qEAAqE,CACtE,CAAA;IACH,MAAM,IAAA,sBAAc,EAAC,EAAE,EAAE,0BAAW,EAAE,GAAG,CAAC,CAAA;IAC1C,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;AAC9B,CAAC","sourcesContent":["import { EntityManager, In } from 'typeorm'\n\nimport { Refusal, refuseTiedRows } from '@things-factory/shell'\n\nimport { Transaction } from '../transaction/transaction'\nimport { BankAccount } from './bank-account'\n\n/**\n * An account that lines were written on is made inactive, not deleted - the lines keep pointing at it, deleted ones\n * too, since a deleted financial row stays readable. Whatever else names it stops the delete (§`refuseTiedRows`).\n */\nexport async function deleteBankAccounts(tx: EntityManager, domain: { id: string }, ids: string[]): Promise<void> {\n const repo = tx.getRepository(BankAccount)\n const found = await repo.find({ where: { domain: { id: domain.id }, id: In(ids) } })\n if (found.length !== new Set(ids).size)\n throw new Refusal('bank-account-not-found', {}, 'a bank account was not found - reload and try again')\n const used = await tx\n .getRepository(Transaction)\n .count({ where: { domain: { id: domain.id }, bankAccount: { id: In(ids) } }, withDeleted: true })\n if (used)\n throw new Refusal(\n 'bank-account-has-transactions',\n {},\n 'transactions were written on the account - make it inactive instead'\n )\n await refuseTiedRows(tx, BankAccount, ids)\n await repo.softRemove(found)\n}\n"]}
1
+ {"version":3,"file":"bank-account-service.js","sourceRoot":"","sources":["../../../server/service/bank-account/bank-account-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In, Not } from 'typeorm'\nimport moment from 'moment-timezone'\n\nimport { Refusal, refuseTiedRows } from '@things-factory/shell'\n\nimport { Employee } from '@things-factory/organization'\n\nimport { Transaction } from '../transaction/transaction'\nimport { AccountType, BankAccount } from './bank-account'\nimport { checkCardFields } from './card-rules'\n\n/**\n * An account that lines were written on is made inactive, not deleted - the lines keep pointing at it, deleted ones\n * too, since a deleted financial row stays readable. Whatever else names it stops the delete (§`refuseTiedRows`).\n */\nexport async function deleteBankAccounts(tx: EntityManager, domain: { id: string }, ids: string[]): Promise<void> {\n const repo = tx.getRepository(BankAccount)\n const found = await repo.find({ where: { domain: { id: domain.id }, id: In(ids) } })\n if (found.length !== new Set(ids).size)\n throw new Refusal('bank-account-not-found', {}, 'a bank account was not found - reload and try again')\n const used = await tx\n .getRepository(Transaction)\n .count({ where: { domain: { id: domain.id }, bankAccount: { id: In(ids) } }, withDeleted: true })\n if (used)\n throw new Refusal(\n 'bank-account-has-transactions',\n {},\n 'transactions were written on the account - make it inactive instead'\n )\n await refuseTiedRows(tx, BankAccount, ids)\n await repo.softRemove(found)\n}\n\n/** A patch as the doors take it - relations by `{ id }`. */\nexport type BankAccountInput = Partial<Omit<BankAccount, 'holder' | 'settlementAccount'>> & {\n holder?: { id: string } | null\n settlementAccount?: { id: string } | null\n}\n\nconst ISO_CURRENCIES = new Set((Intl as any).supportedValuesOf('currency') as string[])\n\n/**\n * What an account must hold before it is written, read off the account alone: a name, and - when given - an ISO 4217\n * currency and an IANA time zone, the two a statement import reads its lines by (§`bankTimestamp`). Pure.\n */\nexport function checkBankAccountFields(account: { name?: string | null; currency?: string | null; timezone?: string | null }): void {\n if (account.name === undefined || account.name === null || String(account.name).trim() === '')\n throw new Refusal('bank-account-name-required', {}, 'name: an account has one')\n if (account.currency !== undefined && !ISO_CURRENCIES.has(String(account.currency ?? '')))\n throw new Refusal('bank-account-currency', { value: account.currency ?? '' }, `currency: ${account.currency ?? ''} is not a three-letter ISO 4217 code such as KRW`)\n if (account.timezone !== undefined && !(account.timezone && moment.tz.zone(account.timezone)))\n throw new Refusal('bank-account-timezone', { value: account.timezone ?? '' }, `timezone: ${account.timezone ?? ''} is not an IANA time zone such as Asia/Seoul`)\n}\n\n/**\n * Write a bank account, new or changed. A card keeps a card's facts (§`checkCardFields`): its holder is an employee, its\n * bill is paid from one of the domain's bank accounts. An account with lines keeps its type - a line's category is\n * its account's (ADR-0178 결정 1).\n */\nexport async function saveBankAccount(\n tx: EntityManager,\n domain: { id: string },\n user: any,\n input: BankAccountInput,\n current?: BankAccount\n): Promise<BankAccount> {\n const repo = tx.getRepository(BankAccount)\n const merged = {\n ...current,\n holder: current?.holderId ? { id: current.holderId } : null,\n settlementAccount: current?.settlementAccountId ? { id: current.settlementAccountId } : null,\n accountType: current?.accountType ?? AccountType.BANK,\n ...input\n }\n checkCardFields(merged)\n checkBankAccountFields(merged)\n if (await repo.findOne({ where: { domain: { id: domain.id }, name: merged.name, ...(current ? { id: Not(current.id) } : {}) } }))\n throw new Refusal('bank-account-name-taken', { value: merged.name }, `name: ${merged.name} is already another account's`)\n\n if (current && input.accountType && input.accountType !== current.accountType) {\n const lines = await tx\n .getRepository(Transaction)\n .count({ where: { domain: { id: domain.id }, bankAccount: { id: current.id } }, withDeleted: true })\n if (lines)\n throw new Refusal('account-type-has-lines', {}, 'accountType: lines were written on the account - its type stays')\n }\n if (input.holder?.id && !(await tx.getRepository(Employee).findOne({ where: { domain: { id: domain.id }, id: input.holder.id } as any })))\n throw new Refusal('card-holder-not-found', {}, 'holder: the employee was not found')\n if (input.settlementAccount?.id) {\n const paidFrom = await repo.findOne({ where: { domain: { id: domain.id }, id: input.settlementAccount.id } })\n if (!paidFrom || paidFrom.accountType !== AccountType.BANK)\n throw new Refusal('card-settlement-not-bank', {}, 'settlementAccount: one of the bank accounts')\n }\n if (merged.accountType === AccountType.CARD && typeof input.accountNumber === 'string')\n input = { ...input, accountNumber: input.accountNumber.trim() }\n\n return await repo.save({ ...(current ?? { domain, creator: user }), ...input, updater: user } as BankAccount)\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { ObjectRef } from '@things-factory/shell';
1
2
  import { AccountType, BankAccount, BankAccountPurpose } from './bank-account';
2
3
  export declare class NewBankAccount {
3
4
  name: string;
@@ -10,6 +11,10 @@ export declare class NewBankAccount {
10
11
  purpose?: BankAccountPurpose;
11
12
  statedBalance?: number;
12
13
  statedBalanceDate?: string;
14
+ holder?: ObjectRef;
15
+ settlementAccount?: ObjectRef;
16
+ paymentDay?: number;
17
+ creditLimit?: number;
13
18
  active?: boolean;
14
19
  }
15
20
  export declare class BankAccountPatch {
@@ -24,6 +29,10 @@ export declare class BankAccountPatch {
24
29
  purpose?: BankAccountPurpose;
25
30
  statedBalance?: number;
26
31
  statedBalanceDate?: string;
32
+ holder?: ObjectRef;
33
+ settlementAccount?: ObjectRef;
34
+ paymentDay?: number;
35
+ creditLimit?: number;
27
36
  active?: boolean;
28
37
  cuFlag?: string;
29
38
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BankAccountList = exports.BankAccountPatch = exports.NewBankAccount = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const type_graphql_1 = require("type-graphql");
6
+ const shell_1 = require("@things-factory/shell");
6
7
  const bank_account_1 = require("./bank-account");
7
8
  let NewBankAccount = class NewBankAccount {
8
9
  };
@@ -47,6 +48,22 @@ tslib_1.__decorate([
47
48
  (0, type_graphql_1.Field)({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' }),
48
49
  tslib_1.__metadata("design:type", String)
49
50
  ], NewBankAccount.prototype, "statedBalanceDate", void 0);
51
+ tslib_1.__decorate([
52
+ (0, type_graphql_1.Field)(type => shell_1.ObjectRef, { nullable: true, description: "A card's holder" }),
53
+ tslib_1.__metadata("design:type", shell_1.ObjectRef)
54
+ ], NewBankAccount.prototype, "holder", void 0);
55
+ tslib_1.__decorate([
56
+ (0, type_graphql_1.Field)(type => shell_1.ObjectRef, { nullable: true, description: "The bank account a card's bill is paid from" }),
57
+ tslib_1.__metadata("design:type", shell_1.ObjectRef)
58
+ ], NewBankAccount.prototype, "settlementAccount", void 0);
59
+ tslib_1.__decorate([
60
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: "Day of the month a card's bill is paid - 31 for the last day" }),
61
+ tslib_1.__metadata("design:type", Number)
62
+ ], NewBankAccount.prototype, "paymentDay", void 0);
63
+ tslib_1.__decorate([
64
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { nullable: true, description: "A card's limit for a month" }),
65
+ tslib_1.__metadata("design:type", Number)
66
+ ], NewBankAccount.prototype, "creditLimit", void 0);
50
67
  tslib_1.__decorate([
51
68
  (0, type_graphql_1.Field)({ nullable: true, description: 'An inactive account is not offered for new lines' }),
52
69
  tslib_1.__metadata("design:type", Boolean)
@@ -101,6 +118,22 @@ tslib_1.__decorate([
101
118
  (0, type_graphql_1.Field)({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' }),
102
119
  tslib_1.__metadata("design:type", String)
103
120
  ], BankAccountPatch.prototype, "statedBalanceDate", void 0);
121
+ tslib_1.__decorate([
122
+ (0, type_graphql_1.Field)(type => shell_1.ObjectRef, { nullable: true, description: "A card's holder" }),
123
+ tslib_1.__metadata("design:type", shell_1.ObjectRef)
124
+ ], BankAccountPatch.prototype, "holder", void 0);
125
+ tslib_1.__decorate([
126
+ (0, type_graphql_1.Field)(type => shell_1.ObjectRef, { nullable: true, description: "The bank account a card's bill is paid from" }),
127
+ tslib_1.__metadata("design:type", shell_1.ObjectRef)
128
+ ], BankAccountPatch.prototype, "settlementAccount", void 0);
129
+ tslib_1.__decorate([
130
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: "Day of the month a card's bill is paid - 31 for the last day" }),
131
+ tslib_1.__metadata("design:type", Number)
132
+ ], BankAccountPatch.prototype, "paymentDay", void 0);
133
+ tslib_1.__decorate([
134
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { nullable: true, description: "A card's limit for a month" }),
135
+ tslib_1.__metadata("design:type", Number)
136
+ ], BankAccountPatch.prototype, "creditLimit", void 0);
104
137
  tslib_1.__decorate([
105
138
  (0, type_graphql_1.Field)({ nullable: true, description: 'An inactive account is not offered for new lines' }),
106
139
  tslib_1.__metadata("design:type", Boolean)
@@ -1 +1 @@
1
- {"version":3,"file":"bank-account-type.js","sourceRoot":"","sources":["../../../server/service/bank-account/bank-account-type.ts"],"names":[],"mappings":";;;;AAAA,+CAA2E;AAE3E,iDAA6E;AAGtE,IAAM,cAAc,GAApB,MAAM,cAAc;CAiC1B,CAAA;AAjCY,wCAAc;AAEzB;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,2CAA2C,EAAE,CAAC;;4CACxD;AAGZ;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;;mDAClC;AAGpB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;;gDACnC;AAGjB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC;;qDACnC;AAGtB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,0BAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oCAAoC,EAAE,CAAC;;mDACzE;AAGzB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;;gDACrE;AAGjB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8CAA8C,EAAE,CAAC;;gDACtE;AAGjB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iCAAkB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;;+CACxF;AAG5B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC;;qDAC1E;AAGtB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;;yDACjE;AAG1B;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;;8CAC3E;yBAhCL,cAAc;IAD1B,IAAA,wBAAS,EAAC,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC;GACpC,cAAc,CAiC1B;AAGM,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAuC5B,CAAA;AAvCY,4CAAgB;AAE3B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;;4CACjE;AAGX;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2CAA2C,EAAE,CAAC;;8CACvE;AAGb;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;;qDAClC;AAGpB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;;kDACnC;AAGjB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC;;uDACnC;AAGtB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,0BAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oCAAoC,EAAE,CAAC;;qDACzE;AAGzB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;;kDACrE;AAGjB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8CAA8C,EAAE,CAAC;;kDACtE;AAGjB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iCAAkB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;;iDACxF;AAG5B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC;;uDAC1E;AAGtB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;;2DACjE;AAG1B;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;;gDAC3E;AAGhB;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;;gDAC7C;2BAtCJ,gBAAgB;IAD5B,IAAA,wBAAS,EAAC,EAAE,WAAW,EAAE,qEAAqE,EAAE,CAAC;GACrF,gBAAgB,CAuC5B;AAGM,IAAM,eAAe,GAArB,MAAM,eAAe;CAM3B,CAAA;AANY,0CAAe;AAE1B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,0BAAW,CAAC,EAAE,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC;;8CACvD;AAGpB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC;;8CACpD;0BALF,eAAe;IAD3B,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,yBAAyB,EAAE,CAAC;GAC1C,eAAe,CAM3B","sourcesContent":["import { ObjectType, Field, Float, InputType, Int, ID } from 'type-graphql'\n\nimport { AccountType, BankAccount, BankAccountPurpose } from './bank-account'\n\n@InputType({ description: 'A new bank account' })\nexport class NewBankAccount {\n @Field({ description: 'Name of the account, unique in the domain' })\n name: string\n\n @Field({ nullable: true, description: 'Description' })\n description?: string\n\n @Field({ nullable: true, description: 'Bank name' })\n bankName?: string\n\n @Field({ nullable: true, description: 'Account number' })\n accountNumber?: string\n\n @Field(type => AccountType, { nullable: true, description: 'Type of the account (bank or card)' })\n accountType?: AccountType\n\n @Field({ nullable: true, description: 'ISO 4217 code - the currency of the account' })\n currency?: string\n\n @Field({ nullable: true, description: 'IANA time zone the bank keeps the account in' })\n timezone?: string\n\n @Field(type => BankAccountPurpose, { nullable: true, description: 'What the money in the account may be used for' })\n purpose?: BankAccountPurpose\n\n @Field(type => Float, { nullable: true, description: 'A balance someone read off the account' })\n statedBalance?: number\n\n @Field({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' })\n statedBalanceDate?: string\n\n @Field({ nullable: true, description: 'An inactive account is not offered for new lines' })\n active?: boolean\n}\n\n@InputType({ description: 'A change to a bank account, or a grid row: cuFlag + adds, M changes' })\nexport class BankAccountPatch {\n @Field(type => ID, { nullable: true, description: 'The account to change' })\n id?: string\n\n @Field({ nullable: true, description: 'Name of the account, unique in the domain' })\n name?: string\n\n @Field({ nullable: true, description: 'Description' })\n description?: string\n\n @Field({ nullable: true, description: 'Bank name' })\n bankName?: string\n\n @Field({ nullable: true, description: 'Account number' })\n accountNumber?: string\n\n @Field(type => AccountType, { nullable: true, description: 'Type of the account (bank or card)' })\n accountType?: AccountType\n\n @Field({ nullable: true, description: 'ISO 4217 code - the currency of the account' })\n currency?: string\n\n @Field({ nullable: true, description: 'IANA time zone the bank keeps the account in' })\n timezone?: string\n\n @Field(type => BankAccountPurpose, { nullable: true, description: 'What the money in the account may be used for' })\n purpose?: BankAccountPurpose\n\n @Field(type => Float, { nullable: true, description: 'A balance someone read off the account' })\n statedBalance?: number\n\n @Field({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' })\n statedBalanceDate?: string\n\n @Field({ nullable: true, description: 'An inactive account is not offered for new lines' })\n active?: boolean\n\n @Field({ nullable: true, description: '+ adds, M changes' })\n cuFlag?: string\n}\n\n@ObjectType({ description: 'A page of bank accounts' })\nexport class BankAccountList {\n @Field(type => [BankAccount], { description: 'The accounts on this page' })\n items: BankAccount[]\n\n @Field(type => Int, { description: 'How many there are in all' })\n total: number\n}\n"]}
1
+ {"version":3,"file":"bank-account-type.js","sourceRoot":"","sources":["../../../server/service/bank-account/bank-account-type.ts"],"names":[],"mappings":"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","sourcesContent":["import { ObjectType, Field, Float, InputType, Int, ID } from 'type-graphql'\n\nimport { ObjectRef } from '@things-factory/shell'\n\nimport { AccountType, BankAccount, BankAccountPurpose } from './bank-account'\n\n@InputType({ description: 'A new bank account' })\nexport class NewBankAccount {\n @Field({ description: 'Name of the account, unique in the domain' })\n name: string\n\n @Field({ nullable: true, description: 'Description' })\n description?: string\n\n @Field({ nullable: true, description: 'Bank name' })\n bankName?: string\n\n @Field({ nullable: true, description: 'Account number' })\n accountNumber?: string\n\n @Field(type => AccountType, { nullable: true, description: 'Type of the account (bank or card)' })\n accountType?: AccountType\n\n @Field({ nullable: true, description: 'ISO 4217 code - the currency of the account' })\n currency?: string\n\n @Field({ nullable: true, description: 'IANA time zone the bank keeps the account in' })\n timezone?: string\n\n @Field(type => BankAccountPurpose, { nullable: true, description: 'What the money in the account may be used for' })\n purpose?: BankAccountPurpose\n\n @Field(type => Float, { nullable: true, description: 'A balance someone read off the account' })\n statedBalance?: number\n\n @Field({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' })\n statedBalanceDate?: string\n\n @Field(type => ObjectRef, { nullable: true, description: \"A card's holder\" })\n holder?: ObjectRef\n\n @Field(type => ObjectRef, { nullable: true, description: \"The bank account a card's bill is paid from\" })\n settlementAccount?: ObjectRef\n\n @Field(type => Int, { nullable: true, description: \"Day of the month a card's bill is paid - 31 for the last day\" })\n paymentDay?: number\n\n @Field(type => Float, { nullable: true, description: \"A card's limit for a month\" })\n creditLimit?: number\n\n @Field({ nullable: true, description: 'An inactive account is not offered for new lines' })\n active?: boolean\n}\n\n@InputType({ description: 'A change to a bank account, or a grid row: cuFlag + adds, M changes' })\nexport class BankAccountPatch {\n @Field(type => ID, { nullable: true, description: 'The account to change' })\n id?: string\n\n @Field({ nullable: true, description: 'Name of the account, unique in the domain' })\n name?: string\n\n @Field({ nullable: true, description: 'Description' })\n description?: string\n\n @Field({ nullable: true, description: 'Bank name' })\n bankName?: string\n\n @Field({ nullable: true, description: 'Account number' })\n accountNumber?: string\n\n @Field(type => AccountType, { nullable: true, description: 'Type of the account (bank or card)' })\n accountType?: AccountType\n\n @Field({ nullable: true, description: 'ISO 4217 code - the currency of the account' })\n currency?: string\n\n @Field({ nullable: true, description: 'IANA time zone the bank keeps the account in' })\n timezone?: string\n\n @Field(type => BankAccountPurpose, { nullable: true, description: 'What the money in the account may be used for' })\n purpose?: BankAccountPurpose\n\n @Field(type => Float, { nullable: true, description: 'A balance someone read off the account' })\n statedBalance?: number\n\n @Field({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' })\n statedBalanceDate?: string\n\n @Field(type => ObjectRef, { nullable: true, description: \"A card's holder\" })\n holder?: ObjectRef\n\n @Field(type => ObjectRef, { nullable: true, description: \"The bank account a card's bill is paid from\" })\n settlementAccount?: ObjectRef\n\n @Field(type => Int, { nullable: true, description: \"Day of the month a card's bill is paid - 31 for the last day\" })\n paymentDay?: number\n\n @Field(type => Float, { nullable: true, description: \"A card's limit for a month\" })\n creditLimit?: number\n\n @Field({ nullable: true, description: 'An inactive account is not offered for new lines' })\n active?: boolean\n\n @Field({ nullable: true, description: '+ adds, M changes' })\n cuFlag?: string\n}\n\n@ObjectType({ description: 'A page of bank accounts' })\nexport class BankAccountList {\n @Field(type => [BankAccount], { description: 'The accounts on this page' })\n items: BankAccount[]\n\n @Field(type => Int, { description: 'How many there are in all' })\n total: number\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { Domain } from '@things-factory/shell';
2
2
  import { User } from '@things-factory/auth-base';
3
+ import { Employee } from '@things-factory/organization';
3
4
  export declare enum AccountType {
4
5
  BANK = "BANK",
5
6
  CARD = "CARD"
@@ -24,6 +25,12 @@ export declare class BankAccount {
24
25
  purpose: BankAccountPurpose;
25
26
  statedBalance?: number;
26
27
  statedBalanceDate?: string;
28
+ holder?: Employee;
29
+ holderId?: string;
30
+ settlementAccount?: BankAccount;
31
+ settlementAccountId?: string;
32
+ paymentDay?: number;
33
+ creditLimit?: number;
27
34
  active: boolean;
28
35
  createdAt?: Date;
29
36
  updatedAt?: Date;
@@ -6,6 +6,7 @@ const typeorm_1 = require("typeorm");
6
6
  const type_graphql_1 = require("type-graphql");
7
7
  const shell_1 = require("@things-factory/shell");
8
8
  const auth_base_1 = require("@things-factory/auth-base");
9
+ const organization_1 = require("@things-factory/organization");
9
10
  var AccountType;
10
11
  (function (AccountType) {
11
12
  AccountType["BANK"] = "BANK";
@@ -107,6 +108,34 @@ tslib_1.__decorate([
107
108
  (0, type_graphql_1.Field)({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' }),
108
109
  tslib_1.__metadata("design:type", String)
109
110
  ], BankAccount.prototype, "statedBalanceDate", void 0);
111
+ tslib_1.__decorate([
112
+ (0, typeorm_1.ManyToOne)(type => organization_1.Employee, { nullable: true }),
113
+ (0, type_graphql_1.Field)(type => organization_1.Employee, { nullable: true, description: "A card's holder - who spends with it; empty for a card the office shares" }),
114
+ tslib_1.__metadata("design:type", organization_1.Employee)
115
+ ], BankAccount.prototype, "holder", void 0);
116
+ tslib_1.__decorate([
117
+ (0, typeorm_1.RelationId)((bankAccount) => bankAccount.holder),
118
+ tslib_1.__metadata("design:type", String)
119
+ ], BankAccount.prototype, "holderId", void 0);
120
+ tslib_1.__decorate([
121
+ (0, typeorm_1.ManyToOne)(type => BankAccount, { nullable: true }),
122
+ (0, type_graphql_1.Field)(type => BankAccount, { nullable: true, description: "The bank account a card's bill is paid from" }),
123
+ tslib_1.__metadata("design:type", BankAccount)
124
+ ], BankAccount.prototype, "settlementAccount", void 0);
125
+ tslib_1.__decorate([
126
+ (0, typeorm_1.RelationId)((bankAccount) => bankAccount.settlementAccount),
127
+ tslib_1.__metadata("design:type", String)
128
+ ], BankAccount.prototype, "settlementAccountId", void 0);
129
+ tslib_1.__decorate([
130
+ (0, typeorm_1.Column)({ type: 'int', nullable: true }),
131
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: "Day of the month a card's bill is paid - 31 for the last day" }),
132
+ tslib_1.__metadata("design:type", Number)
133
+ ], BankAccount.prototype, "paymentDay", void 0);
134
+ tslib_1.__decorate([
135
+ (0, typeorm_1.Column)((0, shell_1.moneyColumn)({ nullable: true, default: null })),
136
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { nullable: true, description: "A card's limit for a month" }),
137
+ tslib_1.__metadata("design:type", Number)
138
+ ], BankAccount.prototype, "creditLimit", void 0);
110
139
  tslib_1.__decorate([
111
140
  (0, typeorm_1.Column)({ default: true }),
112
141
  (0, type_graphql_1.Field)({ description: 'An inactive account stays on old lines but is not offered for new ones' }),
@@ -1 +1 @@
1
- {"version":3,"file":"bank-account.js","sourceRoot":"","sources":["../../../server/service/bank-account/bank-account.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CreateDateColumn,\n UpdateDateColumn,\n DeleteDateColumn,\n Entity,\n Index,\n Column,\n RelationId,\n ManyToOne,\n VersionColumn,\n PrimaryGeneratedColumn\n} from 'typeorm'\nimport { Directive, ObjectType, Field, Float, ID, registerEnumType } from 'type-graphql'\n\nimport { Domain, moneyColumn } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\nexport enum AccountType {\n BANK = 'BANK',\n CARD = 'CARD'\n}\n\nregisterEnumType(AccountType, {\n name: 'AccountType',\n description: 'Type of the account (bank or card)'\n})\n\nexport enum BankAccountPurpose {\n OPERATING = 'OPERATING',\n RESTRICTED = 'RESTRICTED',\n CASH = 'CASH'\n}\n\nregisterEnumType(BankAccountPurpose, {\n name: 'BankAccountPurpose',\n description:\n 'What the money in an account may be used for - running the business, held for one purpose, cash kept on hand'\n})\n\n@Entity()\n@Index('ix_bank_account_0', (bankAccount: BankAccount) => [bankAccount.domain, bankAccount.name], {\n where: '\"deleted_at\" IS NULL',\n unique: true\n})\n@ObjectType({ description: 'An account of the business at a bank or card company, or cash it keeps' })\nexport class BankAccount {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @VersionColumn()\n @Field({ nullable: true })\n version?: number = 1\n\n @ManyToOne(type => Domain)\n @Field({ nullable: true })\n domain?: Domain\n\n @RelationId((bankAccount: BankAccount) => bankAccount.domain)\n domainId?: string\n\n @Column()\n @Field({ description: 'Name of the account, unique in the domain' })\n name: string\n\n @Column({ type: 'text', nullable: true })\n @Field({ nullable: true, description: 'Description' })\n description?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Bank name' })\n bankName?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Account number' })\n accountNumber?: string\n\n @Column({ default: AccountType.BANK })\n @Field(type => AccountType, { description: 'Type of the account (bank or card)' })\n accountType: AccountType\n\n @Column({ default: 'KRW' })\n @Field({ description: 'ISO 4217 code - the currency of the account' })\n currency: string\n\n @Column({ default: 'Asia/Seoul' })\n @Field({ description: 'IANA time zone the bank keeps the account in - the day of a bank line is its day there' })\n timezone: string\n\n @Column({ default: BankAccountPurpose.OPERATING })\n @Field(type => BankAccountPurpose, { description: 'What the money in the account may be used for' })\n purpose: BankAccountPurpose\n\n @Column(moneyColumn({ nullable: true, default: null }))\n @Directive('@privilege(category: \"bank\", privilege: \"query\", domainOwnerGranted: false)')\n /* The balance is a bank fact (ADR-0139), as the account itself is - its doors are `bank`. */\n @Field(type => Float, {\n nullable: true,\n description:\n 'A balance someone read off the account, for an account with no bank lines (a pension, cash in the safe)'\n })\n statedBalance?: number\n\n @Column({ nullable: true })\n @Directive('@privilege(category: \"bank\", privilege: \"query\", domainOwnerGranted: false)')\n @Field({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' })\n statedBalanceDate?: string\n\n @Column({ default: true })\n @Field({ description: 'An inactive account stays on old lines but is not offered for new ones' })\n active: boolean\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((bankAccount: BankAccount) => bankAccount.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((bankAccount: BankAccount) => bankAccount.updater)\n updaterId?: string\n}\n"]}
1
+ {"version":3,"file":"bank-account.js","sourceRoot":"","sources":["../../../server/service/bank-account/bank-account.ts"],"names":[],"mappings":";;;;AAAA,qCAWgB;AAChB,+CAA6F;AAE7F,iDAA2D;AAC3D,yDAAgD;AAChD,+DAAuD;AAEvD,IAAY,WAGX;AAHD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,4BAAa,CAAA;AACf,CAAC,EAHW,WAAW,2BAAX,WAAW,QAGtB;AAED,IAAA,+BAAgB,EAAC,WAAW,EAAE;IAC5B,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,oCAAoC;CAClD,CAAC,CAAA;AAEF,IAAY,kBAIX;AAJD,WAAY,kBAAkB;IAC5B,6CAAuB,CAAA;IACvB,+CAAyB,CAAA;IACzB,mCAAa,CAAA;AACf,CAAC,EAJW,kBAAkB,kCAAlB,kBAAkB,QAI7B;AAED,IAAA,+BAAgB,EAAC,kBAAkB,EAAE;IACnC,IAAI,EAAE,oBAAoB;IAC1B,WAAW,EACT,8GAA8G;CACjH,CAAC,CAAA;AAQK,IAAM,WAAW,GAAjB,MAAM,WAAW;IAAjB;QAOL,YAAO,GAAY,CAAC,CAAA;IA4GtB,CAAC;CAAA,CAAA;AAnHY,kCAAW;AAGb;IAFR,IAAA,gCAAsB,EAAC,MAAM,CAAC;IAC9B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,CAAC;;uCACC;AAInB;IAFC,IAAA,uBAAa,GAAE;IACf,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;4CACN;AAIpB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;IACzB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACjB,cAAM;2CAAA;AAGf;IADC,IAAA,oBAAU,EAAC,CAAC,WAAwB,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC;;6CAC5C;AAIjB;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,2CAA2C,EAAE,CAAC;;yCACxD;AAIZ;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;;gDAClC;AAIpB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;;6CACnC;AAIjB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC;;kDACnC;AAItB;IAFC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;IACrC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,oCAAoC,EAAE,CAAC;;gDAC1D;AAIxB;IAFC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;;6CACtD;AAIhB;IAFC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IACjC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,wFAAwF,EAAE,CAAC;;6CACjG;AAIhB;IAFC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,kBAAkB,CAAC,SAAS,EAAE,CAAC;IACjD,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAkB,EAAE,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;;4CACzE;AAU3B;IARC,IAAA,gBAAM,EAAC,IAAA,mBAAW,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,IAAA,wBAAS,EAAC,6EAA6E,CAAC;IACzF,6FAA6F;;IAC5F,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAK,EAAE;QACpB,QAAQ,EAAE,IAAI;QACd,WAAW,EACT,yGAAyG;KAC5G,CAAC;;kDACoB;AAKtB;IAHC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,wBAAS,EAAC,6EAA6E,CAAC;IACxF,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;;sDACjE;AAK1B;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,uBAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,uBAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0EAA0E,EAAE,CAAC;sCAC5H,uBAAQ;2CAAA;AAGjB;IADC,IAAA,oBAAU,EAAC,CAAC,WAAwB,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC;;6CAC5C;AAIjB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAClD,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6CAA6C,EAAE,CAAC;sCACvF,WAAW;sDAAA;AAG/B;IADC,IAAA,oBAAU,EAAC,CAAC,WAAwB,EAAE,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC;;wDAC5C;AAI5B;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;+CACjG;AAInB;IAFC,IAAA,gBAAM,EAAC,IAAA,mBAAW,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;;gDAChE;AAIpB;IAFC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACzB,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,wEAAwE,EAAE,CAAC;;2CAClF;AAIf;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACd,IAAI;8CAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACd,IAAI;8CAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCACd,IAAI;8CAAA;AAIhB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCAC9B,gBAAI;4CAAA;AAGd;IADC,IAAA,oBAAU,EAAC,CAAC,WAAwB,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC;;8CAC5C;AAIlB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,gBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;sCAC9B,gBAAI;4CAAA;AAGd;IADC,IAAA,oBAAU,EAAC,CAAC,WAAwB,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC;;8CAC5C;sBAlHP,WAAW;IANvB,IAAA,gBAAM,GAAE;IACR,IAAA,eAAK,EAAC,mBAAmB,EAAE,CAAC,WAAwB,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;QAChG,KAAK,EAAE,sBAAsB;QAC7B,MAAM,EAAE,IAAI;KACb,CAAC;IACD,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,wEAAwE,EAAE,CAAC;GACzF,WAAW,CAmHvB","sourcesContent":["import {\n CreateDateColumn,\n UpdateDateColumn,\n DeleteDateColumn,\n Entity,\n Index,\n Column,\n RelationId,\n ManyToOne,\n VersionColumn,\n PrimaryGeneratedColumn\n} from 'typeorm'\nimport { Directive, ObjectType, Field, Float, ID, Int, registerEnumType } from 'type-graphql'\n\nimport { Domain, moneyColumn } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { Employee } from '@things-factory/organization'\n\nexport enum AccountType {\n BANK = 'BANK',\n CARD = 'CARD'\n}\n\nregisterEnumType(AccountType, {\n name: 'AccountType',\n description: 'Type of the account (bank or card)'\n})\n\nexport enum BankAccountPurpose {\n OPERATING = 'OPERATING',\n RESTRICTED = 'RESTRICTED',\n CASH = 'CASH'\n}\n\nregisterEnumType(BankAccountPurpose, {\n name: 'BankAccountPurpose',\n description:\n 'What the money in an account may be used for - running the business, held for one purpose, cash kept on hand'\n})\n\n@Entity()\n@Index('ix_bank_account_0', (bankAccount: BankAccount) => [bankAccount.domain, bankAccount.name], {\n where: '\"deleted_at\" IS NULL',\n unique: true\n})\n@ObjectType({ description: 'An account of the business at a bank or card company, or cash it keeps' })\nexport class BankAccount {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @VersionColumn()\n @Field({ nullable: true })\n version?: number = 1\n\n @ManyToOne(type => Domain)\n @Field({ nullable: true })\n domain?: Domain\n\n @RelationId((bankAccount: BankAccount) => bankAccount.domain)\n domainId?: string\n\n @Column()\n @Field({ description: 'Name of the account, unique in the domain' })\n name: string\n\n @Column({ type: 'text', nullable: true })\n @Field({ nullable: true, description: 'Description' })\n description?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Bank name' })\n bankName?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Account number' })\n accountNumber?: string\n\n @Column({ default: AccountType.BANK })\n @Field(type => AccountType, { description: 'Type of the account (bank or card)' })\n accountType: AccountType\n\n @Column({ default: 'KRW' })\n @Field({ description: 'ISO 4217 code - the currency of the account' })\n currency: string\n\n @Column({ default: 'Asia/Seoul' })\n @Field({ description: 'IANA time zone the bank keeps the account in - the day of a bank line is its day there' })\n timezone: string\n\n @Column({ default: BankAccountPurpose.OPERATING })\n @Field(type => BankAccountPurpose, { description: 'What the money in the account may be used for' })\n purpose: BankAccountPurpose\n\n @Column(moneyColumn({ nullable: true, default: null }))\n @Directive('@privilege(category: \"bank\", privilege: \"query\", domainOwnerGranted: false)')\n /* The balance is a bank fact (ADR-0139), as the account itself is - its doors are `bank`. */\n @Field(type => Float, {\n nullable: true,\n description:\n 'A balance someone read off the account, for an account with no bank lines (a pension, cash in the safe)'\n })\n statedBalance?: number\n\n @Column({ nullable: true })\n @Directive('@privilege(category: \"bank\", privilege: \"query\", domainOwnerGranted: false)')\n @Field({ nullable: true, description: 'YYYY-MM-DD - the day the stated balance was read' })\n statedBalanceDate?: string\n\n /* A card's own facts (ADR-0178 결정 2) - empty on a bank account. */\n @ManyToOne(type => Employee, { nullable: true })\n @Field(type => Employee, { nullable: true, description: \"A card's holder - who spends with it; empty for a card the office shares\" })\n holder?: Employee\n\n @RelationId((bankAccount: BankAccount) => bankAccount.holder)\n holderId?: string\n\n @ManyToOne(type => BankAccount, { nullable: true })\n @Field(type => BankAccount, { nullable: true, description: \"The bank account a card's bill is paid from\" })\n settlementAccount?: BankAccount\n\n @RelationId((bankAccount: BankAccount) => bankAccount.settlementAccount)\n settlementAccountId?: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: \"Day of the month a card's bill is paid - 31 for the last day\" })\n paymentDay?: number\n\n @Column(moneyColumn({ nullable: true, default: null }))\n @Field(type => Float, { nullable: true, description: \"A card's limit for a month\" })\n creditLimit?: number\n\n @Column({ default: true })\n @Field({ description: 'An inactive account stays on old lines but is not offered for new ones' })\n active: boolean\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true })\n deletedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((bankAccount: BankAccount) => bankAccount.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((bankAccount: BankAccount) => bankAccount.updater)\n updaterId?: string\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import { ListParam } from '@things-factory/shell';
2
+ import { ExpenditureRequestItem } from '../expenditure-request/expenditure-request-item';
3
+ import { Transaction } from '../transaction/transaction';
4
+ import { TransactionList } from '../transaction/transaction-type';
5
+ export declare class CardMonthSummary {
6
+ spent: number;
7
+ refunded: number;
8
+ billed: number;
9
+ outstanding: number;
10
+ unexplained: number;
11
+ personalUse: number;
12
+ creditLimit?: number;
13
+ }
14
+ /** The lines that explain charges, by charge - a line of a deleted request explains nothing. */
15
+ export declare function explanationsOf(domain: {
16
+ id: string;
17
+ }, chargeIds: string[]): Promise<ExpenditureRequestItem[]>;
18
+ export declare class CardQuery {
19
+ /** The charges on the corporate cards - the card's own list, apart from the bank lines (ADR-0178 결정 6). */
20
+ cardCharges(params: ListParam, context: ResolverContext): Promise<TransactionList>;
21
+ cardMonth(cardId: string, month: string, context: ResolverContext): Promise<CardMonthSummary>;
22
+ /** The expenditure line that explains a card charge - empty for a bank line or a charge nobody explained yet. */
23
+ explainedBy(line: Transaction, context: ResolverContext): Promise<ExpenditureRequestItem | null>;
24
+ }
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CardQuery = exports.CardMonthSummary = void 0;
4
+ exports.explanationsOf = explanationsOf;
5
+ const tslib_1 = require("tslib");
6
+ const type_graphql_1 = require("type-graphql");
7
+ const typeorm_1 = require("typeorm");
8
+ const shell_1 = require("@things-factory/shell");
9
+ const expenditure_request_item_1 = require("../expenditure-request/expenditure-request-item");
10
+ const expenditure_request_rules_1 = require("../expenditure-request/expenditure-request-rules");
11
+ const card_bill_target_1 = require("../payment/card-bill-target");
12
+ const payment_1 = require("../payment/payment");
13
+ const transaction_1 = require("../transaction/transaction");
14
+ const transaction_query_1 = require("../transaction/transaction-query");
15
+ const transaction_type_1 = require("../transaction/transaction-type");
16
+ const bank_account_1 = require("./bank-account");
17
+ const card_summary_1 = require("./card-summary");
18
+ let CardMonthSummary = class CardMonthSummary {
19
+ };
20
+ exports.CardMonthSummary = CardMonthSummary;
21
+ tslib_1.__decorate([
22
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { description: 'Charged in the month' }),
23
+ tslib_1.__metadata("design:type", Number)
24
+ ], CardMonthSummary.prototype, "spent", void 0);
25
+ tslib_1.__decorate([
26
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { description: 'Refunded in the month' }),
27
+ tslib_1.__metadata("design:type", Number)
28
+ ], CardMonthSummary.prototype, "refunded", void 0);
29
+ tslib_1.__decorate([
30
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { description: "The card's bills paid in the month" }),
31
+ tslib_1.__metadata("design:type", Number)
32
+ ], CardMonthSummary.prototype, "billed", void 0);
33
+ tslib_1.__decorate([
34
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { description: 'What the card still owes when the month ends' }),
35
+ tslib_1.__metadata("design:type", Number)
36
+ ], CardMonthSummary.prototype, "outstanding", void 0);
37
+ tslib_1.__decorate([
38
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Charges of the month no line explains yet' }),
39
+ tslib_1.__metadata("design:type", Number)
40
+ ], CardMonthSummary.prototype, "unexplained", void 0);
41
+ tslib_1.__decorate([
42
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { description: 'Spent for oneself in the month - owed back by the holder' }),
43
+ tslib_1.__metadata("design:type", Number)
44
+ ], CardMonthSummary.prototype, "personalUse", void 0);
45
+ tslib_1.__decorate([
46
+ (0, type_graphql_1.Field)(type => type_graphql_1.Float, { nullable: true, description: "The card's limit for a month" }),
47
+ tslib_1.__metadata("design:type", Number)
48
+ ], CardMonthSummary.prototype, "creditLimit", void 0);
49
+ exports.CardMonthSummary = CardMonthSummary = tslib_1.__decorate([
50
+ (0, type_graphql_1.ObjectType)({ description: "A corporate card's month - charged, taken back, billed, and still owed (ADR-0178)" })
51
+ ], CardMonthSummary);
52
+ /** The lines that explain charges, by charge - a line of a deleted request explains nothing. */
53
+ async function explanationsOf(domain, chargeIds) {
54
+ if (!chargeIds.length)
55
+ return [];
56
+ const items = await (0, shell_1.getRepository)(expenditure_request_item_1.ExpenditureRequestItem).find({
57
+ where: { domain: { id: domain.id }, cardTransaction: { id: (0, typeorm_1.In)(chargeIds) } },
58
+ relations: ['request']
59
+ });
60
+ return items.filter(item => item.request && !item.request.deletedAt);
61
+ }
62
+ let CardQuery = class CardQuery {
63
+ /** The charges on the corporate cards - the card's own list, apart from the bank lines (ADR-0178 결정 6). */
64
+ async cardCharges(params, context) {
65
+ const { domain } = context.state;
66
+ /* The bank lines' list (`transactions`), held to the cards' charges - the same words searched, the same order. */
67
+ const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
68
+ domain,
69
+ params,
70
+ repository: await (0, shell_1.getRepository)(transaction_1.Transaction),
71
+ searchables: ['description', 'counterpartyName', 'counterparty', 'ledgerCategory', 'bankDescription', 'bankCounterpartyName', 'bankMemo', 'notes'],
72
+ alias: 'transaction'
73
+ });
74
+ queryBuilder.andWhere('transaction.category = :category', { category: transaction_1.TransactionCategory.CARD });
75
+ for (const field of transaction_query_1.BOOK_ORDER)
76
+ if (!params.sortings?.some(sorting => sorting.name === field))
77
+ queryBuilder.addOrderBy(`transaction.${field}`, 'DESC');
78
+ const [items, total] = await queryBuilder.getManyAndCount();
79
+ return { items, total };
80
+ }
81
+ async cardMonth(cardId, month, context) {
82
+ const { domain } = context.state;
83
+ if (!(0, expenditure_request_rules_1.monthOf)(month))
84
+ throw new shell_1.Refusal('card-month-invalid', { value: month }, `month: '${month}' is not a month (use YYYY-MM)`);
85
+ const card = await (0, shell_1.getRepository)(bank_account_1.BankAccount).findOne({ where: { domain: { id: domain.id }, id: cardId, accountType: bank_account_1.AccountType.CARD } });
86
+ if (!card)
87
+ throw new shell_1.Refusal('card-not-found', {}, 'the card was not found - reload and try again');
88
+ const lines = await (0, shell_1.getRepository)(transaction_1.Transaction).find({ where: { domain: { id: domain.id }, bankAccount: { id: card.id }, category: transaction_1.TransactionCategory.CARD } });
89
+ const payments = await (0, shell_1.getRepository)(payment_1.Payment).find({
90
+ where: { domain: { id: domain.id }, targetType: card_bill_target_1.CARD_BILL_TARGET, targetId: card.id },
91
+ relations: ['transaction']
92
+ });
93
+ const explained = new Map((await explanationsOf(domain, lines.filter(one => one.transactionDate?.slice(0, 7) === month).map(one => one.id))).map(item => [
94
+ item.cardTransactionId,
95
+ { personalUse: !!item.personalUse }
96
+ ]));
97
+ const summary = (0, card_summary_1.cardMonth)(month, lines, payments.filter(one => one.transaction && !one.transaction.deletedAt).map(one => ({ transactionDate: one.transaction.transactionDate, amount: Number(one.amount) })), explained);
98
+ return { ...summary, creditLimit: card.creditLimit ?? undefined };
99
+ }
100
+ /** The expenditure line that explains a card charge - empty for a bank line or a charge nobody explained yet. */
101
+ async explainedBy(line, context) {
102
+ if (line.category !== transaction_1.TransactionCategory.CARD)
103
+ return null;
104
+ const [item] = await explanationsOf(context.state.domain, [line.id]);
105
+ return item ?? null;
106
+ }
107
+ };
108
+ exports.CardQuery = CardQuery;
109
+ tslib_1.__decorate([
110
+ (0, type_graphql_1.Directive)('@privilege(category: "bank", privilege: "query", domainOwnerGranted: false)'),
111
+ (0, type_graphql_1.Query)(returns => transaction_type_1.TransactionList, { description: 'Charges on the corporate cards, newest first' }),
112
+ tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
113
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
114
+ tslib_1.__metadata("design:type", Function),
115
+ tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
116
+ tslib_1.__metadata("design:returntype", Promise)
117
+ ], CardQuery.prototype, "cardCharges", null);
118
+ tslib_1.__decorate([
119
+ (0, type_graphql_1.Directive)('@privilege(category: "bank", privilege: "query", domainOwnerGranted: false)'),
120
+ (0, type_graphql_1.Query)(returns => CardMonthSummary, { description: "A corporate card's month - charged, refunded, billed, still owed" }),
121
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('card')),
122
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('month')),
123
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
124
+ tslib_1.__metadata("design:type", Function),
125
+ tslib_1.__metadata("design:paramtypes", [String, String, Object]),
126
+ tslib_1.__metadata("design:returntype", Promise)
127
+ ], CardQuery.prototype, "cardMonth", null);
128
+ tslib_1.__decorate([
129
+ (0, type_graphql_1.FieldResolver)(type => expenditure_request_item_1.ExpenditureRequestItem, { nullable: true, description: 'The expenditure line that explains this card charge' }),
130
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
131
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
132
+ tslib_1.__metadata("design:type", Function),
133
+ tslib_1.__metadata("design:paramtypes", [transaction_1.Transaction, Object]),
134
+ tslib_1.__metadata("design:returntype", Promise)
135
+ ], CardQuery.prototype, "explainedBy", null);
136
+ exports.CardQuery = CardQuery = tslib_1.__decorate([
137
+ (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
138
+ (0, type_graphql_1.Resolver)(transaction_1.Transaction)
139
+ ], CardQuery);
140
+ //# sourceMappingURL=card-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-query.js","sourceRoot":"","sources":["../../../server/service/bank-account/card-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, Field, Float, FieldResolver, Int, ObjectType, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { getQueryBuilderFromListParams, getRepository, ListParam, Refusal, SpeakRefusals } from '@things-factory/shell'\n\nimport { ExpenditureRequestItem } from '../expenditure-request/expenditure-request-item'\nimport { monthOf } from '../expenditure-request/expenditure-request-rules'\nimport { CARD_BILL_TARGET } from '../payment/card-bill-target'\nimport { Payment } from '../payment/payment'\nimport { Transaction, TransactionCategory } from '../transaction/transaction'\nimport { BOOK_ORDER } from '../transaction/transaction-query'\nimport { TransactionList } from '../transaction/transaction-type'\nimport { AccountType, BankAccount } from './bank-account'\nimport { cardMonth } from './card-summary'\n\n@ObjectType({ description: \"A corporate card's month - charged, taken back, billed, and still owed (ADR-0178)\" })\nexport class CardMonthSummary {\n @Field(type => Float, { description: 'Charged in the month' })\n spent: number\n\n @Field(type => Float, { description: 'Refunded in the month' })\n refunded: number\n\n @Field(type => Float, { description: \"The card's bills paid in the month\" })\n billed: number\n\n @Field(type => Float, { description: 'What the card still owes when the month ends' })\n outstanding: number\n\n @Field(type => Int, { description: 'Charges of the month no line explains yet' })\n unexplained: number\n\n @Field(type => Float, { description: 'Spent for oneself in the month - owed back by the holder' })\n personalUse: number\n\n @Field(type => Float, { nullable: true, description: \"The card's limit for a month\" })\n creditLimit?: number\n}\n\n/** The lines that explain charges, by charge - a line of a deleted request explains nothing. */\nexport async function explanationsOf(domain: { id: string }, chargeIds: string[]): Promise<ExpenditureRequestItem[]> {\n if (!chargeIds.length) return []\n const items = await getRepository(ExpenditureRequestItem).find({\n where: { domain: { id: domain.id }, cardTransaction: { id: In(chargeIds) } } as any,\n relations: ['request']\n })\n return items.filter(item => item.request && !item.request.deletedAt)\n}\n\n@UseMiddleware(SpeakRefusals)\n@Resolver(Transaction)\nexport class CardQuery {\n /** The charges on the corporate cards - the card's own list, apart from the bank lines (ADR-0178 결정 6). */\n @Directive('@privilege(category: \"bank\", privilege: \"query\", domainOwnerGranted: false)')\n @Query(returns => TransactionList, { description: 'Charges on the corporate cards, newest first' })\n async cardCharges(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<TransactionList> {\n const { domain } = context.state\n\n /* The bank lines' list (`transactions`), held to the cards' charges - the same words searched, the same order. */\n const queryBuilder = getQueryBuilderFromListParams({\n domain,\n params,\n repository: await getRepository(Transaction),\n searchables: ['description', 'counterpartyName', 'counterparty', 'ledgerCategory', 'bankDescription', 'bankCounterpartyName', 'bankMemo', 'notes'],\n alias: 'transaction'\n })\n queryBuilder.andWhere('transaction.category = :category', { category: TransactionCategory.CARD })\n for (const field of BOOK_ORDER)\n if (!params.sortings?.some(sorting => sorting.name === field)) queryBuilder.addOrderBy(`transaction.${field}`, 'DESC')\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Directive('@privilege(category: \"bank\", privilege: \"query\", domainOwnerGranted: false)')\n @Query(returns => CardMonthSummary, { description: \"A corporate card's month - charged, refunded, billed, still owed\" })\n async cardMonth(@Arg('card') cardId: string, @Arg('month') month: string, @Ctx() context: ResolverContext): Promise<CardMonthSummary> {\n const { domain } = context.state\n if (!monthOf(month)) throw new Refusal('card-month-invalid', { value: month }, `month: '${month}' is not a month (use YYYY-MM)`)\n const card = await getRepository(BankAccount).findOne({ where: { domain: { id: domain.id }, id: cardId, accountType: AccountType.CARD } as any })\n if (!card) throw new Refusal('card-not-found', {}, 'the card was not found - reload and try again')\n\n const lines = await getRepository(Transaction).find({ where: { domain: { id: domain.id }, bankAccount: { id: card.id }, category: TransactionCategory.CARD } as any })\n const payments = await getRepository(Payment).find({\n where: { domain: { id: domain.id }, targetType: CARD_BILL_TARGET, targetId: card.id } as any,\n relations: ['transaction']\n })\n const explained = new Map(\n (await explanationsOf(domain, lines.filter(one => one.transactionDate?.slice(0, 7) === month).map(one => one.id))).map(item => [\n item.cardTransactionId!,\n { personalUse: !!item.personalUse }\n ])\n )\n const summary = cardMonth(\n month,\n lines,\n payments.filter(one => one.transaction && !one.transaction.deletedAt).map(one => ({ transactionDate: one.transaction.transactionDate, amount: Number(one.amount) })),\n explained\n )\n return { ...summary, creditLimit: card.creditLimit ?? undefined }\n }\n\n /** The expenditure line that explains a card charge - empty for a bank line or a charge nobody explained yet. */\n @FieldResolver(type => ExpenditureRequestItem, { nullable: true, description: 'The expenditure line that explains this card charge' })\n async explainedBy(@Root() line: Transaction, @Ctx() context: ResolverContext): Promise<ExpenditureRequestItem | null> {\n if (line.category !== TransactionCategory.CARD) return null\n const [item] = await explanationsOf(context.state.domain, [line.id])\n return item ?? null\n }\n}\n"]}
@@ -0,0 +1,21 @@
1
+ /** The facts only a card has (ADR-0178 결정 2). */
2
+ export declare const CARD_FIELDS: readonly ["holder", "settlementAccount", "paymentDay", "creditLimit"];
3
+ /** An account as it will be once a patch is written - a relation is its id or a `{ id }`. */
4
+ export interface AccountShape {
5
+ id?: string;
6
+ accountType?: string | null;
7
+ accountNumber?: string | null;
8
+ holder?: {
9
+ id?: string;
10
+ } | string | null;
11
+ settlementAccount?: {
12
+ id?: string;
13
+ } | string | null;
14
+ paymentDay?: number | null;
15
+ creditLimit?: number | null;
16
+ }
17
+ /**
18
+ * What a card account may hold, read off the account alone. A card keeps only the last four digits of its number - the
19
+ * full number is never written; a bank account has none of a card's facts. Pure.
20
+ */
21
+ export declare function checkCardFields(account: AccountShape): void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CARD_FIELDS = void 0;
4
+ exports.checkCardFields = checkCardFields;
5
+ const shell_1 = require("@things-factory/shell");
6
+ /** The facts only a card has (ADR-0178 결정 2). */
7
+ exports.CARD_FIELDS = ['holder', 'settlementAccount', 'paymentDay', 'creditLimit'];
8
+ const given = (value) => value !== undefined && value !== null && value !== '' && !(typeof value === 'object' && !value.id);
9
+ const idOf = (value) => (typeof value === 'string' ? value : value?.id);
10
+ /**
11
+ * What a card account may hold, read off the account alone. A card keeps only the last four digits of its number - the
12
+ * full number is never written; a bank account has none of a card's facts. Pure.
13
+ */
14
+ function checkCardFields(account) {
15
+ if (account.accountType === 'CARD') {
16
+ if (given(account.accountNumber) && !/^\d{4}$/.test(String(account.accountNumber).trim()))
17
+ throw new shell_1.Refusal('card-number-last-four', {}, 'accountNumber: a card keeps only the last four digits of its number');
18
+ if (given(account.paymentDay) && !(Number.isInteger(Number(account.paymentDay)) && Number(account.paymentDay) >= 1 && Number(account.paymentDay) <= 31))
19
+ throw new shell_1.Refusal('card-payment-day', {}, 'paymentDay: a day of the month, 1 to 31');
20
+ if (given(account.creditLimit) && !(Number(account.creditLimit) >= 0))
21
+ throw new shell_1.Refusal('card-credit-limit', {}, 'creditLimit: zero or more');
22
+ if (account.id && idOf(account.settlementAccount) === account.id)
23
+ throw new shell_1.Refusal('card-settles-itself', {}, 'settlementAccount: a card is paid from a bank account, not from itself');
24
+ return;
25
+ }
26
+ const field = exports.CARD_FIELDS.find(one => given(account[one]));
27
+ if (field)
28
+ throw new shell_1.Refusal('card-fields-on-bank-account', { field }, `${field}: only a card has it`);
29
+ }
30
+ //# sourceMappingURL=card-rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-rules.js","sourceRoot":"","sources":["../../../server/service/bank-account/card-rules.ts"],"names":[],"mappings":";;;AAuBA,0CAcC;AArCD,iDAA+C;AAE/C,iDAAiD;AACpC,QAAA,WAAW,GAAG,CAAC,QAAQ,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,CAAU,CAAA;AAahG,MAAM,KAAK,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAE,KAAa,CAAC,EAAE,CAAC,CAAA;AAC7I,MAAM,IAAI,GAAG,CAAC,KAA6B,EAAE,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAE/F;;;GAGG;AACH,SAAgB,eAAe,CAAC,OAAqB;IACnD,IAAI,OAAO,CAAC,WAAW,KAAK,MAAM,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC;YACvF,MAAM,IAAI,eAAO,CAAC,uBAAuB,EAAE,EAAE,EAAE,qEAAqE,CAAC,CAAA;QACvH,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YACrJ,MAAM,IAAI,eAAO,CAAC,kBAAkB,EAAE,EAAE,EAAE,yCAAyC,CAAC,CAAA;QACtF,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACnE,MAAM,IAAI,eAAO,CAAC,mBAAmB,EAAE,EAAE,EAAE,2BAA2B,CAAC,CAAA;QACzE,IAAI,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,OAAO,CAAC,EAAE;YAC9D,MAAM,IAAI,eAAO,CAAC,qBAAqB,EAAE,EAAE,EAAE,wEAAwE,CAAC,CAAA;QACxH,OAAM;IACR,CAAC;IACD,MAAM,KAAK,GAAG,mBAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAC1D,IAAI,KAAK;QAAE,MAAM,IAAI,eAAO,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,sBAAsB,CAAC,CAAA;AACxG,CAAC","sourcesContent":["import { Refusal } from '@things-factory/shell'\n\n/** The facts only a card has (ADR-0178 결정 2). */\nexport const CARD_FIELDS = ['holder', 'settlementAccount', 'paymentDay', 'creditLimit'] as const\n\n/** An account as it will be once a patch is written - a relation is its id or a `{ id }`. */\nexport interface AccountShape {\n id?: string\n accountType?: string | null\n accountNumber?: string | null\n holder?: { id?: string } | string | null\n settlementAccount?: { id?: string } | string | null\n paymentDay?: number | null\n creditLimit?: number | null\n}\n\nconst given = (value: unknown) => value !== undefined && value !== null && value !== '' && !(typeof value === 'object' && !(value as any).id)\nconst idOf = (value: AccountShape['holder']) => (typeof value === 'string' ? value : value?.id)\n\n/**\n * What a card account may hold, read off the account alone. A card keeps only the last four digits of its number - the\n * full number is never written; a bank account has none of a card's facts. Pure.\n */\nexport function checkCardFields(account: AccountShape): void {\n if (account.accountType === 'CARD') {\n if (given(account.accountNumber) && !/^\\d{4}$/.test(String(account.accountNumber).trim()))\n throw new Refusal('card-number-last-four', {}, 'accountNumber: a card keeps only the last four digits of its number')\n if (given(account.paymentDay) && !(Number.isInteger(Number(account.paymentDay)) && Number(account.paymentDay) >= 1 && Number(account.paymentDay) <= 31))\n throw new Refusal('card-payment-day', {}, 'paymentDay: a day of the month, 1 to 31')\n if (given(account.creditLimit) && !(Number(account.creditLimit) >= 0))\n throw new Refusal('card-credit-limit', {}, 'creditLimit: zero or more')\n if (account.id && idOf(account.settlementAccount) === account.id)\n throw new Refusal('card-settles-itself', {}, 'settlementAccount: a card is paid from a bank account, not from itself')\n return\n }\n const field = CARD_FIELDS.find(one => given(account[one]))\n if (field) throw new Refusal('card-fields-on-bank-account', { field }, `${field}: only a card has it`)\n}\n"]}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * A corporate card's month (ADR-0178 결정 4 · 6): what was charged, what was taken back, what its bills paid, and what
3
+ * the card still owes when the month ends - its charges less its refunds less its bills, from the first line on. How
4
+ * many charges no line explains yet, and how much was spent for oneself.
5
+ *
6
+ * Pure.
7
+ */
8
+ export interface CardLine {
9
+ id: string;
10
+ transactionDate?: string | null;
11
+ type: string;
12
+ amount: number;
13
+ }
14
+ export interface CardBill {
15
+ transactionDate?: string | null;
16
+ amount: number;
17
+ }
18
+ export interface CardMonth {
19
+ spent: number;
20
+ refunded: number;
21
+ billed: number;
22
+ outstanding: number;
23
+ unexplained: number;
24
+ personalUse: number;
25
+ }
26
+ /** `month` is YYYY-MM; `explained` is each explained charge's id and whether it was personal use. */
27
+ export declare function cardMonth(month: string, lines: readonly CardLine[], bills: readonly CardBill[], explained: ReadonlyMap<string, {
28
+ personalUse: boolean;
29
+ }>): CardMonth;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * A corporate card's month (ADR-0178 결정 4 · 6): what was charged, what was taken back, what its bills paid, and what
4
+ * the card still owes when the month ends - its charges less its refunds less its bills, from the first line on. How
5
+ * many charges no line explains yet, and how much was spent for oneself.
6
+ *
7
+ * Pure.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.cardMonth = cardMonth;
11
+ /** `month` is YYYY-MM; `explained` is each explained charge's id and whether it was personal use. */
12
+ function cardMonth(month, lines, bills, explained) {
13
+ const inMonth = (day) => !!day && day.slice(0, 7) === month;
14
+ const byEnd = (day) => !!day && day.slice(0, 7) <= month;
15
+ const amount = (value) => Math.abs(Number(value) || 0);
16
+ const result = { spent: 0, refunded: 0, billed: 0, outstanding: 0, unexplained: 0, personalUse: 0 };
17
+ for (const line of lines) {
18
+ const charge = line.type === 'EXPENSE';
19
+ if (byEnd(line.transactionDate))
20
+ result.outstanding += charge ? amount(line.amount) : -amount(line.amount);
21
+ if (!inMonth(line.transactionDate))
22
+ continue;
23
+ if (!charge) {
24
+ result.refunded += amount(line.amount);
25
+ continue;
26
+ }
27
+ result.spent += amount(line.amount);
28
+ const explanation = explained.get(line.id);
29
+ if (!explanation)
30
+ result.unexplained++;
31
+ else if (explanation.personalUse)
32
+ result.personalUse += amount(line.amount);
33
+ }
34
+ for (const bill of bills) {
35
+ if (byEnd(bill.transactionDate))
36
+ result.outstanding -= amount(bill.amount);
37
+ if (inMonth(bill.transactionDate))
38
+ result.billed += amount(bill.amount);
39
+ }
40
+ return result;
41
+ }
42
+ //# sourceMappingURL=card-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-summary.js","sourceRoot":"","sources":["../../../server/service/bank-account/card-summary.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAwBH,8BA6BC;AA9BD,qGAAqG;AACrG,SAAgB,SAAS,CACvB,KAAa,EACb,KAA0B,EAC1B,KAA0B,EAC1B,SAAwD;IAExD,MAAM,OAAO,GAAG,CAAC,GAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,CAAA;IAC3E,MAAM,KAAK,GAAG,CAAC,GAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAA;IACxE,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IAC9D,MAAM,MAAM,GAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAA;IAE9G,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAA;QACtC,IAAI,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC;YAAE,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC1G,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC;YAAE,SAAQ;QAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACtC,SAAQ;QACV,CAAC;QACD,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACnC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC1C,IAAI,CAAC,WAAW;YAAE,MAAM,CAAC,WAAW,EAAE,CAAA;aACjC,IAAI,WAAW,CAAC,WAAW;YAAE,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC7E,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC;YAAE,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC1E,IAAI,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC;YAAE,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACzE,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC","sourcesContent":["/**\n * A corporate card's month (ADR-0178 결정 4 · 6): what was charged, what was taken back, what its bills paid, and what\n * the card still owes when the month ends - its charges less its refunds less its bills, from the first line on. How\n * many charges no line explains yet, and how much was spent for oneself.\n *\n * Pure.\n */\n\nexport interface CardLine {\n id: string\n transactionDate?: string | null\n type: string\n amount: number\n}\n\nexport interface CardBill {\n transactionDate?: string | null\n amount: number\n}\n\nexport interface CardMonth {\n spent: number\n refunded: number\n billed: number\n outstanding: number\n unexplained: number\n personalUse: number\n}\n\n/** `month` is YYYY-MM; `explained` is each explained charge's id and whether it was personal use. */\nexport function cardMonth(\n month: string,\n lines: readonly CardLine[],\n bills: readonly CardBill[],\n explained: ReadonlyMap<string, { personalUse: boolean }>\n): CardMonth {\n const inMonth = (day?: string | null) => !!day && day.slice(0, 7) === month\n const byEnd = (day?: string | null) => !!day && day.slice(0, 7) <= month\n const amount = (value: number) => Math.abs(Number(value) || 0)\n const result: CardMonth = { spent: 0, refunded: 0, billed: 0, outstanding: 0, unexplained: 0, personalUse: 0 }\n\n for (const line of lines) {\n const charge = line.type === 'EXPENSE'\n if (byEnd(line.transactionDate)) result.outstanding += charge ? amount(line.amount) : -amount(line.amount)\n if (!inMonth(line.transactionDate)) continue\n if (!charge) {\n result.refunded += amount(line.amount)\n continue\n }\n result.spent += amount(line.amount)\n const explanation = explained.get(line.id)\n if (!explanation) result.unexplained++\n else if (explanation.personalUse) result.personalUse += amount(line.amount)\n }\n for (const bill of bills) {\n if (byEnd(bill.transactionDate)) result.outstanding -= amount(bill.amount)\n if (inMonth(bill.transactionDate)) result.billed += amount(bill.amount)\n }\n return result\n}\n"]}
@@ -2,6 +2,7 @@ import { BankAccount } from './bank-account';
2
2
  import { BankAccountHistoryEntitySubscriber } from './event-subscriber';
3
3
  import { BankAccountQuery } from './bank-account-query';
4
4
  import { BankAccountMutation } from './bank-account-mutation';
5
+ import { CardQuery } from './card-query';
5
6
  export declare const entities: (typeof BankAccount)[];
6
- export declare const resolvers: (typeof BankAccountQuery | typeof BankAccountMutation)[];
7
+ export declare const resolvers: (typeof BankAccountQuery | typeof BankAccountMutation | typeof CardQuery)[];
7
8
  export declare const subscribers: (typeof BankAccountHistoryEntitySubscriber)[];