@soostori/desktop-adapter 0.1.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-pin.d.ts +16 -0
- package/dist/auth-pin.d.ts.map +1 -0
- package/dist/auth-pin.js +14 -0
- package/dist/auth-pin.js.map +1 -0
- package/dist/business-repository.d.ts +31 -0
- package/dist/business-repository.d.ts.map +1 -0
- package/dist/business-repository.js +61 -0
- package/dist/business-repository.js.map +1 -0
- package/dist/categories-repository.d.ts +15 -0
- package/dist/categories-repository.d.ts.map +1 -0
- package/dist/categories-repository.js +35 -0
- package/dist/categories-repository.js.map +1 -0
- package/dist/customers-repository.d.ts +20 -0
- package/dist/customers-repository.d.ts.map +1 -0
- package/dist/customers-repository.js +95 -0
- package/dist/customers-repository.js.map +1 -0
- package/dist/debts-repository.d.ts +48 -0
- package/dist/debts-repository.d.ts.map +1 -0
- package/dist/debts-repository.js +57 -0
- package/dist/debts-repository.js.map +1 -0
- package/dist/devices-repository.d.ts +29 -0
- package/dist/devices-repository.d.ts.map +1 -0
- package/dist/devices-repository.js +120 -0
- package/dist/devices-repository.js.map +1 -0
- package/dist/domain-repositories.d.ts +12 -0
- package/dist/domain-repositories.d.ts.map +1 -0
- package/dist/domain-repositories.js +12 -0
- package/dist/domain-repositories.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory-repository.d.ts +31 -0
- package/dist/inventory-repository.d.ts.map +1 -0
- package/dist/inventory-repository.js +127 -0
- package/dist/inventory-repository.js.map +1 -0
- package/dist/products-repository-mappers.d.ts +77 -0
- package/dist/products-repository-mappers.d.ts.map +1 -0
- package/dist/products-repository-mappers.js +75 -0
- package/dist/products-repository-mappers.js.map +1 -0
- package/dist/products-repository-read.d.ts +17 -0
- package/dist/products-repository-read.d.ts.map +1 -0
- package/dist/products-repository-read.js +51 -0
- package/dist/products-repository-read.js.map +1 -0
- package/dist/products-repository-stock.d.ts +28 -0
- package/dist/products-repository-stock.d.ts.map +1 -0
- package/dist/products-repository-stock.js +57 -0
- package/dist/products-repository-stock.js.map +1 -0
- package/dist/products-repository-types.d.ts +51 -0
- package/dist/products-repository-types.d.ts.map +1 -0
- package/dist/products-repository-types.js +5 -0
- package/dist/products-repository-types.js.map +1 -0
- package/dist/products-repository-variants.d.ts +19 -0
- package/dist/products-repository-variants.d.ts.map +1 -0
- package/dist/products-repository-variants.js +26 -0
- package/dist/products-repository-variants.js.map +1 -0
- package/dist/products-repository-write.d.ts +14 -0
- package/dist/products-repository-write.d.ts.map +1 -0
- package/dist/products-repository-write.js +99 -0
- package/dist/products-repository-write.js.map +1 -0
- package/dist/products-repository.d.ts +69 -0
- package/dist/products-repository.d.ts.map +1 -0
- package/dist/products-repository.js +48 -0
- package/dist/products-repository.js.map +1 -0
- package/dist/sales-repository.d.ts +95 -0
- package/dist/sales-repository.d.ts.map +1 -0
- package/dist/sales-repository.js +160 -0
- package/dist/sales-repository.js.map +1 -0
- package/dist/sqlite-database.d.ts +16 -0
- package/dist/sqlite-database.d.ts.map +1 -0
- package/dist/sqlite-database.js +24 -0
- package/dist/sqlite-database.js.map +1 -0
- package/dist/sqlite-repository.d.ts +18 -0
- package/dist/sqlite-repository.d.ts.map +1 -0
- package/dist/sqlite-repository.js +61 -0
- package/dist/sqlite-repository.js.map +1 -0
- package/dist/sqlite-transaction.d.ts +13 -0
- package/dist/sqlite-transaction.d.ts.map +1 -0
- package/dist/sqlite-transaction.js +35 -0
- package/dist/sqlite-transaction.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProductsRepository type definitions — shared interfaces for the repository module.
|
|
3
|
+
*/
|
|
4
|
+
import type { ProductId, CategoryId, ProductVariantId, ISO8601, Money } from '@soostori/core';
|
|
5
|
+
export type { ProductId, CategoryId, ProductVariantId, ISO8601, Money };
|
|
6
|
+
/** Full product insert input — includes Desktop-extended fields not in SDK Product. */
|
|
7
|
+
export interface ProductCreateInput {
|
|
8
|
+
name: string;
|
|
9
|
+
categoryId?: string | null;
|
|
10
|
+
sku?: string | null;
|
|
11
|
+
barcode?: string | null;
|
|
12
|
+
description?: string | null;
|
|
13
|
+
imageUrl?: string | null;
|
|
14
|
+
costPrice?: Money;
|
|
15
|
+
sellingPrice: Money;
|
|
16
|
+
discountPrice?: Money | null;
|
|
17
|
+
unit?: string;
|
|
18
|
+
stockQuantity?: number;
|
|
19
|
+
lowStockThreshold?: number;
|
|
20
|
+
trackInventory?: boolean;
|
|
21
|
+
hasVariants?: boolean;
|
|
22
|
+
allowSingleUnitSale?: boolean;
|
|
23
|
+
distributorName?: string | null;
|
|
24
|
+
distributorPhone?: string | null;
|
|
25
|
+
isActive?: boolean;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
/** Full category insert input. */
|
|
29
|
+
export interface CategoryCreateInput {
|
|
30
|
+
name: string;
|
|
31
|
+
description?: string | null;
|
|
32
|
+
icon?: string | null;
|
|
33
|
+
color?: string;
|
|
34
|
+
displayOrder?: number;
|
|
35
|
+
isActive?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** Local ProductVariant — mirrors @soostori/business/products ProductVariant */
|
|
38
|
+
export interface ProductVariant {
|
|
39
|
+
id: ProductVariantId;
|
|
40
|
+
productId: ProductId;
|
|
41
|
+
name: string;
|
|
42
|
+
sku: string | null;
|
|
43
|
+
barcode: string | null;
|
|
44
|
+
costPrice: Money | null;
|
|
45
|
+
sellingPrice: Money | null;
|
|
46
|
+
stockQuantity: number;
|
|
47
|
+
metadata: Record<string, unknown> | null;
|
|
48
|
+
createdAt: ISO8601;
|
|
49
|
+
updatedAt: ISO8601;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=products-repository-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products-repository-types.d.ts","sourceRoot":"","sources":["../src/products-repository-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAC7F,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;AAEvE,uFAAuF;AACvF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,YAAY,EAAE,KAAK,CAAA;IACnB,aAAa,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,kCAAkC;AAClC,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,gBAAgB,CAAA;IACpB,SAAS,EAAE,SAAS,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,KAAK,GAAG,IAAI,CAAA;IACvB,YAAY,EAAE,KAAK,GAAG,IAAI,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACxC,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products-repository-types.js","sourceRoot":"","sources":["../src/products-repository-types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product variant operations.
|
|
3
|
+
*/
|
|
4
|
+
import type { ProductVariant } from './products-repository-types.js';
|
|
5
|
+
import type { ProductId } from './products-repository-types.js';
|
|
6
|
+
export declare class ProductsVariantRepository {
|
|
7
|
+
findVariants(productId: ProductId): Promise<ProductVariant[]>;
|
|
8
|
+
createVariant(data: {
|
|
9
|
+
productId: import('@soostori/core').UUID;
|
|
10
|
+
name: string;
|
|
11
|
+
sku?: string | null;
|
|
12
|
+
barcode?: string | null;
|
|
13
|
+
costPrice?: import('@soostori/core').Money | null;
|
|
14
|
+
sellingPrice?: import('@soostori/core').Money | null;
|
|
15
|
+
stockQuantity?: number;
|
|
16
|
+
metadata?: Record<string, unknown> | null;
|
|
17
|
+
}): Promise<ProductVariant>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=products-repository-variants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products-repository-variants.d.ts","sourceRoot":"","sources":["../src/products-repository-variants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAoB,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAIjF,qBAAa,yBAAyB;IAC9B,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAO7D,aAAa,CAAC,IAAI,EAAE;QACxB,SAAS,EAAE,OAAO,gBAAgB,EAAE,IAAI,CAAA;QACxC,IAAI,EAAE,MAAM,CAAA;QACZ,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACnB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACvB,SAAS,CAAC,EAAE,OAAO,gBAAgB,EAAE,KAAK,GAAG,IAAI,CAAA;QACjD,YAAY,CAAC,EAAE,OAAO,gBAAgB,EAAE,KAAK,GAAG,IAAI,CAAA;QACpD,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;KAC1C,GAAG,OAAO,CAAC,cAAc,CAAC;CAkB5B"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product variant operations.
|
|
3
|
+
*/
|
|
4
|
+
import { getDatabase } from './sqlite-database.js';
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
6
|
+
import { rowToVariant } from './products-repository-mappers.js';
|
|
7
|
+
export class ProductsVariantRepository {
|
|
8
|
+
async findVariants(productId) {
|
|
9
|
+
const rows = getDatabase()
|
|
10
|
+
.prepare('SELECT * FROM product_variants WHERE product_id = ?')
|
|
11
|
+
.all(productId);
|
|
12
|
+
return rows.map(rowToVariant);
|
|
13
|
+
}
|
|
14
|
+
async createVariant(data) {
|
|
15
|
+
const db = getDatabase();
|
|
16
|
+
const id = randomUUID();
|
|
17
|
+
const now = new Date().toISOString();
|
|
18
|
+
db.prepare(`
|
|
19
|
+
INSERT INTO product_variants (id, product_id, name, sku, barcode, cost_price, selling_price, stock_quantity, metadata, created_at, updated_at)
|
|
20
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
21
|
+
`).run(id, data.productId, data.name, data.sku || null, data.barcode || null, data.costPrice ?? null, data.sellingPrice ?? null, data.stockQuantity ?? 0, data.metadata ? JSON.stringify(data.metadata) : null, now, now);
|
|
22
|
+
const row = db.prepare('SELECT * FROM product_variants WHERE id = ?').get(id);
|
|
23
|
+
return rowToVariant(row);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=products-repository-variants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products-repository-variants.js","sourceRoot":"","sources":["../src/products-repository-variants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAInC,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAE/D,MAAM,OAAO,yBAAyB;IACpC,KAAK,CAAC,YAAY,CAAC,SAAoB;QACrC,MAAM,IAAI,GAAG,WAAW,EAAE;aACvB,OAAO,CAAC,qDAAqD,CAAC;aAC9D,GAAG,CAAC,SAAmB,CAAiB,CAAA;QAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,IASnB;QACC,MAAM,EAAE,GAAG,WAAW,EAAE,CAAA;QACxB,MAAM,EAAE,GAAG,UAAU,EAAiC,CAAA;QACtD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACpC,EAAE,CAAC,OAAO,CAAC;;;KAGV,CAAC,CAAC,GAAG,CACJ,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,EAC7B,IAAI,CAAC,GAAG,IAAI,IAAI,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI,EACtC,IAAI,CAAC,SAAS,IAAI,IAAI,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI,EACjD,IAAI,CAAC,aAAa,IAAI,CAAC,EACvB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EACpD,GAAG,EAAE,GAAG,CACT,CAAA;QACD,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC,GAAG,CAAC,EAAY,CAAe,CAAA;QACrG,OAAO,YAAY,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Products write operations — creates, updates, deletes.
|
|
3
|
+
*/
|
|
4
|
+
import type { Product, Category } from '@soostori/core';
|
|
5
|
+
import type { ProductCreateInput, CategoryCreateInput } from './products-repository-types.js';
|
|
6
|
+
import type { ProductId, CategoryId } from './products-repository-types.js';
|
|
7
|
+
export declare class ProductsWriteRepository {
|
|
8
|
+
create(data: ProductCreateInput): Promise<Product>;
|
|
9
|
+
update(id: ProductId, changes: Partial<ProductCreateInput>): Promise<Product>;
|
|
10
|
+
softDelete(id: ProductId): Promise<void>;
|
|
11
|
+
createCategory(data: CategoryCreateInput): Promise<Category>;
|
|
12
|
+
updateCategory(id: CategoryId, changes: Partial<CategoryCreateInput>): Promise<Category>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=products-repository-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products-repository-write.d.ts","sourceRoot":"","sources":["../src/products-repository-write.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AAC7F,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAgB3E,qBAAa,uBAAuB;IAC5B,MAAM,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IA6BlD,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB7E,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxC,cAAc,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAa5D,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;CAiB/F"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Products write operations — creates, updates, deletes.
|
|
3
|
+
*/
|
|
4
|
+
import { getDatabase } from './sqlite-database.js';
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
6
|
+
import { rowToProduct, rowToCategory } from './products-repository-mappers.js';
|
|
7
|
+
const fieldMap = [
|
|
8
|
+
['name', 'name'], ['categoryId', 'category_id'], ['sku', 'sku'],
|
|
9
|
+
['barcode', 'barcode'], ['description', 'description'],
|
|
10
|
+
['imageUrl', 'image_url'], ['costPrice', 'cost_price'],
|
|
11
|
+
['sellingPrice', 'selling_price'], ['discountPrice', 'discount_price'],
|
|
12
|
+
['unit', 'unit'], ['stockQuantity', 'stock_quantity'],
|
|
13
|
+
['lowStockThreshold', 'low_stock_threshold'],
|
|
14
|
+
['trackInventory', 'track_inventory'], ['allowSingleUnitSale', 'allow_single_unit_sale'],
|
|
15
|
+
['distributorName', 'distributor_name'],
|
|
16
|
+
['distributorPhone', 'distributor_phone'],
|
|
17
|
+
];
|
|
18
|
+
export class ProductsWriteRepository {
|
|
19
|
+
async create(data) {
|
|
20
|
+
const db = getDatabase();
|
|
21
|
+
const id = randomUUID();
|
|
22
|
+
const now = new Date().toISOString();
|
|
23
|
+
db.prepare(`
|
|
24
|
+
INSERT INTO products (id, category_id, name, sku, barcode, description, image_url,
|
|
25
|
+
cost_price, selling_price, discount_price, unit, stock_quantity,
|
|
26
|
+
low_stock_threshold, track_inventory, has_variants, expiry_date,
|
|
27
|
+
is_active, distributor_name, distributor_phone,
|
|
28
|
+
barcode_generated, allow_single_unit_sale, units_per_package,
|
|
29
|
+
box_buying_price, bulk_selling_price, group_prices,
|
|
30
|
+
created_at, updated_at)
|
|
31
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
32
|
+
`).run(id, data.categoryId || null, data.name, data.sku || null, data.barcode || null, data.description || null, data.imageUrl || null, data.costPrice ?? 0, data.sellingPrice, data.discountPrice ?? null, data.unit || 'piece', data.stockQuantity ?? 0, data.lowStockThreshold ?? 5, data.trackInventory ? 1 : 0, 0, null, data.isActive !== undefined ? (data.isActive ? 1 : 0) : 1, data.distributorName || null, data.distributorPhone || null, 0, data.allowSingleUnitSale !== false ? 1 : 0, null, null, null, null, now, now);
|
|
33
|
+
const row = db.prepare('SELECT * FROM products WHERE id = ?').get(id);
|
|
34
|
+
return rowToProduct(row);
|
|
35
|
+
}
|
|
36
|
+
async update(id, changes) {
|
|
37
|
+
const db = getDatabase();
|
|
38
|
+
const now = new Date().toISOString();
|
|
39
|
+
const sets = [];
|
|
40
|
+
const vals = [];
|
|
41
|
+
for (const [sdkKey, dbCol] of fieldMap) {
|
|
42
|
+
const v = changes[sdkKey];
|
|
43
|
+
if (v !== undefined) {
|
|
44
|
+
sets.push(`${dbCol} = ?`);
|
|
45
|
+
if (sdkKey === 'trackInventory' || sdkKey === 'allowSingleUnitSale') {
|
|
46
|
+
vals.push(v ? 1 : 0);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
vals.push(v);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
sets.push('updated_at = ?');
|
|
54
|
+
vals.push(now, id);
|
|
55
|
+
db.prepare(`UPDATE products SET ${sets.join(', ')} WHERE id = ?`).run(...vals);
|
|
56
|
+
const row = db.prepare('SELECT * FROM products WHERE id = ?').get(id);
|
|
57
|
+
return rowToProduct(row);
|
|
58
|
+
}
|
|
59
|
+
async softDelete(id) {
|
|
60
|
+
const db = getDatabase();
|
|
61
|
+
const now = new Date().toISOString();
|
|
62
|
+
db.prepare('UPDATE products SET deleted_at = ?, is_active = 0 WHERE id = ?')
|
|
63
|
+
.run(now, id);
|
|
64
|
+
}
|
|
65
|
+
async createCategory(data) {
|
|
66
|
+
const db = getDatabase();
|
|
67
|
+
const id = randomUUID();
|
|
68
|
+
const now = new Date().toISOString();
|
|
69
|
+
db.prepare(`
|
|
70
|
+
INSERT INTO categories (id, name, description, icon, color, display_order, is_active, created_at, updated_at)
|
|
71
|
+
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
72
|
+
`).run(id, data.name, data.description || null, data.icon || null, data.color || '#6366f1', data.displayOrder ?? 0, now, now);
|
|
73
|
+
const row = db.prepare('SELECT * FROM categories WHERE id = ?').get(id);
|
|
74
|
+
return rowToCategory(row);
|
|
75
|
+
}
|
|
76
|
+
async updateCategory(id, changes) {
|
|
77
|
+
const db = getDatabase();
|
|
78
|
+
const now = new Date().toISOString();
|
|
79
|
+
const catFieldMap = [
|
|
80
|
+
['name', 'name'], ['description', 'description'],
|
|
81
|
+
['icon', 'icon'], ['color', 'color'], ['displayOrder', 'display_order'],
|
|
82
|
+
];
|
|
83
|
+
const sets = [];
|
|
84
|
+
const vals = [];
|
|
85
|
+
for (const [sdkKey, dbCol] of catFieldMap) {
|
|
86
|
+
const v = changes[sdkKey];
|
|
87
|
+
if (v !== undefined) {
|
|
88
|
+
sets.push(`${dbCol} = ?`);
|
|
89
|
+
vals.push(v);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
sets.push('updated_at = ?');
|
|
93
|
+
vals.push(now, id);
|
|
94
|
+
db.prepare(`UPDATE categories SET ${sets.join(', ')} WHERE id = ?`).run(...vals);
|
|
95
|
+
const row = db.prepare('SELECT * FROM categories WHERE id = ?').get(id);
|
|
96
|
+
return rowToCategory(row);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=products-repository-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products-repository-write.js","sourceRoot":"","sources":["../src/products-repository-write.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Products repository — implements @soostori/products ProductRepository over Desktop products table.
|
|
3
|
+
*
|
|
4
|
+
* Broken into focused modules:
|
|
5
|
+
* products-repository-read — queries (findById, findMany, findByBarcode, categories)
|
|
6
|
+
* products-repository-write — mutations (create, update, softDelete, categories)
|
|
7
|
+
* products-repository-stock — stock adjustments (increment, decrement, set)
|
|
8
|
+
* products-repository-variants — variant CRUD
|
|
9
|
+
* products-repository-mappers — row→domain type converters
|
|
10
|
+
* products-repository-types — shared interfaces
|
|
11
|
+
*/
|
|
12
|
+
export type { ProductCreateInput, CategoryCreateInput, ProductVariant } from './products-repository-types.js';
|
|
13
|
+
export type { ProductId, CategoryId, ProductVariantId, ISO8601, Money } from './products-repository-types.js';
|
|
14
|
+
import { setCurrentMeta } from './products-repository-mappers.js';
|
|
15
|
+
import type { Product, Category } from '@soostori/core';
|
|
16
|
+
import type { ProductId, CategoryId } from './products-repository-types.js';
|
|
17
|
+
import type { ProductVariant } from './products-repository-types.js';
|
|
18
|
+
import type { UUID } from '@soostori/core';
|
|
19
|
+
export { setCurrentMeta };
|
|
20
|
+
export declare class ProductsRepository {
|
|
21
|
+
private read;
|
|
22
|
+
private write;
|
|
23
|
+
private stock;
|
|
24
|
+
private variants;
|
|
25
|
+
findById: (id: ProductId) => Promise<Product | null>;
|
|
26
|
+
findMany: (filter?: {
|
|
27
|
+
categoryId?: CategoryId;
|
|
28
|
+
search?: string;
|
|
29
|
+
activeOnly?: boolean;
|
|
30
|
+
}) => Promise<Product[]>;
|
|
31
|
+
findByBarcode: (barcode: string) => Promise<Product | null>;
|
|
32
|
+
findCategoryById: (id: CategoryId) => Promise<Category | null>;
|
|
33
|
+
findCategories: () => Promise<Category[]>;
|
|
34
|
+
create: (data: import("./products-repository-types.js").ProductCreateInput) => Promise<Product>;
|
|
35
|
+
update: (id: ProductId, changes: Partial<import("./products-repository-types.js").ProductCreateInput>) => Promise<Product>;
|
|
36
|
+
softDelete: (id: ProductId) => Promise<void>;
|
|
37
|
+
createCategory: (data: import("./products-repository-types.js").CategoryCreateInput) => Promise<Category>;
|
|
38
|
+
updateCategory: (id: CategoryId, changes: Partial<import("./products-repository-types.js").CategoryCreateInput>) => Promise<Category>;
|
|
39
|
+
/** Overridden to inject inventory ledger meta — called by SalesService.commit(). */
|
|
40
|
+
decrementStock(productId: ProductId, quantity: number): Promise<void>;
|
|
41
|
+
incrementStock: (productId: ProductId, quantity: number, meta?: {
|
|
42
|
+
reason?: string;
|
|
43
|
+
referenceId?: string;
|
|
44
|
+
userId?: string;
|
|
45
|
+
deviceId?: string;
|
|
46
|
+
shopId?: string;
|
|
47
|
+
}) => Promise<void>;
|
|
48
|
+
setStock: (productId: ProductId, newQuantity: number) => Promise<void>;
|
|
49
|
+
findVariants: (productId: ProductId) => Promise<ProductVariant[]>;
|
|
50
|
+
createVariant: (data: {
|
|
51
|
+
productId: import("@soostori/core").UUID;
|
|
52
|
+
name: string;
|
|
53
|
+
sku?: string | null;
|
|
54
|
+
barcode?: string | null;
|
|
55
|
+
costPrice?: import("@soostori/core").Money | null;
|
|
56
|
+
sellingPrice?: import("@soostori/core").Money | null;
|
|
57
|
+
stockQuantity?: number;
|
|
58
|
+
metadata?: Record<string, unknown> | null;
|
|
59
|
+
}) => Promise<ProductVariant>;
|
|
60
|
+
/** Set sale context before calling commit(). Used by the orchestrator. */
|
|
61
|
+
static setSaleMeta(meta: {
|
|
62
|
+
saleId?: string;
|
|
63
|
+
userId?: string;
|
|
64
|
+
deviceId?: string;
|
|
65
|
+
shopId?: string;
|
|
66
|
+
}): void;
|
|
67
|
+
private static _currentSaleMeta;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=products-repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products-repository.d.ts","sourceRoot":"","sources":["../src/products-repository.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC7G,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAA;AAM7G,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAE1C,OAAO,EAAE,cAAc,EAAE,CAAA;AAEzB,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,QAAQ,CAAkC;IAElD,QAAQ,6CAAqC;IAC7C,QAAQ;kBAnBa,CAAC;cAAuB,CAAC;kBAChD,CAAC;6BAkB8C;IAC7C,aAAa,+CAA0C;IACvD,gBAAgB,+CAA6C;IAC7D,cAAc,4BAA2C;IAEzD,MAAM,0FAAqC;IAC3C,MAAM,qHAAqC;IAC3C,UAAU,mCAAyC;IACnD,cAAc,4FAA6C;IAC3D,cAAc,wHAA6C;IAE3D,oFAAoF;IAC9E,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E,cAAc;cAAO,CAAC;mBAAqB,CAAC;cAC5C,CAAD;gBAAkB,CAAC;cAAgB,CAAC;wBADwB;IAC3D,QAAQ,+DAAuC;IAE/C,YAAY,sDAAiD;IAC7D,aAAa;;;WAvCE,CAAC;eAA2B,CAAC;iBAC1C,CAAC;oBAAwD,CAAC;qBAChB,CAAC;gBAAqB,CAAC;kCAqCJ;IAE/D,0EAA0E;IAC1E,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAKxG,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAK;CACrC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Products repository — implements @soostori/products ProductRepository over Desktop products table.
|
|
3
|
+
*
|
|
4
|
+
* Broken into focused modules:
|
|
5
|
+
* products-repository-read — queries (findById, findMany, findByBarcode, categories)
|
|
6
|
+
* products-repository-write — mutations (create, update, softDelete, categories)
|
|
7
|
+
* products-repository-stock — stock adjustments (increment, decrement, set)
|
|
8
|
+
* products-repository-variants — variant CRUD
|
|
9
|
+
* products-repository-mappers — row→domain type converters
|
|
10
|
+
* products-repository-types — shared interfaces
|
|
11
|
+
*/
|
|
12
|
+
import { ProductsReadRepository } from './products-repository-read.js';
|
|
13
|
+
import { ProductsWriteRepository } from './products-repository-write.js';
|
|
14
|
+
import { ProductsStockRepository } from './products-repository-stock.js';
|
|
15
|
+
import { ProductsVariantRepository } from './products-repository-variants.js';
|
|
16
|
+
import { setCurrentMeta } from './products-repository-mappers.js';
|
|
17
|
+
export { setCurrentMeta };
|
|
18
|
+
export class ProductsRepository {
|
|
19
|
+
read = new ProductsReadRepository();
|
|
20
|
+
write = new ProductsWriteRepository();
|
|
21
|
+
stock = new ProductsStockRepository();
|
|
22
|
+
variants = new ProductsVariantRepository();
|
|
23
|
+
findById = this.read.findById.bind(this.read);
|
|
24
|
+
findMany = this.read.findMany.bind(this.read);
|
|
25
|
+
findByBarcode = this.read.findByBarcode.bind(this.read);
|
|
26
|
+
findCategoryById = this.read.findCategoryById.bind(this.read);
|
|
27
|
+
findCategories = this.read.findCategories.bind(this.read);
|
|
28
|
+
create = this.write.create.bind(this.write);
|
|
29
|
+
update = this.write.update.bind(this.write);
|
|
30
|
+
softDelete = this.write.softDelete.bind(this.write);
|
|
31
|
+
createCategory = this.write.createCategory.bind(this.write);
|
|
32
|
+
updateCategory = this.write.updateCategory.bind(this.write);
|
|
33
|
+
/** Overridden to inject inventory ledger meta — called by SalesService.commit(). */
|
|
34
|
+
async decrementStock(productId, quantity) {
|
|
35
|
+
return this.stock.decrementStock(productId, quantity, ProductsRepository._currentSaleMeta);
|
|
36
|
+
}
|
|
37
|
+
incrementStock = this.stock.incrementStock.bind(this.stock);
|
|
38
|
+
setStock = this.stock.setStock.bind(this.stock);
|
|
39
|
+
findVariants = this.variants.findVariants.bind(this.variants);
|
|
40
|
+
createVariant = this.variants.createVariant.bind(this.variants);
|
|
41
|
+
/** Set sale context before calling commit(). Used by the orchestrator. */
|
|
42
|
+
static setSaleMeta(meta) {
|
|
43
|
+
ProductsRepository._currentSaleMeta = meta;
|
|
44
|
+
setCurrentMeta(meta);
|
|
45
|
+
}
|
|
46
|
+
static _currentSaleMeta = {};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=products-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products-repository.js","sourceRoot":"","sources":["../src/products-repository.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAMjE,OAAO,EAAE,cAAc,EAAE,CAAA;AAEzB,MAAM,OAAO,kBAAkB;IACrB,IAAI,GAAG,IAAI,sBAAsB,EAAE,CAAA;IACnC,KAAK,GAAG,IAAI,uBAAuB,EAAE,CAAA;IACrC,KAAK,GAAG,IAAI,uBAAuB,EAAE,CAAA;IACrC,QAAQ,GAAG,IAAI,yBAAyB,EAAE,CAAA;IAElD,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC7C,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC7C,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvD,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC7D,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEzD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC3C,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACnD,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC3D,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAE3D,oFAAoF;IACpF,KAAK,CAAC,cAAc,CAAC,SAAoB,EAAE,QAAgB;QACzD,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,EAAE,QAAQ,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,CAAA;IAC5F,CAAC;IAED,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC3D,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAE/C,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC7D,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAE/D,0EAA0E;IAC1E,MAAM,CAAC,WAAW,CAAC,IAA8E;QAC/F,kBAAkB,CAAC,gBAAgB,GAAG,IAAI,CAAA;QAC1C,cAAc,CAAC,IAAI,CAAC,CAAA;IACtB,CAAC;IAEO,MAAM,CAAC,gBAAgB,GAAG,EAAE,CAAA"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sales repository — implements SalesRepository contract over Desktop sales table.
|
|
3
|
+
*
|
|
4
|
+
* Desktop table: sales(id, shop_id, user_id, device_id, customer_id, customer_name,
|
|
5
|
+
* customer_phone, subtotal, discount_amount, tax_amount, total_amount, paid_amount,
|
|
6
|
+
* payment_method, type, status, note, created_at, updated_at)
|
|
7
|
+
*
|
|
8
|
+
* Desktop sale_items table: sale_items(id, sale_id, product_id, variation_name,
|
|
9
|
+
* product_name, quantity, unit_price, discount, total_price, created_at)
|
|
10
|
+
*
|
|
11
|
+
* Types match @soostori/sales canonical shapes exactly.
|
|
12
|
+
*/
|
|
13
|
+
import type { SaleId, ShopId, UserId, DeviceId, CustomerId, ISO8601, Money, UUID } from '@soostori/core';
|
|
14
|
+
export type SaleType = 'retail' | 'wholesale';
|
|
15
|
+
export type SaleStatus = 'pending' | 'confirmed' | 'rejected' | 'completed' | 'refunded' | 'cancelled';
|
|
16
|
+
export type PaymentMethod = 'cash' | 'mobile_money' | 'card' | 'transfer' | 'debt';
|
|
17
|
+
export interface Sale {
|
|
18
|
+
id: SaleId;
|
|
19
|
+
shopId: ShopId;
|
|
20
|
+
userId: UserId;
|
|
21
|
+
deviceId: DeviceId;
|
|
22
|
+
type: SaleType;
|
|
23
|
+
status: SaleStatus;
|
|
24
|
+
authorizedBy: UUID | null;
|
|
25
|
+
subtotal: Money;
|
|
26
|
+
discountAmount: Money;
|
|
27
|
+
taxAmount: Money;
|
|
28
|
+
totalAmount: Money;
|
|
29
|
+
paidAmount: Money;
|
|
30
|
+
paymentMethod: PaymentMethod;
|
|
31
|
+
note: string | null;
|
|
32
|
+
customerId: CustomerId | null;
|
|
33
|
+
customerName: string | null;
|
|
34
|
+
customerIdNumber: string | null;
|
|
35
|
+
itemsSummary: string | null;
|
|
36
|
+
createdAt: ISO8601;
|
|
37
|
+
updatedAt: ISO8601;
|
|
38
|
+
confirmedAt: ISO8601 | null;
|
|
39
|
+
}
|
|
40
|
+
export interface SaleItem {
|
|
41
|
+
id: SaleId;
|
|
42
|
+
saleId: SaleId;
|
|
43
|
+
productId: UUID | null;
|
|
44
|
+
productName: string;
|
|
45
|
+
variationName: string | null;
|
|
46
|
+
quantity: number;
|
|
47
|
+
unitPrice: Money;
|
|
48
|
+
discount: Money;
|
|
49
|
+
totalPrice: Money;
|
|
50
|
+
}
|
|
51
|
+
export interface HeldSale {
|
|
52
|
+
id: UUID;
|
|
53
|
+
shopId: ShopId;
|
|
54
|
+
name: string | null;
|
|
55
|
+
cartItems: string;
|
|
56
|
+
paymentMethod: PaymentMethod;
|
|
57
|
+
createdAt: ISO8601;
|
|
58
|
+
userId: UserId;
|
|
59
|
+
}
|
|
60
|
+
export declare class DesktopSalesRepository {
|
|
61
|
+
private tableName;
|
|
62
|
+
findById(id: SaleId): Promise<Sale | null>;
|
|
63
|
+
findMany(filter?: {
|
|
64
|
+
status?: Sale['status'];
|
|
65
|
+
startDate?: ISO8601;
|
|
66
|
+
endDate?: ISO8601;
|
|
67
|
+
customerId?: string;
|
|
68
|
+
userId?: string;
|
|
69
|
+
deviceId?: string;
|
|
70
|
+
paymentMethod?: Sale['paymentMethod'];
|
|
71
|
+
}): Promise<Sale[]>;
|
|
72
|
+
create(sale: Sale, items: SaleItem[]): Promise<Sale>;
|
|
73
|
+
update(id: SaleId, changes: Partial<Sale>): Promise<Sale>;
|
|
74
|
+
findItemsBySaleId(saleId: SaleId): Promise<SaleItem[]>;
|
|
75
|
+
findHeldSales(_shopId: ShopId): Promise<HeldSale[]>;
|
|
76
|
+
createHeldSale(data: {
|
|
77
|
+
id: UUID;
|
|
78
|
+
shopId: ShopId;
|
|
79
|
+
name: string | null;
|
|
80
|
+
cartItems: string;
|
|
81
|
+
paymentMethod: PaymentMethod;
|
|
82
|
+
userId: UserId;
|
|
83
|
+
}): Promise<HeldSale>;
|
|
84
|
+
deleteHeldSale(id: UUID): Promise<void>;
|
|
85
|
+
totals(_filter?: {
|
|
86
|
+
status?: Sale['status'];
|
|
87
|
+
startDate?: ISO8601;
|
|
88
|
+
endDate?: ISO8601;
|
|
89
|
+
}): Promise<{
|
|
90
|
+
count: number;
|
|
91
|
+
total: Money;
|
|
92
|
+
byPaymentMethod: Record<string, Money>;
|
|
93
|
+
}>;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=sales-repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sales-repository.d.ts","sourceRoot":"","sources":["../src/sales-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sales repository — implements SalesRepository contract over Desktop sales table.
|
|
3
|
+
*
|
|
4
|
+
* Desktop table: sales(id, shop_id, user_id, device_id, customer_id, customer_name,
|
|
5
|
+
* customer_phone, subtotal, discount_amount, tax_amount, total_amount, paid_amount,
|
|
6
|
+
* payment_method, type, status, note, created_at, updated_at)
|
|
7
|
+
*
|
|
8
|
+
* Desktop sale_items table: sale_items(id, sale_id, product_id, variation_name,
|
|
9
|
+
* product_name, quantity, unit_price, discount, total_price, created_at)
|
|
10
|
+
*
|
|
11
|
+
* Types match @soostori/sales canonical shapes exactly.
|
|
12
|
+
*/
|
|
13
|
+
import { getDatabase } from './sqlite-database.js';
|
|
14
|
+
import { asSaleId, asShopId } from '@soostori/core';
|
|
15
|
+
// ── Row mappers ──────────────────────────────────────────────────────────
|
|
16
|
+
function rowToSale(row) {
|
|
17
|
+
return {
|
|
18
|
+
id: asSaleId(row.id),
|
|
19
|
+
shopId: asShopId(row.shop_id),
|
|
20
|
+
userId: row.user_id,
|
|
21
|
+
deviceId: row.device_id,
|
|
22
|
+
type: row.type,
|
|
23
|
+
status: row.status,
|
|
24
|
+
authorizedBy: null,
|
|
25
|
+
subtotal: row.subtotal,
|
|
26
|
+
discountAmount: row.discount_amount,
|
|
27
|
+
taxAmount: row.tax_amount,
|
|
28
|
+
totalAmount: row.total_amount,
|
|
29
|
+
paidAmount: row.paid_amount,
|
|
30
|
+
paymentMethod: row.payment_method,
|
|
31
|
+
note: row.note ?? null,
|
|
32
|
+
customerId: (row.customer_id ?? null),
|
|
33
|
+
customerName: row.customer_name ?? null,
|
|
34
|
+
customerIdNumber: row.customer_phone ?? null,
|
|
35
|
+
itemsSummary: null,
|
|
36
|
+
createdAt: row.created_at,
|
|
37
|
+
updatedAt: row.updated_at,
|
|
38
|
+
confirmedAt: null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// ── Repository implementation ───────────────────────────────────────────────
|
|
42
|
+
export class DesktopSalesRepository {
|
|
43
|
+
tableName = 'sales';
|
|
44
|
+
async findById(id) {
|
|
45
|
+
const row = getDatabase()
|
|
46
|
+
.prepare(`SELECT * FROM ${this.tableName} WHERE id = ?`)
|
|
47
|
+
.get(id);
|
|
48
|
+
return row ? rowToSale(row) : null;
|
|
49
|
+
}
|
|
50
|
+
async findMany(filter) {
|
|
51
|
+
const db = getDatabase();
|
|
52
|
+
const conditions = [];
|
|
53
|
+
const values = [];
|
|
54
|
+
if (filter?.status) {
|
|
55
|
+
conditions.push('status = ?');
|
|
56
|
+
values.push(filter.status);
|
|
57
|
+
}
|
|
58
|
+
if (filter?.userId) {
|
|
59
|
+
conditions.push('user_id = ?');
|
|
60
|
+
values.push(filter.userId);
|
|
61
|
+
}
|
|
62
|
+
if (filter?.deviceId) {
|
|
63
|
+
conditions.push('device_id = ?');
|
|
64
|
+
values.push(filter.deviceId);
|
|
65
|
+
}
|
|
66
|
+
if (filter?.paymentMethod) {
|
|
67
|
+
conditions.push('payment_method = ?');
|
|
68
|
+
values.push(filter.paymentMethod);
|
|
69
|
+
}
|
|
70
|
+
if (filter?.startDate) {
|
|
71
|
+
conditions.push('created_at >= ?');
|
|
72
|
+
values.push(filter.startDate);
|
|
73
|
+
}
|
|
74
|
+
if (filter?.endDate) {
|
|
75
|
+
conditions.push('created_at <= ?');
|
|
76
|
+
values.push(filter.endDate);
|
|
77
|
+
}
|
|
78
|
+
const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
79
|
+
const rows = db.prepare(`SELECT * FROM ${this.tableName} ${where} ORDER BY created_at DESC`)
|
|
80
|
+
.all(...values);
|
|
81
|
+
return rows.map(rowToSale);
|
|
82
|
+
}
|
|
83
|
+
async create(sale, items) {
|
|
84
|
+
// Idempotent: if this saleId already exists, return it without re-inserting.
|
|
85
|
+
const existing = await this.findById(sale.id);
|
|
86
|
+
if (existing)
|
|
87
|
+
return existing;
|
|
88
|
+
const db = getDatabase();
|
|
89
|
+
const now = new Date().toISOString();
|
|
90
|
+
db.prepare(`
|
|
91
|
+
INSERT INTO sales (id, shop_id, user_id, device_id, customer_id, customer_name, customer_phone,
|
|
92
|
+
subtotal, discount_amount, tax_amount, total_amount, paid_amount, payment_method, type, status,
|
|
93
|
+
note, created_at, updated_at)
|
|
94
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
95
|
+
`).run(sale.id, sale.shopId, sale.userId, sale.deviceId, sale.customerId, sale.customerName, null, sale.subtotal, sale.discountAmount, sale.taxAmount, sale.totalAmount, sale.paidAmount, sale.paymentMethod, sale.type, sale.status, sale.note, sale.createdAt ?? now, sale.updatedAt ?? now);
|
|
96
|
+
const insertItem = db.prepare(`
|
|
97
|
+
INSERT INTO sale_items (id, sale_id, product_id, variation_name, product_name, quantity, unit_price, discount, total_price, shop_id, created_at)
|
|
98
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
99
|
+
`);
|
|
100
|
+
for (const item of items) {
|
|
101
|
+
insertItem.run(item.id, sale.id, item.productId, item.variationName, item.productName, item.quantity, item.unitPrice, item.discount, item.totalPrice, sale.shopId, now);
|
|
102
|
+
}
|
|
103
|
+
return sale;
|
|
104
|
+
}
|
|
105
|
+
async update(id, changes) {
|
|
106
|
+
const db = getDatabase();
|
|
107
|
+
const fields = Object.keys(changes);
|
|
108
|
+
const vals = fields.map(k => changes[k]);
|
|
109
|
+
const setClause = fields.map(f => `${f} = ?`).join(', ');
|
|
110
|
+
db.prepare(`UPDATE ${this.tableName} SET ${setClause}, updated_at = ? WHERE id = ?`)
|
|
111
|
+
.run(...vals, new Date().toISOString(), id);
|
|
112
|
+
return (await this.findById(id));
|
|
113
|
+
}
|
|
114
|
+
async findItemsBySaleId(saleId) {
|
|
115
|
+
const rows = getDatabase()
|
|
116
|
+
.prepare('SELECT * FROM sale_items WHERE sale_id = ?')
|
|
117
|
+
.all(saleId);
|
|
118
|
+
return rows.map(r => ({
|
|
119
|
+
id: asSaleId(r.id),
|
|
120
|
+
saleId: asSaleId(r.sale_id),
|
|
121
|
+
productId: (r.product_id ?? null),
|
|
122
|
+
productName: r.product_name,
|
|
123
|
+
variationName: r.variation_name ?? null,
|
|
124
|
+
quantity: r.quantity,
|
|
125
|
+
unitPrice: r.unit_price,
|
|
126
|
+
discount: r.discount,
|
|
127
|
+
totalPrice: r.total_price,
|
|
128
|
+
}));
|
|
129
|
+
}
|
|
130
|
+
async findHeldSales(_shopId) {
|
|
131
|
+
const rows = getDatabase()
|
|
132
|
+
.prepare('SELECT * FROM held_sales ORDER BY created_at DESC')
|
|
133
|
+
.all();
|
|
134
|
+
return rows.map(r => ({
|
|
135
|
+
id: r.id,
|
|
136
|
+
shopId: r.shop_id,
|
|
137
|
+
name: r.name,
|
|
138
|
+
cartItems: r.cart_items,
|
|
139
|
+
paymentMethod: r.payment_method,
|
|
140
|
+
createdAt: r.created_at,
|
|
141
|
+
userId: r.user_id,
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
async createHeldSale(data) {
|
|
145
|
+
const db = getDatabase();
|
|
146
|
+
const now = new Date().toISOString();
|
|
147
|
+
db.prepare(`
|
|
148
|
+
INSERT INTO held_sales (id, shop_id, name, cart_items, payment_method, user_id, created_at)
|
|
149
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
150
|
+
`).run(data.id, data.shopId, data.name ?? null, data.cartItems, data.paymentMethod, data.userId, now);
|
|
151
|
+
return { ...data, createdAt: now };
|
|
152
|
+
}
|
|
153
|
+
async deleteHeldSale(id) {
|
|
154
|
+
getDatabase().prepare('DELETE FROM held_sales WHERE id = ?').run(id);
|
|
155
|
+
}
|
|
156
|
+
async totals(_filter) {
|
|
157
|
+
return { count: 0, total: 0, byPaymentMethod: {} };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=sales-repository.js.map
|