@dealpos-npm/ng-dealpos-library 21.0.39 → 21.0.40

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.
@@ -2,6 +2,7 @@ import Dexie, { liveQuery } from 'dexie';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, Inject, Injectable, makeEnvironmentProviders } from '@angular/core';
4
4
  import { Observable } from 'rxjs';
5
+ import { v4 } from 'uuid';
5
6
  import Fuse from 'fuse.js';
6
7
 
7
8
  class PosDatabaseBase extends Dexie {
@@ -12,6 +13,14 @@ class PosDatabaseBase extends Dexie {
12
13
  orders: '++id, status',
13
14
  settings: 'key',
14
15
  });
16
+ // v2 replaces the auto-increment `orders` primary key with a UUID string.
17
+ // The schema change already drops the object store, so this explicit clear
18
+ // only states the intent: old numeric-key order rows are not migrated.
19
+ this.version(2)
20
+ .stores({
21
+ orders: 'id, status',
22
+ })
23
+ .upgrade((tx) => tx.table('orders').clear());
15
24
  }
16
25
  }
17
26
 
@@ -30,8 +39,14 @@ class OrderQueueRepository {
30
39
  toStored(record) {
31
40
  return Object.assign(record.order, { id: record.id });
32
41
  }
33
- saveUnsent(order) {
42
+ /**
43
+ * Queues an order. Pass `id` to make the save idempotent — re-saving the same
44
+ * order overwrites the existing record instead of creating a duplicate.
45
+ * When omitted, a fresh UUID is generated.
46
+ */
47
+ saveUnsent(order, id) {
34
48
  return this.table.add({
49
+ id: id ?? v4(),
35
50
  status: 'unsent',
36
51
  order: this.toPayload(order),
37
52
  });
@@ -104,20 +119,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
104
119
  args: [POS_DATABASE]
105
120
  }] }] });
106
121
 
