@zhin.js/plugin-ledger 1.0.0 → 1.0.2

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 (67) hide show
  1. package/README.md +6 -0
  2. package/commands/ledger-add/index.js +6 -4
  3. package/commands/ledger-add/index.ts +6 -4
  4. package/commands/ledger-delete/index.js +6 -4
  5. package/commands/ledger-delete/index.ts +6 -4
  6. package/commands/ledger-list/index.js +8 -6
  7. package/commands/ledger-list/index.ts +8 -6
  8. package/commands/ledger-month/index.js +5 -3
  9. package/commands/ledger-month/index.ts +5 -3
  10. package/commands/ledger-report/index.js +11 -11
  11. package/commands/ledger-report/index.ts +10 -12
  12. package/commands/ledger-stats/index.js +8 -6
  13. package/commands/ledger-stats/index.ts +8 -6
  14. package/commands/ledger-today/index.js +5 -3
  15. package/commands/ledger-today/index.ts +5 -3
  16. package/commands/ledger-week/index.js +5 -3
  17. package/commands/ledger-week/index.ts +5 -3
  18. package/lib/config.js +3 -3
  19. package/lib/config.js.map +1 -1
  20. package/lib/entry-input.d.ts +3 -2
  21. package/lib/entry-input.d.ts.map +1 -1
  22. package/lib/entry-input.js +11 -9
  23. package/lib/entry-input.js.map +1 -1
  24. package/lib/i18n.d.ts +2 -0
  25. package/lib/i18n.d.ts.map +1 -0
  26. package/lib/i18n.js +200 -0
  27. package/lib/i18n.js.map +1 -0
  28. package/lib/identity.d.ts +3 -1
  29. package/lib/identity.d.ts.map +1 -1
  30. package/lib/identity.js +5 -2
  31. package/lib/identity.js.map +1 -1
  32. package/lib/index.d.ts +1 -1
  33. package/lib/index.d.ts.map +1 -1
  34. package/lib/index.js +1 -1
  35. package/lib/index.js.map +1 -1
  36. package/lib/money.d.ts +2 -1
  37. package/lib/money.d.ts.map +1 -1
  38. package/lib/money.js +6 -5
  39. package/lib/money.js.map +1 -1
  40. package/lib/period.d.ts +4 -3
  41. package/lib/period.d.ts.map +1 -1
  42. package/lib/period.js +8 -16
  43. package/lib/period.js.map +1 -1
  44. package/lib/report-format.d.ts +5 -4
  45. package/lib/report-format.d.ts.map +1 -1
  46. package/lib/report-format.js +25 -24
  47. package/lib/report-format.js.map +1 -1
  48. package/lib/service.d.ts +1 -1
  49. package/lib/service.d.ts.map +1 -1
  50. package/lib/service.js +59 -25
  51. package/lib/service.js.map +1 -1
  52. package/lib/store.d.ts +9 -1
  53. package/lib/store.d.ts.map +1 -1
  54. package/lib/store.js +32 -3
  55. package/lib/store.js.map +1 -1
  56. package/package.json +7 -7
  57. package/schema.json +15 -0
  58. package/src/config.ts +3 -3
  59. package/src/entry-input.ts +12 -9
  60. package/src/i18n.ts +200 -0
  61. package/src/identity.ts +6 -2
  62. package/src/index.ts +1 -1
  63. package/src/money.ts +7 -5
  64. package/src/period.ts +7 -13
  65. package/src/report-format.ts +26 -24
  66. package/src/service.ts +59 -26
  67. package/src/store.ts +33 -3
package/src/store.ts CHANGED
@@ -1,7 +1,10 @@
1
+ import { resolveLocale, type Locale } from 'zhin.js/i18n';
1
2
  import type { DatabaseHostModel, DeliveryTarget, PluginDatabaseHost } from 'zhin.js';
2
3
 
3
4
  export const ENTRY_TABLE = 'ledger_entries';
4
5
  export const USER_TABLE = 'ledger_users';
6
+ /** Separate table: existing databases only run CREATE TABLE IF NOT EXISTS, so new columns on `ledger_users` would never appear. */
7
+ export const PRIVATE_TARGET_TABLE = 'ledger_private_targets';
5
8
 
6
9
  /** One expense. `seq` is the per-user number shown as `#id`; amounts are integer cents. */
