@mxpicture/tesla-superchargers-api 0.1.3 → 0.1.5
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/api/ChargersApi.d.ts +1 -1
- package/dist/api/ChargersApi.d.ts.map +1 -1
- package/dist/api/ChargersApi.js +6 -17
- package/dist/api/ChargersApi.js.map +1 -1
- package/dist/api/InvoicesApi.d.ts +27 -0
- package/dist/api/InvoicesApi.d.ts.map +1 -0
- package/dist/api/InvoicesApi.js +94 -0
- package/dist/api/InvoicesApi.js.map +1 -0
- package/dist/api/SlugsApi.d.ts +1 -1
- package/dist/api/SlugsApi.d.ts.map +1 -1
- package/dist/api/SlugsApi.js +4 -15
- package/dist/api/SlugsApi.js.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -0
- package/dist/api/index.js.map +1 -1
- package/dist/common/index.d.ts +1 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +1 -0
- package/dist/common/index.js.map +1 -1
- package/dist/common/invoicesCsv.common.d.ts +87 -0
- package/dist/common/invoicesCsv.common.d.ts.map +1 -0
- package/dist/common/invoicesCsv.common.js +193 -0
- package/dist/common/invoicesCsv.common.js.map +1 -0
- package/dist/common/sync.common.d.ts +1 -48
- package/dist/common/sync.common.d.ts.map +1 -1
- package/dist/common/sync.common.js +1 -97
- package/dist/common/sync.common.js.map +1 -1
- package/dist/sync/ChargersSync.d.ts +13 -0
- package/dist/sync/ChargersSync.d.ts.map +1 -0
- package/dist/sync/ChargersSync.js +25 -0
- package/dist/sync/ChargersSync.js.map +1 -0
- package/dist/sync/ISyncHandler.d.ts +40 -0
- package/dist/sync/ISyncHandler.d.ts.map +1 -0
- package/dist/sync/ISyncHandler.js +67 -0
- package/dist/sync/ISyncHandler.js.map +1 -0
- package/dist/sync/ISyncPlanHandler.d.ts +25 -0
- package/dist/sync/ISyncPlanHandler.d.ts.map +1 -0
- package/dist/sync/ISyncPlanHandler.js +62 -0
- package/dist/sync/ISyncPlanHandler.js.map +1 -0
- package/dist/sync/InvoicesSync.d.ts +8 -0
- package/dist/sync/InvoicesSync.d.ts.map +1 -0
- package/dist/sync/InvoicesSync.js +21 -0
- package/dist/sync/InvoicesSync.js.map +1 -0
- package/dist/sync/SlugsSync.d.ts +9 -0
- package/dist/sync/SlugsSync.d.ts.map +1 -0
- package/dist/sync/SlugsSync.js +18 -0
- package/dist/sync/SlugsSync.js.map +1 -0
- package/dist/sync/index.d.ts +6 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +7 -0
- package/dist/sync/index.js.map +1 -0
- package/package.json +11 -4
|
@@ -47,7 +47,7 @@ export declare class ChargersApi extends IApi {
|
|
|
47
47
|
syncLoad(slug: string, locale: string, slugsId?: PicSlugsId): Promise<PicChargers>;
|
|
48
48
|
/** Snapshot sync from a full-feed file dump. Does not touch pricebooks. */
|
|
49
49
|
syncLoadFile(path: string): Promise<SyncSummary>;
|
|
50
|
-
protected _syncLoad(
|
|
50
|
+
protected _syncLoad(docs: TeslaClientCharger[]): Promise<SyncSummary>;
|
|
51
51
|
}
|
|
52
52
|
export declare const chargersApi: () => ChargersApi;
|
|
53
53
|
//# sourceMappingURL=ChargersApi.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChargersApi.d.ts","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"AAOA,OAAO,
|
|
1
|
+
{"version":3,"file":"ChargersApi.d.ts","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,UAAU,EAChB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,4CAA4C,CAAC;AAOpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAOhF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAO1D,qBAAa,WAAY,SAAQ,IAAI;IACnC;;;;;;;;;;OAUG;IACU,IAAI,CACf,IAAI,EAAE,aAAa,EACnB,MAAM,GAAE,MAAgB,GACvB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA8D9B;;;;;;;;;;;;;;;OAeG;IACU,UAAU,CACrB,IAAI,EAAE,aAAa,EACnB,EAAE,EAAE,IAAI,GACP,OAAO,CAAC,aAAa,EAAE,CAAC;IAmBd,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzD;;;;;;;;;OASG;IACU,QAAQ,CACnB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,WAAW,CAAC;IAgDvB,2EAA2E;IAC9D,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;cAK7C,SAAS,CAAC,IAAI,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;CAK5E;AAGD,eAAO,MAAM,WAAW,mBAAqC,CAAC"}
|
package/dist/api/ChargersApi.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createMeta, chargerToInitializer, pricebookToInitializer, } from "@mxpicture/tesla-superchargers-mate/transform";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import json5 from "json5";
|
|
4
|
-
import {
|
|
4
|
+
import {} from "@mxpicture/tesla-superchargers-generated/public";
|
|
5
5
|
import { teslaClient, teslaClientChargersSchema, } from "@mxpicture/tesla-superchargers-mate/client";
|
|
6
6
|
import { picChargersStore, picPricebooksStore, picSlugsStore, transaction, } from "@mxpicture/tesla-superchargers-mate/store";
|
|
7
|
-
import { FAILURE_DEPRIORITIZE_THRESHOLD, isFresh, MAX_CHARGER_FETCHES,
|
|
7
|
+
import { FAILURE_DEPRIORITIZE_THRESHOLD, isFresh, MAX_CHARGER_FETCHES, } from "../common/chargers.common.js";
|
|
8
8
|
import { IApi } from "./IApi.js";
|
|
9
|
-
import { syncColumns, syncSnapshot } from "../common/sync.common.js";
|
|
10
9
|
import { pricebookCoversInstant, samePricebookGroup, } from "../common/pricebooks.common.js";
|
|
10
|
+
import { ChargersSync } from "../sync/ChargersSync.js";
|
|
11
11
|
export class ChargersApi extends IApi {
|
|
12
12
|
/**
|
|
13
13
|
* Find the Supercharger at a coordinate: try the nearby slug rows
|
|
@@ -151,21 +151,10 @@ export class ChargersApi extends IApi {
|
|
|
151
151
|
const json = json5.parse(await readFile(path, { encoding: "utf8" }));
|
|
152
152
|
return await this._syncLoad(teslaClientChargersSchema.parse(json));
|
|
153
153
|
}
|
|
154
|
-
async _syncLoad(
|
|
154
|
+
async _syncLoad(docs) {
|
|
155
155
|
const meta = createMeta();
|
|
156
|
-
const
|
|
157
|
-
return await
|
|
158
|
-
store: picChargersStore(),
|
|
159
|
-
clientDocs,
|
|
160
|
-
meta,
|
|
161
|
-
toInitializer: (charger) => chargerToInitializer({ charger, meta }),
|
|
162
|
-
keyOfInit: (doc) => doc.location_guid,
|
|
163
|
-
keyOfDb: (doc) => doc.location_guid,
|
|
164
|
-
deleteAbsent: "soft",
|
|
165
|
-
conflictColumn: "location_guid",
|
|
166
|
-
compareColumns: withoutFkColumns(compareColumns),
|
|
167
|
-
updateColumns: withoutFkColumns(updateColumns),
|
|
168
|
-
});
|
|
156
|
+
const sync = new ChargersSync();
|
|
157
|
+
return await sync.snapshot({ docs, meta });
|
|
169
158
|
}
|
|
170
159
|
}
|
|
171
160
|
let _api = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChargersApi.js","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,
|
|
1
|
+
{"version":3,"file":"ChargersApi.js","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type InvoicesCsv } from "../common/invoicesCsv.common.js";
|
|
2
|
+
import { IApi } from "./IApi.js";
|
|
3
|
+
import type { SyncSummary } from "../types/sync.types.js";
|
|
4
|
+
import type { Meta } from "@mxpicture/tesla-superchargers-mate/types";
|
|
5
|
+
import type { DropboxClient } from "@mxpicture/tesla-superchargers-cloud-store/client";
|
|
6
|
+
import type { DropboxEntry } from "@mxpicture/tesla-superchargers-cloud-store/types";
|
|
7
|
+
export declare class InvoicesApi extends IApi {
|
|
8
|
+
syncDropbox(): Promise<SyncSummary>;
|
|
9
|
+
/**
|
|
10
|
+
* Sync one dropbox entry: non-CSV entries and files already recorded in
|
|
11
|
+
* `pic_invoice_files` are skipped. A file is recorded only after all its
|
|
12
|
+
* rows landed — a failed file is logged and retried on the next run.
|
|
13
|
+
*/
|
|
14
|
+
protected syncDropboxEntry(entry: DropboxEntry, client: DropboxClient, meta: Meta, storedNames: Set<string>): Promise<SyncSummary | null>;
|
|
15
|
+
/**
|
|
16
|
+
* Throws when any row fails validation, before touching the db — a file is
|
|
17
|
+
* imported completely or not at all, so a file recorded as synced never
|
|
18
|
+
* hides silently dropped rows. The exception are credit/free charges
|
|
19
|
+
* without an invoice number: they cannot be keyed, so they are skipped and
|
|
20
|
+
* reported via `feedNullKeys` instead of failing the file.
|
|
21
|
+
*/
|
|
22
|
+
syncCsv(csvText: string): Promise<SyncSummary>;
|
|
23
|
+
syncCsvFile(path: string): Promise<SyncSummary>;
|
|
24
|
+
protected _syncLoad(csvs: InvoicesCsv[]): Promise<SyncSummary>;
|
|
25
|
+
}
|
|
26
|
+
export declare const invoicesApi: () => InvoicesApi;
|
|
27
|
+
//# sourceMappingURL=InvoicesApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvoicesApi.d.ts","sourceRoot":"","sources":["../../src/api/InvoicesApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAO1D,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,2CAA2C,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mDAAmD,CAAC;AAEvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kDAAkD,CAAC;AAErF,qBAAa,WAAY,SAAQ,IAAI;IACtB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;IAqChD;;;;OAIG;cACa,gBAAgB,CAC9B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,GACvB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAmB9B;;;;;;OAMG;IACU,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAc9C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;cAI5C,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;CAmBrE;AAGD,eAAO,MAAM,WAAW,mBAAqC,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { formatInvoicesCsvErrors, fromInvoiceCsv, parseInvoicesCsv, } from "../common/invoicesCsv.common.js";
|
|
2
|
+
import { IApi } from "./IApi.js";
|
|
3
|
+
import { createMeta } from "@mxpicture/tesla-superchargers-mate/transform";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { InvoicesSync } from "../sync/InvoicesSync.js";
|
|
6
|
+
import { chargingProcessesStore, picInvoiceFilesStore, } from "@mxpicture/tesla-superchargers-mate/store";
|
|
7
|
+
import { dropboxClientByEnv } from "@mxpicture/tesla-superchargers-cloud-store/client";
|
|
8
|
+
export class InvoicesApi extends IApi {
|
|
9
|
+
async syncDropbox() {
|
|
10
|
+
const client = dropboxClientByEnv();
|
|
11
|
+
const entries = await client.fetchBaseDir();
|
|
12
|
+
const meta = createMeta();
|
|
13
|
+
const storedNames = new Set((await picInvoiceFilesStore().query()).map((file) => file.name.toLowerCase()));
|
|
14
|
+
const summary = {
|
|
15
|
+
feedCount: 0,
|
|
16
|
+
feedDuplicates: 0,
|
|
17
|
+
feedNullKeys: 0,
|
|
18
|
+
upserted: 0,
|
|
19
|
+
deleted: 0,
|
|
20
|
+
};
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
const subSummary = await this.syncDropboxEntry(entry, client, meta, storedNames);
|
|
23
|
+
if (subSummary) {
|
|
24
|
+
summary.feedCount += subSummary.feedCount;
|
|
25
|
+
summary.feedDuplicates += subSummary.feedDuplicates;
|
|
26
|
+
summary.feedNullKeys += subSummary.feedNullKeys;
|
|
27
|
+
summary.upserted += subSummary.upserted;
|
|
28
|
+
summary.deleted += subSummary.deleted;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return summary;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Sync one dropbox entry: non-CSV entries and files already recorded in
|
|
35
|
+
* `pic_invoice_files` are skipped. A file is recorded only after all its
|
|
36
|
+
* rows landed — a failed file is logged and retried on the next run.
|
|
37
|
+
*/
|
|
38
|
+
async syncDropboxEntry(entry, client, meta, storedNames) {
|
|
39
|
+
const nameLower = entry.name.toLowerCase();
|
|
40
|
+
if (!nameLower.endsWith(".csv"))
|
|
41
|
+
return null;
|
|
42
|
+
if (storedNames.has(nameLower))
|
|
43
|
+
return null;
|
|
44
|
+
try {
|
|
45
|
+
const file = await client.fetchFile(entry.path);
|
|
46
|
+
const summary = await this.syncCsv(file.content);
|
|
47
|
+
await picInvoiceFilesStore().insert({ ...meta, name: entry.name });
|
|
48
|
+
storedNames.add(nameLower);
|
|
49
|
+
return summary;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.warn(`invoices dropbox: sync of "${entry.name}" failed:`, error);
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Throws when any row fails validation, before touching the db — a file is
|
|
58
|
+
* imported completely or not at all, so a file recorded as synced never
|
|
59
|
+
* hides silently dropped rows. The exception are credit/free charges
|
|
60
|
+
* without an invoice number: they cannot be keyed, so they are skipped and
|
|
61
|
+
* reported via `feedNullKeys` instead of failing the file.
|
|
62
|
+
*/
|
|
63
|
+
async syncCsv(csvText) {
|
|
64
|
+
const { invoices, errors, nullInvoiceNumbers } = parseInvoicesCsv(csvText);
|
|
65
|
+
if (errors.length > 0)
|
|
66
|
+
throw new Error(`invoices CSV: ${errors.length} invalid row(s)\n` +
|
|
67
|
+
formatInvoicesCsvErrors(errors));
|
|
68
|
+
const summary = await this._syncLoad(invoices);
|
|
69
|
+
// skipped pre-parse, so mirror the plan's null-key accounting
|
|
70
|
+
summary.feedCount += nullInvoiceNumbers;
|
|
71
|
+
summary.feedNullKeys += nullInvoiceNumbers;
|
|
72
|
+
return summary;
|
|
73
|
+
}
|
|
74
|
+
async syncCsvFile(path) {
|
|
75
|
+
return await this.syncCsv(await readFile(path, { encoding: "utf8" }));
|
|
76
|
+
}
|
|
77
|
+
async _syncLoad(csvs) {
|
|
78
|
+
const cp = chargingProcessesStore();
|
|
79
|
+
const meta = createMeta();
|
|
80
|
+
const docs = [];
|
|
81
|
+
for (const csv of csvs) {
|
|
82
|
+
const chargingProcessesId = await cp.lookupChargingProcessId(csv.Vin, csv.ChargeStartDateTime);
|
|
83
|
+
docs.push({ ...fromInvoiceCsv({ csv, meta }), chargingProcessesId });
|
|
84
|
+
}
|
|
85
|
+
const sync = new InvoicesSync();
|
|
86
|
+
return await sync.snapshot({
|
|
87
|
+
docs,
|
|
88
|
+
meta,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
let _api = null;
|
|
93
|
+
export const invoicesApi = () => (_api ??= new InvoicesApi());
|
|
94
|
+
//# sourceMappingURL=InvoicesApi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InvoicesApi.js","sourceRoot":"","sources":["../../src/api/InvoicesApi.ts"],"names":[],"mappings":"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"}
|
package/dist/api/SlugsApi.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare class SlugsApi extends IApi {
|
|
|
9
9
|
initialLoadFile(path: string): Promise<SyncSummary>;
|
|
10
10
|
syncLoad(): Promise<SyncSummary>;
|
|
11
11
|
syncLoadFile(path: string): Promise<SyncSummary>;
|
|
12
|
-
protected _syncLoad(
|
|
12
|
+
protected _syncLoad(docs: TeslaClientSlug[]): Promise<SyncSummary>;
|
|
13
13
|
}
|
|
14
14
|
export declare const slugsApi: () => SlugsApi;
|
|
15
15
|
//# sourceMappingURL=SlugsApi.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlugsApi.d.ts","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SlugsApi.d.ts","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAY1D,qBAAa,QAAS,SAAQ,IAAI;IACnB,IAAI,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAItD,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;IAgBnC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBnD,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;IAKhC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;cAI7C,SAAS,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;CAKzE;AAGD,eAAO,MAAM,QAAQ,gBAAkC,CAAC"}
|
package/dist/api/SlugsApi.js
CHANGED
|
@@ -2,10 +2,9 @@ import { parseTeslaClientSlugs, teslaClient, } from "@mxpicture/tesla-supercharg
|
|
|
2
2
|
import { createMeta, slugToInitializer, } from "@mxpicture/tesla-superchargers-mate/transform";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import json5 from "json5";
|
|
5
|
-
import { picSlugsInitializerKeys } from "@mxpicture/tesla-superchargers-generated/public";
|
|
6
5
|
import { picSlugsStore } from "@mxpicture/tesla-superchargers-mate/store";
|
|
7
6
|
import { IApi } from "./IApi.js";
|
|
8
|
-
import {
|
|
7
|
+
import { SlugsSync } from "../sync/SlugsSync.js";
|
|
9
8
|
/** Per-element parse of a slugs file dump; invalid entries are skipped, not fatal. */
|
|
10
9
|
const readSlugsFile = async (path) => {
|
|
11
10
|
const json = json5.parse(await readFile(path, { encoding: "utf8" }));
|
|
@@ -47,20 +46,10 @@ export class SlugsApi extends IApi {
|
|
|
47
46
|
async syncLoadFile(path) {
|
|
48
47
|
return await this._syncLoad(await readSlugsFile(path));
|
|
49
48
|
}
|
|
50
|
-
async _syncLoad(
|
|
49
|
+
async _syncLoad(docs) {
|
|
51
50
|
const meta = createMeta();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
clientDocs,
|
|
55
|
-
meta,
|
|
56
|
-
toInitializer: (slug) => slugToInitializer({ slug, meta }),
|
|
57
|
-
keyOfInit: (doc) => doc.tesla_uuid ?? null,
|
|
58
|
-
keyOfDb: (doc) => doc.tesla_uuid,
|
|
59
|
-
// the table mirrors the feed: rows absent from it are hard-deleted
|
|
60
|
-
deleteAbsent: "hard",
|
|
61
|
-
conflictColumn: "tesla_uuid",
|
|
62
|
-
...syncColumns(picSlugsInitializerKeys),
|
|
63
|
-
});
|
|
51
|
+
const sync = new SlugsSync();
|
|
52
|
+
return await sync.snapshot({ docs, meta });
|
|
64
53
|
}
|
|
65
54
|
}
|
|
66
55
|
let _api = null;
|
package/dist/api/SlugsApi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlugsApi.js","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,WAAW,GACZ,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACL,UAAU,EACV,iBAAiB,GAClB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"SlugsApi.js","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"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"}
|
package/dist/api/index.d.ts
CHANGED
package/dist/api/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC"}
|
package/dist/api/index.js
CHANGED
package/dist/api/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC"}
|
package/dist/common/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
|
package/dist/common/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// This file is auto-generated by build-cli. Do not edit manually.
|
|
2
2
|
export * from "./chargers.common.js";
|
|
3
3
|
export * from "./failures.common.js";
|
|
4
|
+
export * from "./invoicesCsv.common.js";
|
|
4
5
|
export * from "./pricebooks.common.js";
|
|
5
6
|
export * from "./pushover.common.js";
|
|
6
7
|
export * from "./sync.common.js";
|
package/dist/common/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tesla charging-CSV import for pic_invoices.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline: raw CSV string
|
|
5
|
+
* → csv-parse (structure: delimiters, quoting, headers)
|
|
6
|
+
* → zod row schema (semantics: "N/A" → null, "22.1285 kwh" → value+unit,
|
|
7
|
+
* "0.51/kwh" → value+unit, NUMERIC precision checks, ISO dates)
|
|
8
|
+
* → PicInvoicesInitializer
|
|
9
|
+
* → parameterized INSERT (numerics stay strings; pg casts to NUMERIC losslessly)
|
|
10
|
+
*
|
|
11
|
+
* deps: npm i csv-parse postgres zod
|
|
12
|
+
*/
|
|
13
|
+
import type { Invoice, Meta } from "@mxpicture/tesla-superchargers-mate/types";
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
export declare const invoicesCsvSchema: z.ZodObject<{
|
|
16
|
+
ChargeStartDateTime: z.ZodPipe<z.ZodString, z.ZodTransform<Date, string>>;
|
|
17
|
+
Name: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
18
|
+
Vin: z.ZodString;
|
|
19
|
+
Model: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
20
|
+
Country: z.ZodString;
|
|
21
|
+
SiteLocationName: z.ZodString;
|
|
22
|
+
Description: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
23
|
+
QuantityBase: z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
24
|
+
value: number;
|
|
25
|
+
unit: string;
|
|
26
|
+
}, string>>;
|
|
27
|
+
QuantityTier1: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
28
|
+
value: number;
|
|
29
|
+
unit: string;
|
|
30
|
+
}, string>>>>;
|
|
31
|
+
QuantityTier2: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
32
|
+
value: number;
|
|
33
|
+
unit: string;
|
|
34
|
+
}, string>>>>;
|
|
35
|
+
QuantityTier3: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
36
|
+
value: number;
|
|
37
|
+
unit: string;
|
|
38
|
+
}, string>>>>;
|
|
39
|
+
QuantityTier4: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
40
|
+
value: number;
|
|
41
|
+
unit: string;
|
|
42
|
+
}, string>>>>;
|
|
43
|
+
InvoiceNumber: z.ZodString;
|
|
44
|
+
UnitCostBase: z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
45
|
+
value: number;
|
|
46
|
+
unit: string;
|
|
47
|
+
}, string>>;
|
|
48
|
+
UnitCostTier1: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
49
|
+
value: number;
|
|
50
|
+
unit: string;
|
|
51
|
+
}, string>>>>;
|
|
52
|
+
UnitCostTier2: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
53
|
+
value: number;
|
|
54
|
+
unit: string;
|
|
55
|
+
}, string>>>>;
|
|
56
|
+
UnitCostTier3: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
57
|
+
value: number;
|
|
58
|
+
unit: string;
|
|
59
|
+
}, string>>>>;
|
|
60
|
+
UnitCostTier4: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
61
|
+
value: number;
|
|
62
|
+
unit: string;
|
|
63
|
+
}, string>>>>;
|
|
64
|
+
VAT: z.ZodString;
|
|
65
|
+
"Total Exc. VAT": z.ZodString;
|
|
66
|
+
"Total Inc. VAT": z.ZodString;
|
|
67
|
+
Status: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
68
|
+
Invoice: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
69
|
+
}, z.core.$strip>;
|
|
70
|
+
export type InvoicesCsv = z.infer<typeof invoicesCsvSchema>;
|
|
71
|
+
export interface InvoicesCsvError {
|
|
72
|
+
line: number;
|
|
73
|
+
issues: z.core.$ZodIssue[];
|
|
74
|
+
}
|
|
75
|
+
/** One line per invalid row: `line 3: QuantityBase: invalid quantity: "x"`. */
|
|
76
|
+
export declare const formatInvoicesCsvErrors: (errors: InvoicesCsvError[]) => string;
|
|
77
|
+
export declare const parseInvoicesCsv: (csvText: string) => {
|
|
78
|
+
invoices: InvoicesCsv[];
|
|
79
|
+
errors: InvoicesCsvError[];
|
|
80
|
+
/** rows without an invoice number (credit/free charges) — skipped, not errors */
|
|
81
|
+
nullInvoiceNumbers: number;
|
|
82
|
+
};
|
|
83
|
+
export declare const fromInvoiceCsv: ({ csv, meta, }: {
|
|
84
|
+
csv: InvoicesCsv;
|
|
85
|
+
meta: Meta;
|
|
86
|
+
}) => Invoice;
|
|
87
|
+
//# sourceMappingURL=invoicesCsv.common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invoicesCsv.common.d.ts","sourceRoot":"","sources":["../../src/common/invoicesCsv.common.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EACV,OAAO,EAEP,IAAI,EACL,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAmGxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwB5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAM5D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;CAC5B;AAED,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,GAAI,QAAQ,gBAAgB,EAAE,KAAG,MAQtD,CAAC;AAEhB,eAAO,MAAM,gBAAgB,GAC3B,SAAS,MAAM,KACd;IACD,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,iFAAiF;IACjF,kBAAkB,EAAE,MAAM,CAAC;CA4B5B,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,gBAG5B;IACD,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;CACZ,KAAG,OAgCH,CAAC"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tesla charging-CSV import for pic_invoices.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline: raw CSV string
|
|
5
|
+
* → csv-parse (structure: delimiters, quoting, headers)
|
|
6
|
+
* → zod row schema (semantics: "N/A" → null, "22.1285 kwh" → value+unit,
|
|
7
|
+
* "0.51/kwh" → value+unit, NUMERIC precision checks, ISO dates)
|
|
8
|
+
* → PicInvoicesInitializer
|
|
9
|
+
* → parameterized INSERT (numerics stay strings; pg casts to NUMERIC losslessly)
|
|
10
|
+
*
|
|
11
|
+
* deps: npm i csv-parse postgres zod
|
|
12
|
+
*/
|
|
13
|
+
import { removeUndefined } from "@mxpicture/tesla-superchargers-mate/transform";
|
|
14
|
+
import { parse } from "csv-parse/sync";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
/* ------------------------------------------------------------------ */
|
|
17
|
+
/* helpers */
|
|
18
|
+
/* ------------------------------------------------------------------ */
|
|
19
|
+
const castNum = (name, str) => {
|
|
20
|
+
const value = str === null ? str : Number(str);
|
|
21
|
+
if (value === null || !Number.isFinite(value))
|
|
22
|
+
throw new Error(`invalid ${name}: "${str}"`);
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
25
|
+
/** "N/A" / "" / whitespace → null, everything else → trimmed string. */
|
|
26
|
+
const naToNull = (v) => {
|
|
27
|
+
if (typeof v !== "string")
|
|
28
|
+
return v;
|
|
29
|
+
const t = v.trim();
|
|
30
|
+
return t === "" || t.toUpperCase() === "N/A" ? null : t;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Decimal kept as *string* (matches Kanel's typing of pg NUMERIC) with a
|
|
34
|
+
* precision/scale check mirroring the column definition, so bad values fail
|
|
35
|
+
* in validation instead of as a pg error mid-insert.
|
|
36
|
+
*/
|
|
37
|
+
const numericString = (precision, scale) => z
|
|
38
|
+
.string()
|
|
39
|
+
.trim()
|
|
40
|
+
.regex(/^-?\d+(\.\d+)?$/, "not a decimal number")
|
|
41
|
+
.refine((s) => {
|
|
42
|
+
const [int = "", frac = ""] = s.replace("-", "").split(".");
|
|
43
|
+
return frac.length <= scale && int.length <= precision - scale;
|
|
44
|
+
}, `exceeds NUMERIC(${precision}, ${scale})`);
|
|
45
|
+
/** "22.1285 kwh" → { value: 22.1285, unit: "kwh" } (unit optional). */
|
|
46
|
+
const quantity = z
|
|
47
|
+
.string()
|
|
48
|
+
.trim()
|
|
49
|
+
.transform((s, ctx) => {
|
|
50
|
+
const m = s.match(/^(-?\d+(?:\.\d+)?)(?:\s+(\S+))?$/);
|
|
51
|
+
if (!m) {
|
|
52
|
+
ctx.addIssue({ code: "custom", message: `invalid quantity: "${s}"` });
|
|
53
|
+
return z.NEVER;
|
|
54
|
+
}
|
|
55
|
+
const value = m[1] === null ? m[1] : Number(m[1]);
|
|
56
|
+
if (value === null || !Number.isFinite(value)) {
|
|
57
|
+
ctx.addIssue({ code: "custom", message: `invalid quantity: "${s}"` });
|
|
58
|
+
return z.NEVER;
|
|
59
|
+
}
|
|
60
|
+
return { value, unit: m[2]?.toLowerCase() ?? null };
|
|
61
|
+
})
|
|
62
|
+
.refine((q) => numericString(8, 4).safeParse(String(q.value)).success, {
|
|
63
|
+
message: "quantity exceeds NUMERIC(8, 4)",
|
|
64
|
+
});
|
|
65
|
+
/** "0.51/kwh" → { value: 0.51, unit: "kwh" }. */
|
|
66
|
+
const unitCost = z
|
|
67
|
+
.string()
|
|
68
|
+
.trim()
|
|
69
|
+
.transform((s, ctx) => {
|
|
70
|
+
const m = s.match(/^(-?\d+(?:\.\d+)?)\s*\/\s*(\S+)$/);
|
|
71
|
+
if (!m) {
|
|
72
|
+
ctx.addIssue({ code: "custom", message: `invalid unit cost: "${s}"` });
|
|
73
|
+
return z.NEVER;
|
|
74
|
+
}
|
|
75
|
+
const value = m[1] === null ? m[1] : Number(m[1]);
|
|
76
|
+
if (value === null || !Number.isFinite(value)) {
|
|
77
|
+
ctx.addIssue({ code: "custom", message: `invalid unit cost: "${s}"` });
|
|
78
|
+
return z.NEVER;
|
|
79
|
+
}
|
|
80
|
+
return { value, unit: m[2].toLowerCase() };
|
|
81
|
+
})
|
|
82
|
+
.refine((c) => numericString(4, 2).safeParse(String(c.value)).success, {
|
|
83
|
+
message: "unit cost exceeds NUMERIC(4, 2)",
|
|
84
|
+
});
|
|
85
|
+
/** ISO-8601 with offset ("2026-03-31T14:56:00+02:00") → Date. */
|
|
86
|
+
const isoDate = z
|
|
87
|
+
.string()
|
|
88
|
+
.trim()
|
|
89
|
+
.transform((s, ctx) => {
|
|
90
|
+
const d = new Date(s);
|
|
91
|
+
if (Number.isNaN(d.getTime())) {
|
|
92
|
+
ctx.addIssue({ code: "custom", message: `invalid date: "${s}"` });
|
|
93
|
+
return z.NEVER;
|
|
94
|
+
}
|
|
95
|
+
return d;
|
|
96
|
+
});
|
|
97
|
+
const nullable = (schema) => z.preprocess(naToNull, schema.nullable());
|
|
98
|
+
const nonEmpty = z.string().trim().min(1);
|
|
99
|
+
/* ------------------------------------------------------------------ */
|
|
100
|
+
/* CSV row schema (keys = exact CSV headers) */
|
|
101
|
+
/* ------------------------------------------------------------------ */
|
|
102
|
+
export const invoicesCsvSchema = z.object({
|
|
103
|
+
ChargeStartDateTime: isoDate,
|
|
104
|
+
Name: nullable(nonEmpty),
|
|
105
|
+
Vin: nonEmpty,
|
|
106
|
+
Model: nullable(nonEmpty),
|
|
107
|
+
Country: nonEmpty,
|
|
108
|
+
SiteLocationName: nonEmpty,
|
|
109
|
+
Description: nullable(nonEmpty),
|
|
110
|
+
QuantityBase: quantity,
|
|
111
|
+
QuantityTier1: nullable(quantity),
|
|
112
|
+
QuantityTier2: nullable(quantity),
|
|
113
|
+
QuantityTier3: nullable(quantity),
|
|
114
|
+
QuantityTier4: nullable(quantity),
|
|
115
|
+
InvoiceNumber: nonEmpty,
|
|
116
|
+
UnitCostBase: unitCost,
|
|
117
|
+
UnitCostTier1: nullable(unitCost),
|
|
118
|
+
UnitCostTier2: nullable(unitCost),
|
|
119
|
+
UnitCostTier3: nullable(unitCost),
|
|
120
|
+
UnitCostTier4: nullable(unitCost),
|
|
121
|
+
VAT: numericString(5, 2),
|
|
122
|
+
"Total Exc. VAT": numericString(5, 2),
|
|
123
|
+
"Total Inc. VAT": numericString(5, 2),
|
|
124
|
+
Status: nullable(nonEmpty),
|
|
125
|
+
Invoice: nullable(z.string().trim().url()),
|
|
126
|
+
});
|
|
127
|
+
/** One line per invalid row: `line 3: QuantityBase: invalid quantity: "x"`. */
|
|
128
|
+
export const formatInvoicesCsvErrors = (errors) => errors
|
|
129
|
+
.map(({ line, issues }) => `line ${line}: ${issues
|
|
130
|
+
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
|
131
|
+
.join("; ")}`)
|
|
132
|
+
.join("\n");
|
|
133
|
+
export const parseInvoicesCsv = (csvText) => {
|
|
134
|
+
// csv-parse handles quoting ("Windischeschenbach, Germany"), BOM, CRLF.
|
|
135
|
+
const records = parse(csvText, {
|
|
136
|
+
columns: true, // first line = header, rows become objects
|
|
137
|
+
bom: true,
|
|
138
|
+
skip_empty_lines: true,
|
|
139
|
+
trim: true,
|
|
140
|
+
});
|
|
141
|
+
const invoices = [];
|
|
142
|
+
const errors = [];
|
|
143
|
+
let nullInvoiceNumbers = 0;
|
|
144
|
+
records.forEach((record, i) => {
|
|
145
|
+
// Credit/free charges ("CHARGING : CREDIT", €0.00) come without an
|
|
146
|
+
// invoice number. They cannot be keyed on invoice_number, so they are
|
|
147
|
+
// counted and skipped instead of failing the whole file.
|
|
148
|
+
if (naToNull(record.InvoiceNumber) === null) {
|
|
149
|
+
nullInvoiceNumbers++;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const result = invoicesCsvSchema.safeParse(record);
|
|
153
|
+
if (result.success)
|
|
154
|
+
invoices.push(result.data);
|
|
155
|
+
else
|
|
156
|
+
errors.push({ line: i + 2, issues: result.error.issues });
|
|
157
|
+
});
|
|
158
|
+
return { invoices, errors, nullInvoiceNumbers };
|
|
159
|
+
};
|
|
160
|
+
export const fromInvoiceCsv = ({ csv, meta, }) => {
|
|
161
|
+
const result = {
|
|
162
|
+
id: undefined,
|
|
163
|
+
chargingProcessesId: null,
|
|
164
|
+
fetched_at: meta.fetched_at,
|
|
165
|
+
last_fetch_uuid: meta.last_fetch_uuid,
|
|
166
|
+
chargeStartDateTime: csv.ChargeStartDateTime,
|
|
167
|
+
name: csv.Name,
|
|
168
|
+
vin: csv.Vin,
|
|
169
|
+
model: csv.Model,
|
|
170
|
+
country: csv.Country,
|
|
171
|
+
siteLocationName: csv.SiteLocationName,
|
|
172
|
+
description: csv.Description,
|
|
173
|
+
ucom: csv.QuantityBase.unit,
|
|
174
|
+
quantityBase: csv.QuantityBase.value,
|
|
175
|
+
quantityTier1: csv.QuantityTier1?.value,
|
|
176
|
+
quantityTier2: csv.QuantityTier2?.value,
|
|
177
|
+
quantityTier3: csv.QuantityTier3?.value,
|
|
178
|
+
quantityTier4: csv.QuantityTier4?.value,
|
|
179
|
+
invoiceNumber: csv.InvoiceNumber,
|
|
180
|
+
unitCostBase: csv.UnitCostBase.value,
|
|
181
|
+
unitCostTier1: csv.UnitCostTier1?.value,
|
|
182
|
+
unitCostTier2: csv.UnitCostTier2?.value,
|
|
183
|
+
unitCostTier3: csv.UnitCostTier3?.value,
|
|
184
|
+
unitCostTier4: csv.UnitCostTier4?.value,
|
|
185
|
+
vat: castNum("VAT", csv.VAT),
|
|
186
|
+
totalExcVat: castNum("Total Exc. VAT", csv["Total Exc. VAT"]),
|
|
187
|
+
totalIncVat: castNum("Total Inc. VAT", csv["Total Inc. VAT"]),
|
|
188
|
+
status: csv.Status,
|
|
189
|
+
invoice: csv.Invoice,
|
|
190
|
+
};
|
|
191
|
+
return removeUndefined(result);
|
|
192
|
+
};
|
|
193
|
+
//# sourceMappingURL=invoicesCsv.common.js.map
|