122
+ const UNRANKED = Number.MAX_SAFE_INTEGER;
123
+ function escapeContainsToken(token) {
124
+ return token.replace(/"/g, '').replace(/\|/g, '\\|');
125
+ }
126
+ /**
127
+ * Builds an extended-search pattern that matches by **substring** ("contains")
128
+ * instead of the default fuzzy bitap algorithm. Each word becomes one `include`
129
+ * matcher (`'word`) and words are AND-ed because extended search treats
130
+ * space-separated tokens as a conjunction.
131
+ */
132
+ function toContainsPattern(query) {
133
+ return query
134
+ .trim()
135
+ .split(/\s+/)
136
+ .map(escapeContainsToken)
137
+ .filter((token) => token.length > 0)
138
+ .map((token) => `'${token}`)
139
+ .join(' ');
140
+ }
141
+ function firstMatchIndex(arg) {
142
+ let first = UNRANKED;
143
+ for (const match of arg.matches ?? []) {
144
+ const start = match.indices?.[0]?.[0];
145
+ if (typeof start === 'number' && start < first) {
146
+ first = start;
147
+ }
148
+ }
149
+ return first;
150
+ }
151
+ function lastMatchIndex(arg) {
152
+ let last = -1;
153
+ for (const match of arg.matches ?? []) {
154
+ for (const range of match.indices ?? []) {
155
+ if (range[0] > last) {
156
+ last = range[0];
157
+ }
158
+ }
159
+ }
160
+ return last;
161
+ }
162
+ function shortestMatchedValue(arg) {
163
+ let shortest = UNRANKED;
164
+ for (const match of arg.matches ?? []) {
165
+ shortest = Math.min(shortest, match.value?.length ?? 0);
166
+ }
167
+ return shortest;
168
+ }
169
+ /**
170
+ * Substring matches all score 0 in extended search, so relevance is restored
171
+ * here: earliest hit first (prefix beats mid-word), then tightest span, then
172
+ * shortest matched field, then catalog order as the stable tie-break.
173
+ */
174
+ const matchPositionSortFn = (a, b) => {
175
+ const first = firstMatchIndex(a) - firstMatchIndex(b);
176
+ if (first !== 0) {
177
+ return first;
178
+ }
179
+ const last = lastMatchIndex(a) - lastMatchIndex(b);
180
+ if (last !== 0) {
181
+ return last;
182
+ }
183
+ const length = shortestMatchedValue(a) - shortestMatchedValue(b);
184
+ if (length !== 0) {
185
+ return length;
186
+ }
187
+ return a.idx - b.idx;
188
+ };
107
189
  function createFuzzyIndex(items, keys, options) {
108
190
  return new Fuse([...items], {
109
191
  includeScore: true,
110
192
  includeMatches: true,
193
+ findAllMatches: true,
194
+ useExtendedSearch: true,
195
+ sortFn: matchPositionSortFn,
111
196
  keys: [...keys],
112
197
  ...(options ?? {}),
113
198
  });
114
199
  }
115
200
  function fuzzySearch(index, query, opts) {
116
- if (!query) {
201
+ const pattern = index.options.useExtendedSearch !== false ? toContainsPattern(query) : query.trim();
202
+ if (!pattern) {
117
203
  return [];
118
204
  }
119
205
  return index
120
- .search(query, opts)
206
+ .search(pattern, opts)
121
207
  .map((r) => ({
122
208
  item: r.item,
123
209
  score: r.score ?? 0,
@@ -165,6 +251,20 @@ class KeyedTableRepository {
165
251
  count() {
166
252
  return this.table.count();
167
253
  }
254
+ /**
255
+ * Estimasi ukuran penyimpanan (byte) untuk seluruh baris di tabel ini.
256
+ * Dihitung dari panjang serialisasi JSON (UTF-8) tiap record, jadi ini
257
+ * hanya perkiraan — belum termasuk overhead structured-clone dan index Dexie.
258
+ * Membaca per baris via `table.each()` agar tidak menahan seluruh tabel di memori.
259
+ */
260
+ async estimateSize() {
261
+ const encoder = new TextEncoder();
262
+ let total = 0;
263
+ await this.table.each((item) => {
264
+ total += encoder.encode(JSON.stringify(item)).length;
265
+ });
266
+ return total;
267
+ }
168
268
  }
169
269
 
170
270
  class ProductsRepository extends KeyedTableRepository {
@@ -202,8 +302,14 @@ class SettingsRepository extends KeyValueRepository {
202
302
  getSyncTime() {
203
303
  return this.get('syncTime');
204
304
  }
205
- putSyncTime(time) {
206
- return this.put('syncTime', { time });
305
+ /**
306
+ * Catat waktu sync terakhir, opsional beserta durasi proses sync (ms).
307
+ * `durationMs` bersifat opsional agar pemanggil lama tetap kompatibel.
308
+ * Saat tidak diisi, field tidak disimpan sehingga record tetap `{ time }`.
309
+ */
310
+ putSyncTime(time, durationMs) {
311
+ const value = durationMs === undefined ? { time } : { time, durationMs };
312
+ return this.put('syncTime', value);
207
313
  }
208
314
  getLoadPOSAPI() {
209
315
  return this.get('LoadPOSAPI');
@@ -242,5 +348,5 @@ function provideDexieDataAccess(database) {
242
348
  * Generated bundle index. Do not edit.
243
349
  */
244
350
 
245
- export { KeyValueRepository, KeyedTableRepository, OrderQueueRepository, OrdersRepository, POS_DATABASE, PosDatabaseBase, ProductsRepository, SettingsRepository, createFuzzyIndex, fuzzySearch, provideDexieDataAccess };
351
+ export { KeyValueRepository, KeyedTableRepository, OrderQueueRepository, OrdersRepository, POS_DATABASE, PosDatabaseBase, ProductsRepository, SettingsRepository, createFuzzyIndex, fuzzySearch, matchPositionSortFn, provideDexieDataAccess, toContainsPattern };
246
352
  //# sourceMappingURL=dealpos-npm-ng-dealpos-library-dexie-data-access.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dealpos-npm-ng-dealpos-library-dexie-data-access.mjs","sources":["../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/db/pos-database.base.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/di/pos-database.token.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/order-queue.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/orders.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/search/fuzzy-search.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/keyed-table.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/products.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/key-value.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/settings.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/di/provide-pos-dexie-data-access.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/dealpos-npm-ng-dealpos-library-dexie-data-access.ts"],"sourcesContent":["import Dexie, { type EntityTable, type IndexableType } from 'dexie';\nimport type {\n\tSalesOrderDataModel,\n\tVariantByIDHttpResponse,\n} from '@dealpos-npm/ng-dealpos-library/sell';\nimport type { OrderRecord, SettingRecord } from './records.model';\n\nexport abstract class PosDatabaseBase<\n\tTProduct extends { ID: IndexableType } = VariantByIDHttpResponse,\n\tTOrder = SalesOrderDataModel,\n> extends Dexie {\n\tproducts!: EntityTable<TProduct, 'ID'>;\n\torders!: EntityTable<OrderRecord<TOrder>, 'id'>;\n\tsettings!: EntityTable<SettingRecord, 'key'>;\n\n\tprotected constructor(name: string) {\n\t\tsuper(name);\n\t\tthis.version(1).stores({\n\t\t\tproducts: 'ID, Code',\n\t\t\torders: '++id, status',\n\t\t\tsettings: 'key',\n\t\t});\n\t}\n}\n","import { InjectionToken } from '@angular/core';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\n\nexport const POS_DATABASE = new InjectionToken<PosDatabaseBase>('POS_DATABASE');\n","import { liveQuery, type EntityTable } from 'dexie';\nimport { Observable } from 'rxjs';\nimport type { SalesOrderDataModel } from '@dealpos-npm/ng-dealpos-library/sell';\nimport type { OrderRecord, OrderStatus } from '../db/records.model';\n\nexport type StoredEntity<T> = T & { id?: number };\n\nexport class OrderQueueRepository<TOrder = SalesOrderDataModel> {\n\tconstructor(\n\t\tprotected readonly table: EntityTable<OrderRecord<TOrder>, 'id', OrderRecord<TOrder>>,\n\t\tprotected readonly options: {\n\t\t\torderIdExtractor: (order: TOrder) => string | number;\n\t\t},\n\t) {}\n\n\tprivate toPayload(order: TOrder): TOrder {\n\t\tconst payload = JSON.parse(JSON.stringify(order)) as TOrder & { id?: number };\n\t\tdelete payload.id;\n\t\treturn payload as TOrder;\n\t}\n\n\tprivate toStored(record: OrderRecord<TOrder>): StoredEntity<TOrder> {\n\t\treturn Object.assign(record.order as object, { id: record.id }) as StoredEntity<TOrder>;\n\t}\n\n\tsaveUnsent(order: TOrder): Promise<number> {\n\t\treturn this.table.add({\n\t\t\tstatus: 'unsent',\n\t\t\torder: this.toPayload(order),\n\t\t}) as Promise<number>;\n\t}\n\n\tobserveByStatus(status: OrderStatus): Observable<Array<StoredEntity<TOrder>>> {\n\t\treturn new Observable((subscriber) => {\n\t\t\tconst live = liveQuery(() => this.table.where('status').equals(status).toArray());\n\t\t\tconst subscription = live.subscribe({\n\t\t\t\tnext: (records) => subscriber.next(records.map((record) => this.toStored(record))),\n\t\t\t\terror: (error) => subscriber.error(error),\n\t\t\t});\n\t\t\treturn () => subscription.unsubscribe();\n\t\t});\n\t}\n\n\tasync listByStatus(status: OrderStatus): Promise<Array<StoredEntity<TOrder>>> {\n\t\tconst records = await this.table.where('status').equals(status).toArray();\n\t\treturn records.map((record) => this.toStored(record));\n\t}\n\n\tlistUnsent(): Promise<Array<StoredEntity<TOrder>>> {\n\t\treturn this.listByStatus('unsent');\n\t}\n\n\tlistFailed(): Promise<Array<StoredEntity<TOrder>>> {\n\t\treturn this.listByStatus('failed');\n\t}\n\n\tlistSuccess(): Promise<Array<StoredEntity<TOrder>>> {\n\t\treturn this.listByStatus('success');\n\t}\n\n\tasync findUnsentByOrderId(\n\t\torderId: string | number,\n\t): Promise<StoredEntity<TOrder> | undefined> {\n\t\tconst records = await this.table.where('status').equals('unsent').toArray();\n\t\tconst match = records.find(\n\t\t\t(record) => this.options.orderIdExtractor(record.order) == orderId,\n\t\t);\n\t\treturn match ? this.toStored(match) : undefined;\n\t}\n\n\tasync remove(id: number): Promise<void> {\n\t\tawait this.table.delete(id);\n\t}\n\n\tmarkFailed(id: number, order: TOrder): Promise<number> {\n\t\treturn this.table.put({\n\t\t\tid,\n\t\t\tstatus: 'failed',\n\t\t\torder: this.toPayload(order),\n\t\t}) as Promise<number>;\n\t}\n\n\tmarkSuccess(id: number, order: TOrder): Promise<number> {\n\t\treturn this.table.put({\n\t\t\tid,\n\t\t\tstatus: 'success',\n\t\t\torder: this.toPayload(order),\n\t\t}) as Promise<number>;\n\t}\n\n\tclearFailed(): Promise<number> {\n\t\treturn this.table.where('status').equals('failed').delete();\n\t}\n\n\tclearSuccess(): Promise<number> {\n\t\treturn this.table.where('status').equals('success').delete();\n\t}\n}\n","import { Inject, Injectable } from '@angular/core';\nimport type { SalesOrderDataModel } from '@dealpos-npm/ng-dealpos-library/sell';\nimport { OrderQueueRepository } from './order-queue.repository';\nimport { POS_DATABASE } from '../di/pos-database.token';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\n\nexport type StoredOrder = SalesOrderDataModel & { id?: number };\n\n@Injectable({ providedIn: 'root' })\nexport class OrdersRepository extends OrderQueueRepository<SalesOrderDataModel> {\n\tconstructor(@Inject(POS_DATABASE) db: PosDatabaseBase) {\n\t\tsuper(db.orders, { orderIdExtractor: (o) => o.Order?.ID });\n\t}\n}\n","import Fuse from 'fuse.js';\nimport type {\n\tFuseOptionKey,\n\tFuseResultMatch,\n\tFuseSearchOptions,\n\tIFuseOptions,\n} from 'fuse.js';\n\nexport interface FuzzyMatch<T> {\n\titem: T;\n\tscore: number;\n\tmatches: readonly FuseResultMatch[];\n}\n\nexport function createFuzzyIndex<T>(\n\titems: ReadonlyArray<T>,\n\tkeys: ReadonlyArray<FuseOptionKey<T>>,\n\toptions?: IFuseOptions<T>,\n): Fuse<T> {\n\treturn new Fuse([...items], {\n\t\tincludeScore: true,\n\t\tincludeMatches: true,\n\t\tkeys: [...keys],\n\t\t...(options ?? {}),\n\t});\n}\n\nexport function fuzzySearch<T>(\n\tindex: Fuse<T>,\n\tquery: string,\n\topts?: FuseSearchOptions,\n): Array<FuzzyMatch<T>> {\n\tif (!query) {\n\t\treturn [];\n\t}\n\treturn index\n\t\t.search(query, opts)\n\t\t.map((r) => ({\n\t\t\titem: r.item,\n\t\t\tscore: r.score ?? 0,\n\t\t\tmatches: r.matches ?? [],\n\t\t}));\n}\n","import type { EntityTable, IDType } from 'dexie';\nimport type { default as Fuse, FuseOptionKey, FuseSearchOptions, IFuseOptions } from 'fuse.js';\nimport { createFuzzyIndex, fuzzySearch } from '../search/fuzzy-search';\nimport type { FuzzyMatch } from '../search/fuzzy-search';\n\nexport class KeyedTableRepository<T, K extends keyof T & string> {\n\tprivate fuzzyIndex: Fuse<T> | undefined;\n\n\tconstructor(\n\t\tprotected readonly table: EntityTable<T, K>,\n\t\tprotected readonly options?: {\n\t\t\tcodeIndex?: string;\n\t\t\tfuzzyKeys?: ReadonlyArray<FuseOptionKey<T>>;\n\t\t\tfuzzyOptions?: IFuseOptions<T>;\n\t\t},\n\t) {}\n\n\tgetAll(): Promise<T[]> {\n\t\treturn this.table.toArray();\n\t}\n\n\tgetById(id: T[K]): Promise<T | undefined> {\n\t\treturn this.table.get(id as IDType<T, K>);\n\t}\n\n\tgetByIndex(index: string, value: unknown): Promise<T | undefined> {\n\t\treturn this.table.where(index).equals(value as never).first();\n\t}\n\n\tasync searchFuzzy(\n\t\tquery: string,\n\t\topts?: FuseSearchOptions,\n\t): Promise<Array<FuzzyMatch<T>>> {\n\t\tconst keys = this.options?.fuzzyKeys;\n\t\tif (!keys || keys.length === 0 || !query) {\n\t\t\treturn [];\n\t\t}\n\t\tif (!this.fuzzyIndex) {\n\t\t\tthis.fuzzyIndex = createFuzzyIndex(\n\t\t\t\tawait this.getAll(),\n\t\t\t\tkeys,\n\t\t\t\tthis.options?.fuzzyOptions,\n\t\t\t);\n\t\t}\n\t\treturn fuzzySearch(this.fuzzyIndex, query, opts);\n\t}\n\n\treplaceAll(items: T[]): Promise<void> {\n\t\tthis.fuzzyIndex = undefined;\n\t\treturn this.table.db.transaction('rw', this.table, async () => {\n\t\t\tawait this.table.clear();\n\t\t\tif (items.length > 0) {\n\t\t\t\tawait this.table.bulkAdd(items);\n\t\t\t}\n\t\t});\n\t}\n\n\tclear(): Promise<void> {\n\t\tthis.fuzzyIndex = undefined;\n\t\treturn this.table.clear();\n\t}\n\n\tcount(): Promise<number> {\n\t\treturn this.table.count();\n\t}\n}\n","import { Inject, Injectable } from '@angular/core';\nimport type { VariantByIDHttpResponse } from '@dealpos-npm/ng-dealpos-library/sell';\nimport { KeyedTableRepository } from './keyed-table.repository';\nimport { POS_DATABASE } from '../di/pos-database.token';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\n\n@Injectable({ providedIn: 'root' })\nexport class ProductsRepository extends KeyedTableRepository<VariantByIDHttpResponse, 'ID'> {\n\tconstructor(@Inject(POS_DATABASE) db: PosDatabaseBase) {\n\t\tsuper(db.products, { codeIndex: 'Code', fuzzyKeys: ['Name', 'Code'] });\n\t}\n}\n","import type { EntityTable } from 'dexie';\nimport type { SettingKey, SettingRecord } from '../db/records.model';\n\nexport class KeyValueRepository<TMap extends object> {\n\tconstructor(protected readonly table: EntityTable<SettingRecord, 'key'>) {}\n\n\tasync get<K extends keyof TMap & string>(key: K): Promise<TMap[K] | undefined> {\n\t\tconst record = await this.table.get(key as SettingKey);\n\t\treturn record?.value as TMap[K] | undefined;\n\t}\n\n\tput<K extends keyof TMap & string>(key: K, value: TMap[K]): Promise<SettingKey> {\n\t\treturn this.table.put({ key: key as SettingKey, value });\n\t}\n}\n","import { Inject, Injectable } from '@angular/core';\nimport { KeyValueRepository } from './key-value.repository';\nimport { POS_DATABASE } from '../di/pos-database.token';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\nimport type { SettingKey, SyncTimeValue } from '../db/records.model';\n\nexport interface CanonicalSettingsMap {\n\tsyncTime: SyncTimeValue;\n\tLoadPOSAPI: unknown;\n\tactiveRegister: unknown;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class SettingsRepository extends KeyValueRepository<CanonicalSettingsMap> {\n\tconstructor(@Inject(POS_DATABASE) db: PosDatabaseBase) {\n\t\tsuper(db.settings);\n\t}\n\n\tgetSyncTime(): Promise<SyncTimeValue | undefined> {\n\t\treturn this.get('syncTime');\n\t}\n\n\tputSyncTime(time: string): Promise<SettingKey> {\n\t\treturn this.put('syncTime', { time });\n\t}\n\n\tgetLoadPOSAPI<T = unknown>(): Promise<T | undefined> {\n\t\treturn this.get('LoadPOSAPI') as Promise<T | undefined>;\n\t}\n\n\tputLoadPOSAPI<T>(value: T): Promise<SettingKey> {\n\t\treturn this.put('LoadPOSAPI', value);\n\t}\n\n\tasync getActiveRegister<T = unknown>(): Promise<T | null> {\n\t\treturn ((await this.get('activeRegister')) as T | undefined) ?? null;\n\t}\n\n\tputActiveRegister<T>(value: T): Promise<SettingKey> {\n\t\treturn this.put('activeRegister', value);\n\t}\n}\n","import { makeEnvironmentProviders } from '@angular/core';\nimport type { EnvironmentProviders, Type } from '@angular/core';\nimport { POS_DATABASE } from './pos-database.token';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\nimport { OrdersRepository } from '../repositories/orders.repository';\nimport { ProductsRepository } from '../repositories/products.repository';\nimport { SettingsRepository } from '../repositories/settings.repository';\n\nexport function provideDexieDataAccess(database: Type<PosDatabaseBase>): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\tdatabase,\n\t\t{ provide: POS_DATABASE, useExisting: database },\n\t\tOrdersRepository,\n\t\tProductsRepository,\n\t\tSettingsRepository,\n\t]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dealpos-npm-ng-dealpos-library-dexie-data-access.mjs","sources":["../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/db/pos-database.base.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/di/pos-database.token.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/order-queue.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/orders.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/search/fuzzy-search.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/keyed-table.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/products.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/key-value.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/repositories/settings.repository.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/src/di/provide-pos-dexie-data-access.ts","../../../projects/dealpos-npm/ng-dealpos-library/dexie-data-access/dealpos-npm-ng-dealpos-library-dexie-data-access.ts"],"sourcesContent":["import Dexie, { type EntityTable, type IndexableType } from 'dexie';\nimport type {\n\tSalesOrderDataModel,\n\tVariantByIDHttpResponse,\n} from '@dealpos-npm/ng-dealpos-library/sell';\nimport type { OrderRecord, SettingRecord } from './records.model';\n\nexport abstract class PosDatabaseBase<\n\tTProduct extends { ID: IndexableType } = VariantByIDHttpResponse,\n\tTOrder = SalesOrderDataModel,\n> extends Dexie {\n\tproducts!: EntityTable<TProduct, 'ID'>;\n\torders!: EntityTable<OrderRecord<TOrder>, 'id', OrderRecord<TOrder>>;\n\tsettings!: EntityTable<SettingRecord, 'key'>;\n\n\tprotected constructor(name: string) {\n\t\tsuper(name);\n\t\tthis.version(1).stores({\n\t\t\tproducts: 'ID, Code',\n\t\t\torders: '++id, status',\n\t\t\tsettings: 'key',\n\t\t});\n\n\t\t// v2 replaces the auto-increment `orders` primary key with a UUID string.\n\t\t// The schema change already drops the object store, so this explicit clear\n\t\t// only states the intent: old numeric-key order rows are not migrated.\n\t\tthis.version(2)\n\t\t\t.stores({\n\t\t\t\torders: 'id, status',\n\t\t\t})\n\t\t\t.upgrade((tx) => tx.table('orders').clear());\n\t}\n}\n","import { InjectionToken } from '@angular/core';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\n\nexport const POS_DATABASE = new InjectionToken<PosDatabaseBase>('POS_DATABASE');\n","import { liveQuery, type EntityTable } from 'dexie';\nimport { Observable } from 'rxjs';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { SalesOrderDataModel } from '@dealpos-npm/ng-dealpos-library/sell';\nimport type { OrderRecord, OrderStatus } from '../db/records.model';\n\n/** Orders table keyed by a UUID string primary key (`id`). */\nexport type OrderTable<TOrder> = EntityTable<\n\tOrderRecord<TOrder>,\n\t'id',\n\tOrderRecord<TOrder>\n>;\n\nexport type StoredEntity<T> = T & { id?: string };\n\nexport class OrderQueueRepository<TOrder = SalesOrderDataModel> {\n\tconstructor(\n\t\tprotected readonly table: OrderTable<TOrder>,\n\t\tprotected readonly options: {\n\t\t\torderIdExtractor: (order: TOrder) => string | number;\n\t\t},\n\t) {}\n\n\tprivate toPayload(order: TOrder): TOrder {\n\t\tconst payload = JSON.parse(JSON.stringify(order)) as TOrder & { id?: string };\n\t\tdelete payload.id;\n\t\treturn payload as TOrder;\n\t}\n\n\tprivate toStored(record: OrderRecord<TOrder>): StoredEntity<TOrder> {\n\t\treturn Object.assign(record.order as object, { id: record.id }) as StoredEntity<TOrder>;\n\t}\n\n\t/**\n\t * Queues an order. Pass `id` to make the save idempotent — re-saving the same\n\t * order overwrites the existing record instead of creating a duplicate.\n\t * When omitted, a fresh UUID is generated.\n\t */\n\tsaveUnsent(order: TOrder, id?: string): Promise<string> {\n\t\treturn this.table.add({\n\t\t\tid: id ?? uuidv4(),\n\t\t\tstatus: 'unsent',\n\t\t\torder: this.toPayload(order),\n\t\t}) as Promise<string>;\n\t}\n\n\tobserveByStatus(status: OrderStatus): Observable<Array<StoredEntity<TOrder>>> {\n\t\treturn new Observable((subscriber) => {\n\t\t\tconst live = liveQuery(() => this.table.where('status').equals(status).toArray());\n\t\t\tconst subscription = live.subscribe({\n\t\t\t\tnext: (records) => subscriber.next(records.map((record) => this.toStored(record))),\n\t\t\t\terror: (error) => subscriber.error(error),\n\t\t\t});\n\t\t\treturn () => subscription.unsubscribe();\n\t\t});\n\t}\n\n\tasync listByStatus(status: OrderStatus): Promise<Array<StoredEntity<TOrder>>> {\n\t\tconst records = await this.table.where('status').equals(status).toArray();\n\t\treturn records.map((record) => this.toStored(record));\n\t}\n\n\tlistUnsent(): Promise<Array<StoredEntity<TOrder>>> {\n\t\treturn this.listByStatus('unsent');\n\t}\n\n\tlistFailed(): Promise<Array<StoredEntity<TOrder>>> {\n\t\treturn this.listByStatus('failed');\n\t}\n\n\tlistSuccess(): Promise<Array<StoredEntity<TOrder>>> {\n\t\treturn this.listByStatus('success');\n\t}\n\n\tasync findUnsentByOrderId(\n\t\torderId: string | number,\n\t): Promise<StoredEntity<TOrder> | undefined> {\n\t\tconst records = await this.table.where('status').equals('unsent').toArray();\n\t\tconst match = records.find(\n\t\t\t(record) => this.options.orderIdExtractor(record.order) == orderId,\n\t\t);\n\t\treturn match ? this.toStored(match) : undefined;\n\t}\n\n\tasync remove(id: string): Promise<void> {\n\t\tawait this.table.delete(id);\n\t}\n\n\tmarkFailed(id: string, order: TOrder): Promise<string> {\n\t\treturn this.table.put({\n\t\t\tid,\n\t\t\tstatus: 'failed',\n\t\t\torder: this.toPayload(order),\n\t\t}) as Promise<string>;\n\t}\n\n\tmarkSuccess(id: string, order: TOrder): Promise<string> {\n\t\treturn this.table.put({\n\t\t\tid,\n\t\t\tstatus: 'success',\n\t\t\torder: this.toPayload(order),\n\t\t}) as Promise<string>;\n\t}\n\n\tclearFailed(): Promise<number> {\n\t\treturn this.table.where('status').equals('failed').delete();\n\t}\n\n\tclearSuccess(): Promise<number> {\n\t\treturn this.table.where('status').equals('success').delete();\n\t}\n}\n","import { Inject, Injectable } from '@angular/core';\nimport type { SalesOrderDataModel } from '@dealpos-npm/ng-dealpos-library/sell';\nimport { OrderQueueRepository } from './order-queue.repository';\nimport { POS_DATABASE } from '../di/pos-database.token';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\n\nexport type StoredOrder = SalesOrderDataModel & { id?: string };\n\n@Injectable({ providedIn: 'root' })\nexport class OrdersRepository extends OrderQueueRepository<SalesOrderDataModel> {\n\tconstructor(@Inject(POS_DATABASE) db: PosDatabaseBase) {\n\t\tsuper(db.orders, { orderIdExtractor: (o) => o.Order?.ID });\n\t}\n}\n","import Fuse from 'fuse.js';\nimport type {\n\tFuseOptionKey,\n\tFuseResultMatch,\n\tFuseSearchOptions,\n\tFuseSortFunction,\n\tFuseSortFunctionArg,\n\tIFuseOptions,\n} from 'fuse.js';\n\nexport interface FuzzyMatch<T> {\n\titem: T;\n\tscore: number;\n\tmatches: readonly FuseResultMatch[];\n}\n\nconst UNRANKED = Number.MAX_SAFE_INTEGER;\n\nfunction escapeContainsToken(token: string): string {\n\treturn token.replace(/\"/g, '').replace(/\\|/g, '\\\\|');\n}\n\n/**\n * Builds an extended-search pattern that matches by **substring** (\"contains\")\n * instead of the default fuzzy bitap algorithm. Each word becomes one `include`\n * matcher (`'word`) and words are AND-ed because extended search treats\n * space-separated tokens as a conjunction.\n */\nexport function toContainsPattern(query: string): string {\n\treturn query\n\t\t.trim()\n\t\t.split(/\\s+/)\n\t\t.map(escapeContainsToken)\n\t\t.filter((token) => token.length > 0)\n\t\t.map((token) => `'${token}`)\n\t\t.join(' ');\n}\n\nfunction firstMatchIndex(arg: FuseSortFunctionArg): number {\n\tlet first = UNRANKED;\n\tfor (const match of arg.matches ?? []) {\n\t\tconst start = match.indices?.[0]?.[0];\n\t\tif (typeof start === 'number' && start < first) {\n\t\t\tfirst = start;\n\t\t}\n\t}\n\treturn first;\n}\n\nfunction lastMatchIndex(arg: FuseSortFunctionArg): number {\n\tlet last = -1;\n\tfor (const match of arg.matches ?? []) {\n\t\tfor (const range of match.indices ?? []) {\n\t\t\tif (range[0] > last) {\n\t\t\t\tlast = range[0];\n\t\t\t}\n\t\t}\n\t}\n\treturn last;\n}\n\nfunction shortestMatchedValue(arg: FuseSortFunctionArg): number {\n\tlet shortest = UNRANKED;\n\tfor (const match of arg.matches ?? []) {\n\t\tshortest = Math.min(shortest, match.value?.length ?? 0);\n\t}\n\treturn shortest;\n}\n\n/**\n * Substring matches all score 0 in extended search, so relevance is restored\n * here: earliest hit first (prefix beats mid-word), then tightest span, then\n * shortest matched field, then catalog order as the stable tie-break.\n */\nexport const matchPositionSortFn: FuseSortFunction = (a, b) => {\n\tconst first = firstMatchIndex(a) - firstMatchIndex(b);\n\tif (first !== 0) {\n\t\treturn first;\n\t}\n\tconst last = lastMatchIndex(a) - lastMatchIndex(b);\n\tif (last !== 0) {\n\t\treturn last;\n\t}\n\tconst length = shortestMatchedValue(a) - shortestMatchedValue(b);\n\tif (length !== 0) {\n\t\treturn length;\n\t}\n\treturn a.idx - b.idx;\n};\n\nexport function createFuzzyIndex<T>(\n\titems: ReadonlyArray<T>,\n\tkeys: ReadonlyArray<FuseOptionKey<T>>,\n\toptions?: IFuseOptions<T>,\n): Fuse<T> {\n\treturn new Fuse([...items], {\n\t\tincludeScore: true,\n\t\tincludeMatches: true,\n\t\tfindAllMatches: true,\n\t\tuseExtendedSearch: true,\n\t\tsortFn: matchPositionSortFn,\n\t\tkeys: [...keys],\n\t\t...(options ?? {}),\n\t});\n}\n\nexport function fuzzySearch<T>(\n\tindex: Fuse<T>,\n\tquery: string,\n\topts?: FuseSearchOptions,\n): Array<FuzzyMatch<T>> {\n\tconst pattern =\n\t\tindex.options.useExtendedSearch !== false ? toContainsPattern(query) : query.trim();\n\tif (!pattern) {\n\t\treturn [];\n\t}\n\treturn index\n\t\t.search(pattern, opts)\n\t\t.map((r) => ({\n\t\t\titem: r.item,\n\t\t\tscore: r.score ?? 0,\n\t\t\tmatches: r.matches ?? [],\n\t\t}));\n}\n","import type { EntityTable, IDType } from 'dexie';\nimport type { default as Fuse, FuseOptionKey, FuseSearchOptions, IFuseOptions } from 'fuse.js';\nimport { createFuzzyIndex, fuzzySearch } from '../search/fuzzy-search';\nimport type { FuzzyMatch } from '../search/fuzzy-search';\n\nexport class KeyedTableRepository<T, K extends keyof T & string> {\n\tprivate fuzzyIndex: Fuse<T> | undefined;\n\n\tconstructor(\n\t\tprotected readonly table: EntityTable<T, K>,\n\t\tprotected readonly options?: {\n\t\t\tcodeIndex?: string;\n\t\t\tfuzzyKeys?: ReadonlyArray<FuseOptionKey<T>>;\n\t\t\tfuzzyOptions?: IFuseOptions<T>;\n\t\t},\n\t) {}\n\n\tgetAll(): Promise<T[]> {\n\t\treturn this.table.toArray();\n\t}\n\n\tgetById(id: T[K]): Promise<T | undefined> {\n\t\treturn this.table.get(id as IDType<T, K>);\n\t}\n\n\tgetByIndex(index: string, value: unknown): Promise<T | undefined> {\n\t\treturn this.table.where(index).equals(value as never).first();\n\t}\n\n\tasync searchFuzzy(\n\t\tquery: string,\n\t\topts?: FuseSearchOptions,\n\t): Promise<Array<FuzzyMatch<T>>> {\n\t\tconst keys = this.options?.fuzzyKeys;\n\t\tif (!keys || keys.length === 0 || !query) {\n\t\t\treturn [];\n\t\t}\n\t\tif (!this.fuzzyIndex) {\n\t\t\tthis.fuzzyIndex = createFuzzyIndex(\n\t\t\t\tawait this.getAll(),\n\t\t\t\tkeys,\n\t\t\t\tthis.options?.fuzzyOptions,\n\t\t\t);\n\t\t}\n\t\treturn fuzzySearch(this.fuzzyIndex, query, opts);\n\t}\n\n\treplaceAll(items: T[]): Promise<void> {\n\t\tthis.fuzzyIndex = undefined;\n\t\treturn this.table.db.transaction('rw', this.table, async () => {\n\t\t\tawait this.table.clear();\n\t\t\tif (items.length > 0) {\n\t\t\t\tawait this.table.bulkAdd(items);\n\t\t\t}\n\t\t});\n\t}\n\n\tclear(): Promise<void> {\n\t\tthis.fuzzyIndex = undefined;\n\t\treturn this.table.clear();\n\t}\n\n\tcount(): Promise<number> {\n\t\treturn this.table.count();\n\t}\n\n\t/**\n\t * Estimasi ukuran penyimpanan (byte) untuk seluruh baris di tabel ini.\n\t * Dihitung dari panjang serialisasi JSON (UTF-8) tiap record, jadi ini\n\t * hanya perkiraan — belum termasuk overhead structured-clone dan index Dexie.\n\t * Membaca per baris via `table.each()` agar tidak menahan seluruh tabel di memori.\n\t */\n\tasync estimateSize(): Promise<number> {\n\t\tconst encoder = new TextEncoder();\n\t\tlet total = 0;\n\t\tawait this.table.each((item) => {\n\t\t\ttotal += encoder.encode(JSON.stringify(item)).length;\n\t\t});\n\t\treturn total;\n\t}\n}\n","import { Inject, Injectable } from '@angular/core';\nimport type { VariantByIDHttpResponse } from '@dealpos-npm/ng-dealpos-library/sell';\nimport { KeyedTableRepository } from './keyed-table.repository';\nimport { POS_DATABASE } from '../di/pos-database.token';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\n\n@Injectable({ providedIn: 'root' })\nexport class ProductsRepository extends KeyedTableRepository<VariantByIDHttpResponse, 'ID'> {\n\tconstructor(@Inject(POS_DATABASE) db: PosDatabaseBase) {\n\t\tsuper(db.products, { codeIndex: 'Code', fuzzyKeys: ['Name', 'Code'] });\n\t}\n}\n","import type { EntityTable } from 'dexie';\nimport type { SettingKey, SettingRecord } from '../db/records.model';\n\nexport class KeyValueRepository<TMap extends object> {\n\tconstructor(protected readonly table: EntityTable<SettingRecord, 'key'>) {}\n\n\tasync get<K extends keyof TMap & string>(key: K): Promise<TMap[K] | undefined> {\n\t\tconst record = await this.table.get(key as SettingKey);\n\t\treturn record?.value as TMap[K] | undefined;\n\t}\n\n\tput<K extends keyof TMap & string>(key: K, value: TMap[K]): Promise<SettingKey> {\n\t\treturn this.table.put({ key: key as SettingKey, value });\n\t}\n}\n","import { Inject, Injectable } from '@angular/core';\nimport { KeyValueRepository } from './key-value.repository';\nimport { POS_DATABASE } from '../di/pos-database.token';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\nimport type { SettingKey, SyncTimeValue } from '../db/records.model';\n\nexport interface CanonicalSettingsMap {\n\tsyncTime: SyncTimeValue;\n\tLoadPOSAPI: unknown;\n\tactiveRegister: unknown;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class SettingsRepository extends KeyValueRepository<CanonicalSettingsMap> {\n\tconstructor(@Inject(POS_DATABASE) db: PosDatabaseBase) {\n\t\tsuper(db.settings);\n\t}\n\n\tgetSyncTime(): Promise<SyncTimeValue | undefined> {\n\t\treturn this.get('syncTime');\n\t}\n\n\t/**\n\t * Catat waktu sync terakhir, opsional beserta durasi proses sync (ms).\n\t * `durationMs` bersifat opsional agar pemanggil lama tetap kompatibel.\n\t * Saat tidak diisi, field tidak disimpan sehingga record tetap `{ time }`.\n\t */\n\tputSyncTime(time: string, durationMs?: number): Promise<SettingKey> {\n\t\tconst value: SyncTimeValue =\n\t\t\tdurationMs === undefined ? { time } : { time, durationMs };\n\t\treturn this.put('syncTime', value);\n\t}\n\n\tgetLoadPOSAPI<T = unknown>(): Promise<T | undefined> {\n\t\treturn this.get('LoadPOSAPI') as Promise<T | undefined>;\n\t}\n\n\tputLoadPOSAPI<T>(value: T): Promise<SettingKey> {\n\t\treturn this.put('LoadPOSAPI', value);\n\t}\n\n\tasync getActiveRegister<T = unknown>(): Promise<T | null> {\n\t\treturn ((await this.get('activeRegister')) as T | undefined) ?? null;\n\t}\n\n\tputActiveRegister<T>(value: T): Promise<SettingKey> {\n\t\treturn this.put('activeRegister', value);\n\t}\n}\n","import { makeEnvironmentProviders } from '@angular/core';\nimport type { EnvironmentProviders, Type } from '@angular/core';\nimport { POS_DATABASE } from './pos-database.token';\nimport type { PosDatabaseBase } from '../db/pos-database.base';\nimport { OrdersRepository } from '../repositories/orders.repository';\nimport { ProductsRepository } from '../repositories/products.repository';\nimport { SettingsRepository } from '../repositories/settings.repository';\n\nexport function provideDexieDataAccess(database: Type<PosDatabaseBase>): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\tdatabase,\n\t\t{ provide: POS_DATABASE, useExisting: database },\n\t\tOrdersRepository,\n\t\tProductsRepository,\n\t\tSettingsRepository,\n\t]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["uuidv4"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dealpos-npm/ng-dealpos-library",
3
- "version": "21.0.39",
3
+ "version": "21.0.40",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.5",
6
6
  "@angular/core": "^21.0.5",
@@ -29,7 +29,8 @@
29
29
  "primeng": "^21.2.0",
30
30
  "primeicons": "^7.0.0",
31
31
  "papaparse": "^5.5.3",
32
- "simple-keyboard": "^3.8.93"
32
+ "simple-keyboard": "^3.8.93",
33
+ "uuid": "^14.0.2"
33
34
  },
34
35
  "dependencies": {
35
36
  "tslib": "^2.3.0"
@@ -3,12 +3,12 @@ import { SalesOrderDataModel, VariantByIDHttpResponse } from '@dealpos-npm/ng-de
3
3
  import Dexie, { IndexableType, EntityTable } from 'dexie';
4
4
  import * as i0 from '@angular/core';
5
5
  import { InjectionToken, Type, EnvironmentProviders } from '@angular/core';
6
- import Fuse, { FuseResultMatch, FuseOptionKey, IFuseOptions, FuseSearchOptions } from 'fuse.js';
6
+ import Fuse, { FuseResultMatch, FuseSortFunction, FuseOptionKey, IFuseOptions, FuseSearchOptions } from 'fuse.js';
7
7
  import { Observable } from 'rxjs';
8
8
 
9
9
  type OrderStatus = 'unsent' | 'failed' | 'success';
10
10
  interface OrderRecord<TOrder = SalesOrderDataModel> {
11
- id?: number;
11
+ id: string;
12
12
  status: OrderStatus;
13
13
  order: TOrder;
14
14
  }
@@ -19,13 +19,19 @@ interface SettingRecord {
19
19
  }
20
20
  interface SyncTimeValue {
21
21
  time: string;
22
+ /**
23
+ * Durasi proses sync terakhir dalam milidetik.
24
+ * Opsional: record lama (dan pemanggil yang tidak mengukur durasi)
25
+ * tetap valid tanpa field ini.
26
+ */
27
+ durationMs?: number;
22
28
  }
23
29
 
24
30
  declare abstract class PosDatabaseBase<TProduct extends {
25
31
  ID: IndexableType;
26
32
  } = VariantByIDHttpResponse, TOrder = SalesOrderDataModel> extends Dexie {
27
33
  products: EntityTable<TProduct, 'ID'>;
28
- orders: EntityTable<OrderRecord<TOrder>, 'id'>;
34
+ orders: EntityTable<OrderRecord<TOrder>, 'id', OrderRecord<TOrder>>;
29
35
  settings: EntityTable<SettingRecord, 'key'>;
30
36
  protected constructor(name: string);
31
37
  }
@@ -39,6 +45,19 @@ interface FuzzyMatch<T> {
39
45
  score: number;
40
46
  matches: readonly FuseResultMatch[];
41
47
  }
48
+ /**
49
+ * Builds an extended-search pattern that matches by **substring** ("contains")
50
+ * instead of the default fuzzy bitap algorithm. Each word becomes one `include`
51
+ * matcher (`'word`) and words are AND-ed because extended search treats
52
+ * space-separated tokens as a conjunction.
53
+ */
54
+ declare function toContainsPattern(query: string): string;
55
+ /**
56
+ * Substring matches all score 0 in extended search, so relevance is restored
57
+ * here: earliest hit first (prefix beats mid-word), then tightest span, then
58
+ * shortest matched field, then catalog order as the stable tie-break.
59
+ */
60
+ declare const matchPositionSortFn: FuseSortFunction;
42
61
  declare function createFuzzyIndex<T>(items: ReadonlyArray<T>, keys: ReadonlyArray<FuseOptionKey<T>>, options?: IFuseOptions<T>): Fuse<T>;
43
62
  declare function fuzzySearch<T>(index: Fuse<T>, query: string, opts?: FuseSearchOptions): Array<FuzzyMatch<T>>;
44
63
 
@@ -62,31 +81,45 @@ declare class KeyedTableRepository<T, K extends keyof T & string> {
62
81
  replaceAll(items: T[]): Promise<void>;
63
82
  clear(): Promise<void>;
64
83
  count(): Promise<number>;
84
+ /**
85
+ * Estimasi ukuran penyimpanan (byte) untuk seluruh baris di tabel ini.
86
+ * Dihitung dari panjang serialisasi JSON (UTF-8) tiap record, jadi ini
87
+ * hanya perkiraan — belum termasuk overhead structured-clone dan index Dexie.
88
+ * Membaca per baris via `table.each()` agar tidak menahan seluruh tabel di memori.
89
+ */
90
+ estimateSize(): Promise<number>;
65
91
  }
66
92
 
93
+ /** Orders table keyed by a UUID string primary key (`id`). */
94
+ type OrderTable<TOrder> = EntityTable<OrderRecord<TOrder>, 'id', OrderRecord<TOrder>>;
67
95
  type StoredEntity<T> = T & {
68
- id?: number;
96
+ id?: string;
69
97
  };
70
98
  declare class OrderQueueRepository<TOrder = SalesOrderDataModel> {
71
- protected readonly table: EntityTable<OrderRecord<TOrder>, 'id', OrderRecord<TOrder>>;
99
+ protected readonly table: OrderTable<TOrder>;
72
100
  protected readonly options: {
73
101
  orderIdExtractor: (order: TOrder) => string | number;
74
102
  };
75
- constructor(table: EntityTable<OrderRecord<TOrder>, 'id', OrderRecord<TOrder>>, options: {
103
+ constructor(table: OrderTable<TOrder>, options: {
76
104
  orderIdExtractor: (order: TOrder) => string | number;
77
105
  });
78
106
  private toPayload;
79
107
  private toStored;
80
- saveUnsent(order: TOrder): Promise<number>;
108
+ /**
109
+ * Queues an order. Pass `id` to make the save idempotent — re-saving the same
110
+ * order overwrites the existing record instead of creating a duplicate.
111
+ * When omitted, a fresh UUID is generated.
112
+ */
113
+ saveUnsent(order: TOrder, id?: string): Promise<string>;
81
114
  observeByStatus(status: OrderStatus): Observable<Array<StoredEntity<TOrder>>>;
82
115
  listByStatus(status: OrderStatus): Promise<Array<StoredEntity<TOrder>>>;
83
116
  listUnsent(): Promise<Array<StoredEntity<TOrder>>>;
84
117
  listFailed(): Promise<Array<StoredEntity<TOrder>>>;
85
118
  listSuccess(): Promise<Array<StoredEntity<TOrder>>>;
86
119
  findUnsentByOrderId(orderId: string | number): Promise<StoredEntity<TOrder> | undefined>;
87
- remove(id: number): Promise<void>;
88
- markFailed(id: number, order: TOrder): Promise<number>;
89
- markSuccess(id: number, order: TOrder): Promise<number>;
120
+ remove(id: string): Promise<void>;
121
+ markFailed(id: string, order: TOrder): Promise<string>;
122
+ markSuccess(id: string, order: TOrder): Promise<string>;
90
123
  clearFailed(): Promise<number>;
91
124
  clearSuccess(): Promise<number>;
92
125
  }
@@ -99,7 +132,7 @@ declare class KeyValueRepository<TMap extends object> {
99
132
  }
100
133
 
101
134
  type StoredOrder = SalesOrderDataModel & {
102
- id?: number;
135
+ id?: string;
103
136
  };
104
137
  declare class OrdersRepository extends OrderQueueRepository<SalesOrderDataModel> {
105
138
  constructor(db: PosDatabaseBase);
@@ -121,7 +154,12 @@ interface CanonicalSettingsMap {
121
154
  declare class SettingsRepository extends KeyValueRepository<CanonicalSettingsMap> {
122
155
  constructor(db: PosDatabaseBase);
123
156
  getSyncTime(): Promise<SyncTimeValue | undefined>;
124
- putSyncTime(time: string): Promise<SettingKey>;
157
+ /**
158
+ * Catat waktu sync terakhir, opsional beserta durasi proses sync (ms).
159
+ * `durationMs` bersifat opsional agar pemanggil lama tetap kompatibel.
160
+ * Saat tidak diisi, field tidak disimpan sehingga record tetap `{ time }`.
161
+ */
162
+ putSyncTime(time: string, durationMs?: number): Promise<SettingKey>;
125
163
  getLoadPOSAPI<T = unknown>(): Promise<T | undefined>;
126
164
  putLoadPOSAPI<T>(value: T): Promise<SettingKey>;
127
165
  getActiveRegister<T = unknown>(): Promise<T | null>;
@@ -130,5 +168,5 @@ declare class SettingsRepository extends KeyValueRepository<CanonicalSettingsMap
130
168
  static ɵprov: i0.ɵɵInjectableDeclaration<SettingsRepository>;
131
169
  }
132
170
 
133
- export { KeyValueRepository, KeyedTableRepository, OrderQueueRepository, OrdersRepository, POS_DATABASE, PosDatabaseBase, ProductsRepository, SettingsRepository, createFuzzyIndex, fuzzySearch, provideDexieDataAccess };
134
- export type { CanonicalSettingsMap, FuzzyMatch, OrderRecord, OrderStatus, SettingKey, SettingRecord, StoredEntity, StoredOrder, SyncTimeValue };
171
+ export { KeyValueRepository, KeyedTableRepository, OrderQueueRepository, OrdersRepository, POS_DATABASE, PosDatabaseBase, ProductsRepository, SettingsRepository, createFuzzyIndex, fuzzySearch, matchPositionSortFn, provideDexieDataAccess, toContainsPattern };
172
+ export type { CanonicalSettingsMap, FuzzyMatch, OrderRecord, OrderStatus, OrderTable, SettingKey, SettingRecord, StoredEntity, StoredOrder, SyncTimeValue };