7
10
  export interface LedgerEntry {
@@ -18,6 +21,7 @@ export interface LedgerUserRecord {
18
21
  readonly ownerKey: string;
19
22
  readonly nextSeq: number;
20
23
  readonly reportEnabled: boolean;
24
+ readonly reportLocale?: Locale;
21
25
  readonly reportTarget: DeliveryTarget | undefined;
22
26
  readonly lastReportDate: string;
23
27
  }
@@ -36,8 +40,13 @@ export function defineLedgerTables(database: Pick<PluginDatabaseHost, 'define'>)
36
40
  owner_key: { type: 'text', nullable: false },
37
41
  next_seq: { type: 'integer', default: 1 },
38
42
  report_enabled: { type: 'integer', default: 0 },
43
+ report_locale: { type: 'text', length: 16, nullable: true },
39
44
  report_target: { type: 'text', default: '' },
40
45
  last_report_date: { type: 'text', default: '' },
46
+ }, { addColumns: ['report_locale'] });
47
+ database.define(PRIVATE_TARGET_TABLE, {
48
+ owner_key: { type: 'text', nullable: false },
49
+ target: { type: 'text', nullable: false },
41
50
  });
42
51
  }
43
52
 
@@ -66,6 +75,7 @@ function toUser(row: Record<string, unknown>): LedgerUserRecord {
66
75
  ownerKey: String(row.owner_key),
67
76
  nextSeq: Number(row.next_seq ?? 1),
68
77
  reportEnabled: Number(row.report_enabled ?? 0) === 1,
78
+ reportLocale: resolveLocale(row.report_locale),
69
79
  reportTarget: parseTarget(row.report_target),
70
80
  lastReportDate: String(row.last_report_date ?? ''),
71
81
  };
@@ -91,7 +101,7 @@ export class LedgerStore {
91
101
 
92
102
  async getUser(ownerKey: string): Promise<LedgerUserRecord | undefined> {
93
103
  const rows = await this.#model(USER_TABLE)
94
- .select('owner_key', 'next_seq', 'report_enabled', 'report_target', 'last_report_date')
104
+ .select('owner_key', 'next_seq', 'report_enabled', 'report_locale', 'report_target', 'last_report_date')
95
105
  .where({ owner_key: ownerKey });
96
106
  const first = rows[0];
97
107
  return first ? toUser(first) : undefined;
@@ -148,18 +158,38 @@ export class LedgerStore {
148
158
  await this.#model(ENTRY_TABLE).delete().where({ owner_key: ownerKey, seq });
149
159
  }
150
160
 
151
- async setReport(ownerKey: string, enabled: boolean, target: DeliveryTarget | undefined, lastReportDate: string): Promise<void> {
161
+ async setReport(ownerKey: string, enabled: boolean, target: DeliveryTarget | undefined, lastReportDate: string, locale?: Locale): Promise<void> {
152
162
  await this.#ensureUser(ownerKey);
153
163
  await this.#model(USER_TABLE).update({
154
164
  report_enabled: enabled ? 1 : 0,
165
+ ...(enabled ? { report_locale: resolveLocale(locale) } : {}),
155
166
  report_target: target ? JSON.stringify(target) : '',
156
167
  last_report_date: lastReportDate,
157
168
  }).where({ owner_key: ownerKey });
158
169
  }
159
170
 
171
+ /** The real private conversation saved when the user talked to the bot in private. */
172
+ async getPrivateTarget(ownerKey: string): Promise<DeliveryTarget | undefined> {
173
+ const rows = await this.#model(PRIVATE_TARGET_TABLE).select('owner_key', 'target').where({ owner_key: ownerKey });
174
+ return parseTarget(rows[0]?.target);
175
+ }
176
+
177
+ /** Saves the real private conversation; an enabled daily report follows it. */
178
+ async setPrivateTarget(ownerKey: string, target: DeliveryTarget): Promise<void> {
179
+ const raw = JSON.stringify(target);
180
+ const model = this.#model(PRIVATE_TARGET_TABLE);
181
+ const existing = await model.select('owner_key', 'target').where({ owner_key: ownerKey });
182
+ if (existing.length > 0) await model.update({ target: raw }).where({ owner_key: ownerKey });
183
+ else await model.insert({ owner_key: ownerKey, target: raw });
184
+ const user = await this.getUser(ownerKey);
185
+ if (user?.reportEnabled) {
186
+ await this.#model(USER_TABLE).update({ report_target: raw }).where({ owner_key: ownerKey });
187
+ }
188
+ }
189
+
160
190
  async listReportSubscribers(): Promise<LedgerUserRecord[]> {
161
191
  const rows = await this.#model(USER_TABLE)
162
- .select('owner_key', 'next_seq', 'report_enabled', 'report_target', 'last_report_date')
192
+ .select('owner_key', 'next_seq', 'report_enabled', 'report_locale', 'report_target', 'last_report_date')
163
193
  .where({ report_enabled: 1 });
164
194
  return rows.map(toUser);
165
195
  }