@fayz-ai/plugin-financial 0.2.0 → 0.8.0
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/README.md +2 -0
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/data/tables.d.ts +11 -0
- package/dist/data/tables.d.ts.map +1 -0
- package/dist/index.cjs +64 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +64 -52
- package/dist/index.js.map +1 -1
- package/dist/migrations/index.d.ts +16 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/registries.d.ts.map +1 -1
- package/package.json +10 -4
- package/src/README.md +5 -5
- package/src/contract.test.ts +1 -1
- package/src/data/supabase.ts +50 -47
- package/src/data/tables.ts +12 -0
- package/src/migrations/000_plg_rename.sql +30 -0
- package/src/migrations/001_financial_base.sql +30 -30
- package/src/migrations/002_chart_of_accounts.sql +10 -10
- package/src/migrations/003_card_brands.sql +4 -4
- package/src/migrations/004_order_to_cash.sql +28 -28
- package/src/migrations/005_seed_defaults.sql +6 -6
- package/src/migrations/006_rls_policies.sql +5 -5
- package/src/migrations/{006_extract_fee_amount.sql → 006b_extract_fee_amount.sql} +4 -4
- package/src/migrations/007_reconciliation.sql +9 -9
- package/src/migrations/007b_movement_payment_method_type.sql +6 -0
- package/src/migrations/008_split_payment_movements.sql +5 -5
- package/src/migrations/index.ts +544 -0
- package/src/registries.ts +8 -7
package/dist/index.js
CHANGED
|
@@ -5016,6 +5016,18 @@ function createMockFinancialProvider(options) {
|
|
|
5016
5016
|
return provider;
|
|
5017
5017
|
}
|
|
5018
5018
|
|
|
5019
|
+
// src/data/tables.ts
|
|
5020
|
+
var T = {
|
|
5021
|
+
movements: "plg_financial_movements",
|
|
5022
|
+
chartOfAccounts: "plg_financial_chart_of_accounts",
|
|
5023
|
+
bankAccounts: "plg_financial_bank_accounts",
|
|
5024
|
+
cardBrands: "plg_financial_card_brands",
|
|
5025
|
+
costCenters: "plg_financial_cost_centers",
|
|
5026
|
+
cashRegisterSessions: "plg_financial_cash_register_sessions",
|
|
5027
|
+
paymentMethods: "plg_financial_payment_methods",
|
|
5028
|
+
paymentMethodTypes: "plg_financial_payment_method_types"
|
|
5029
|
+
};
|
|
5030
|
+
|
|
5019
5031
|
// src/data/supabase.ts
|
|
5020
5032
|
function getTenantId() {
|
|
5021
5033
|
return getActiveTenantId();
|
|
@@ -5038,7 +5050,7 @@ function camelToSnake(obj) {
|
|
|
5038
5050
|
function getClients() {
|
|
5039
5051
|
const supabase = getSupabaseClientOptional();
|
|
5040
5052
|
if (!supabase) throw new Error("Supabase not initialized");
|
|
5041
|
-
return { core: supabase
|
|
5053
|
+
return { core: supabase, pub: supabase };
|
|
5042
5054
|
}
|
|
5043
5055
|
function mapStageToInvoiceStatus(stage) {
|
|
5044
5056
|
switch (stage) {
|
|
@@ -5065,11 +5077,11 @@ async function sweepOverdue() {
|
|
|
5065
5077
|
try {
|
|
5066
5078
|
const { core, pub } = getClients();
|
|
5067
5079
|
const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5068
|
-
const { data: overdueMovs } = await pub.from(
|
|
5080
|
+
const { data: overdueMovs } = await pub.from(T.movements).update({ status: "overdue" }).in("status", ["pending", "partial"]).lt("due_date", today2).select("invoice_id");
|
|
5069
5081
|
if (overdueMovs && overdueMovs.length > 0) {
|
|
5070
5082
|
const invoiceIds = [...new Set(overdueMovs.map((m) => m.invoice_id).filter(Boolean))];
|
|
5071
5083
|
for (const invId of invoiceIds) {
|
|
5072
|
-
const { data: allMovs } = await pub.from(
|
|
5084
|
+
const { data: allMovs } = await pub.from(T.movements).select("status").eq("invoice_id", invId).eq("movement_kind", "bill");
|
|
5073
5085
|
const movs = allMovs ?? [];
|
|
5074
5086
|
const hasOverdue = movs.some((m) => m.status === "overdue");
|
|
5075
5087
|
const allPaid = movs.every((m) => m.status === "paid");
|
|
@@ -5107,7 +5119,7 @@ async function findOrderIdsByItemMetadata(core, filters) {
|
|
|
5107
5119
|
}
|
|
5108
5120
|
async function getMethodFeePct(pub, paymentMethodId) {
|
|
5109
5121
|
if (!paymentMethodId) return 0;
|
|
5110
|
-
const { data } = await pub.from(
|
|
5122
|
+
const { data } = await pub.from(T.paymentMethods).select("discount_value").eq("id", paymentMethodId).single();
|
|
5111
5123
|
return Number(data?.discount_value) || 0;
|
|
5112
5124
|
}
|
|
5113
5125
|
function genId() {
|
|
@@ -5179,7 +5191,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5179
5191
|
const o = snakeToCamel(data);
|
|
5180
5192
|
const meta = data.metadata ?? {};
|
|
5181
5193
|
const balance = (await fetchInvoiceBalances(pub, [id])).get(id);
|
|
5182
|
-
const { data: movs } = await pub.from(
|
|
5194
|
+
const { data: movs } = await pub.from(T.movements).select("paid_amount").eq("invoice_id", id).eq("movement_kind", "bill");
|
|
5183
5195
|
return {
|
|
5184
5196
|
id: o.id,
|
|
5185
5197
|
direction: o.direction ?? (o.kind === "invoice_payable" ? "debit" : "credit"),
|
|
@@ -5266,7 +5278,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5266
5278
|
);
|
|
5267
5279
|
}
|
|
5268
5280
|
if (order && input.installments.length > 0) {
|
|
5269
|
-
await pub.from(
|
|
5281
|
+
await pub.from(T.movements).insert(
|
|
5270
5282
|
input.installments.map((inst, i) => ({
|
|
5271
5283
|
tenant_id: tenantId,
|
|
5272
5284
|
invoice_id: order.id,
|
|
@@ -5308,12 +5320,12 @@ function createSupabaseFinancialProvider() {
|
|
|
5308
5320
|
async cancelInvoice(id) {
|
|
5309
5321
|
const { core, pub } = getClients();
|
|
5310
5322
|
await core.from("orders").update({ status: "cancelled" }).eq("id", id);
|
|
5311
|
-
await pub.from(
|
|
5323
|
+
await pub.from(T.movements).update({ status: "cancelled" }).eq("invoice_id", id).eq("status", "pending");
|
|
5312
5324
|
},
|
|
5313
5325
|
// --- Movements (public.financial_movements) ---
|
|
5314
5326
|
async getMovements(query) {
|
|
5315
5327
|
const { pub } = getClients();
|
|
5316
|
-
let qb = pub.from(
|
|
5328
|
+
let qb = pub.from(T.movements).select("*", { count: "exact" });
|
|
5317
5329
|
if (query.direction) qb = qb.eq("direction", query.direction);
|
|
5318
5330
|
if (query.status) {
|
|
5319
5331
|
const statuses = Array.isArray(query.status) ? query.status : [query.status];
|
|
@@ -5330,7 +5342,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5330
5342
|
},
|
|
5331
5343
|
async payMovement(input) {
|
|
5332
5344
|
const { core, pub } = getClients();
|
|
5333
|
-
const { data: mov } = await pub.from(
|
|
5345
|
+
const { data: mov } = await pub.from(T.movements).select("*").eq("id", input.movementId).single();
|
|
5334
5346
|
if (!mov) throw new Error("Movement not found");
|
|
5335
5347
|
const tenantId = mov.tenant_id ?? getTenantId();
|
|
5336
5348
|
const feePct = mov.direction === "credit" ? await getMethodFeePct(pub, input.paymentMethodId) : 0;
|
|
@@ -5355,17 +5367,17 @@ function createSupabaseFinancialProvider() {
|
|
|
5355
5367
|
card_installments: input.cardInstallments ?? null,
|
|
5356
5368
|
notes: input.notes ?? null
|
|
5357
5369
|
};
|
|
5358
|
-
let { data, error } = await pub.from(
|
|
5370
|
+
let { data, error } = await pub.from(T.movements).insert(paymentRow).select().single();
|
|
5359
5371
|
if (error && /fee_amount/i.test(error.message ?? "")) {
|
|
5360
5372
|
const { fee_amount, ...rest } = paymentRow;
|
|
5361
|
-
({ data, error } = await pub.from(
|
|
5373
|
+
({ data, error } = await pub.from(T.movements).insert(rest).select().single());
|
|
5362
5374
|
}
|
|
5363
5375
|
if (error) throw error;
|
|
5364
5376
|
const newPaid = round22((mov.paid_amount ?? 0) + input.amount);
|
|
5365
5377
|
const billStatus = newPaid >= mov.amount ? "paid" : "partial";
|
|
5366
|
-
await pub.from(
|
|
5378
|
+
await pub.from(T.movements).update({ paid_amount: newPaid, status: billStatus, payment_date: null, bank_account_id: null }).eq("id", mov.id);
|
|
5367
5379
|
if (mov.invoice_id) {
|
|
5368
|
-
const { data: allMovs } = await pub.from(
|
|
5380
|
+
const { data: allMovs } = await pub.from(T.movements).select("status, amount, paid_amount").eq("invoice_id", mov.invoice_id).eq("movement_kind", "bill");
|
|
5369
5381
|
const movs = allMovs ?? [];
|
|
5370
5382
|
const allPaid = movs.length > 0 && movs.every((m) => m.status === "paid");
|
|
5371
5383
|
const anyPaid = movs.some((m) => m.status === "paid" || m.status === "partial");
|
|
@@ -5382,7 +5394,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5382
5394
|
},
|
|
5383
5395
|
async cancelMovement(id) {
|
|
5384
5396
|
const { pub } = getClients();
|
|
5385
|
-
await pub.from(
|
|
5397
|
+
await pub.from(T.movements).update({ status: "cancelled" }).eq("id", id);
|
|
5386
5398
|
},
|
|
5387
5399
|
// --- Transfers (between accounts) ---
|
|
5388
5400
|
async createTransfer(input) {
|
|
@@ -5418,10 +5430,10 @@ function createSupabaseFinancialProvider() {
|
|
|
5418
5430
|
metadata: { transferId, transferRole: "in", counterAccountId: input.fromAccountId }
|
|
5419
5431
|
}
|
|
5420
5432
|
];
|
|
5421
|
-
let { data, error } = await pub.from(
|
|
5433
|
+
let { data, error } = await pub.from(T.movements).insert(rowsToInsert).select("id, direction");
|
|
5422
5434
|
if (error && /fee_amount/i.test(error.message ?? "")) {
|
|
5423
5435
|
const stripped = rowsToInsert.map(({ fee_amount, ...rest }) => rest);
|
|
5424
|
-
({ data, error } = await pub.from(
|
|
5436
|
+
({ data, error } = await pub.from(T.movements).insert(stripped).select("id, direction"));
|
|
5425
5437
|
}
|
|
5426
5438
|
if (error) throw error;
|
|
5427
5439
|
const rows = data ?? [];
|
|
@@ -5432,13 +5444,13 @@ function createSupabaseFinancialProvider() {
|
|
|
5432
5444
|
// --- Bank Accounts ---
|
|
5433
5445
|
async getBankAccounts() {
|
|
5434
5446
|
const { pub } = getClients();
|
|
5435
|
-
const { data } = await pub.from(
|
|
5447
|
+
const { data } = await pub.from(T.bankAccounts).select("*").eq("is_active", true).order("name");
|
|
5436
5448
|
return (data ?? []).map((r) => snakeToCamel(r));
|
|
5437
5449
|
},
|
|
5438
5450
|
async createBankAccount(input) {
|
|
5439
5451
|
const { pub } = getClients();
|
|
5440
5452
|
const tenantId = getTenantId();
|
|
5441
|
-
const { data } = await pub.from(
|
|
5453
|
+
const { data } = await pub.from(T.bankAccounts).insert({
|
|
5442
5454
|
...camelToSnake(input),
|
|
5443
5455
|
tenant_id: tenantId,
|
|
5444
5456
|
current_balance: input.initialBalance ?? 0
|
|
@@ -5450,26 +5462,26 @@ function createSupabaseFinancialProvider() {
|
|
|
5450
5462
|
const row = camelToSnake(partial);
|
|
5451
5463
|
delete row.id;
|
|
5452
5464
|
delete row.tenant_id;
|
|
5453
|
-
const { data } = await pub.from(
|
|
5465
|
+
const { data } = await pub.from(T.bankAccounts).update(row).eq("id", id).select().single();
|
|
5454
5466
|
return snakeToCamel(data);
|
|
5455
5467
|
},
|
|
5456
5468
|
// --- Cash Sessions ---
|
|
5457
5469
|
async getCashSessions(bankAccountId) {
|
|
5458
5470
|
const { pub } = getClients();
|
|
5459
|
-
let qb = pub.from(
|
|
5471
|
+
let qb = pub.from(T.cashRegisterSessions).select("*");
|
|
5460
5472
|
if (bankAccountId) qb = qb.eq("bank_account_id", bankAccountId);
|
|
5461
5473
|
const { data } = await qb.order("opened_at", { ascending: false });
|
|
5462
5474
|
return (data ?? []).map((r) => snakeToCamel(r));
|
|
5463
5475
|
},
|
|
5464
5476
|
async getOpenSession(bankAccountId) {
|
|
5465
5477
|
const { pub } = getClients();
|
|
5466
|
-
const { data } = await pub.from(
|
|
5478
|
+
const { data } = await pub.from(T.cashRegisterSessions).select("*").eq("bank_account_id", bankAccountId).eq("status", "open").single();
|
|
5467
5479
|
return data ? snakeToCamel(data) : null;
|
|
5468
5480
|
},
|
|
5469
5481
|
async openCashSession(input) {
|
|
5470
5482
|
const { pub } = getClients();
|
|
5471
5483
|
const tenantId = getTenantId();
|
|
5472
|
-
const { data } = await pub.from(
|
|
5484
|
+
const { data } = await pub.from(T.cashRegisterSessions).insert({
|
|
5473
5485
|
tenant_id: tenantId,
|
|
5474
5486
|
bank_account_id: input.bankAccountId,
|
|
5475
5487
|
status: "open",
|
|
@@ -5482,7 +5494,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5482
5494
|
},
|
|
5483
5495
|
async closeCashSession(input) {
|
|
5484
5496
|
const { pub } = getClients();
|
|
5485
|
-
const { data } = await pub.from(
|
|
5497
|
+
const { data } = await pub.from(T.cashRegisterSessions).update({
|
|
5486
5498
|
status: "closed",
|
|
5487
5499
|
closing_balance: input.closingBalance,
|
|
5488
5500
|
closed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -5494,8 +5506,8 @@ function createSupabaseFinancialProvider() {
|
|
|
5494
5506
|
},
|
|
5495
5507
|
async getCashSessionSummary(sessionId) {
|
|
5496
5508
|
const { pub } = getClients();
|
|
5497
|
-
const session = (await pub.from(
|
|
5498
|
-
const { data: movs } = await pub.from(
|
|
5509
|
+
const session = (await pub.from(T.cashRegisterSessions).select("*").eq("id", sessionId).single()).data;
|
|
5510
|
+
const { data: movs } = await pub.from(T.movements).select("direction, paid_amount").eq("cash_session_id", sessionId).eq("status", "paid");
|
|
5499
5511
|
const movements = movs ?? [];
|
|
5500
5512
|
return {
|
|
5501
5513
|
session: snakeToCamel(session),
|
|
@@ -5507,23 +5519,23 @@ function createSupabaseFinancialProvider() {
|
|
|
5507
5519
|
// --- Payment Methods ---
|
|
5508
5520
|
async getPaymentMethods() {
|
|
5509
5521
|
const { pub } = getClients();
|
|
5510
|
-
const { data } = await pub.from(
|
|
5522
|
+
const { data } = await pub.from(T.paymentMethods).select("*").eq("is_active", true).order("name");
|
|
5511
5523
|
return (data ?? []).map((r) => snakeToCamel(r));
|
|
5512
5524
|
},
|
|
5513
5525
|
async getPaymentMethodTypes() {
|
|
5514
5526
|
const { pub } = getClients();
|
|
5515
|
-
const { data } = await pub.from(
|
|
5527
|
+
const { data } = await pub.from(T.paymentMethodTypes).select("*").eq("is_active", true).order("name");
|
|
5516
5528
|
return (data ?? []).map((r) => snakeToCamel(r));
|
|
5517
5529
|
},
|
|
5518
5530
|
// --- Chart of Accounts ---
|
|
5519
5531
|
async getChartOfAccounts() {
|
|
5520
5532
|
const { pub } = getClients();
|
|
5521
|
-
const { data } = await pub.from(
|
|
5533
|
+
const { data } = await pub.from(T.chartOfAccounts).select("*").eq("is_active", true).order("code");
|
|
5522
5534
|
return (data ?? []).map((r) => snakeToCamel(r));
|
|
5523
5535
|
},
|
|
5524
5536
|
async getCostCenters() {
|
|
5525
5537
|
const { pub } = getClients();
|
|
5526
|
-
const { data } = await pub.from(
|
|
5538
|
+
const { data } = await pub.from(T.costCenters).select("*").eq("is_active", true).order("code");
|
|
5527
5539
|
return (data ?? []).map((r) => snakeToCamel(r));
|
|
5528
5540
|
},
|
|
5529
5541
|
// --- Card Transactions ---
|
|
@@ -5535,7 +5547,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5535
5547
|
async getStatement(query) {
|
|
5536
5548
|
const { core, pub } = getClients();
|
|
5537
5549
|
const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5538
|
-
const { data: acctRows } = await pub.from(
|
|
5550
|
+
const { data: acctRows } = await pub.from(T.bankAccounts).select("id, name, initial_balance, is_active");
|
|
5539
5551
|
const allAccounts = acctRows ?? [];
|
|
5540
5552
|
const consolidated = !query.bankAccountId;
|
|
5541
5553
|
const scopeAccounts = consolidated ? allAccounts.filter((a) => a.is_active) : allAccounts.filter((a) => a.id === query.bankAccountId);
|
|
@@ -5547,10 +5559,10 @@ function createSupabaseFinancialProvider() {
|
|
|
5547
5559
|
}
|
|
5548
5560
|
const scopeFilter = (qb) => consolidated ? qb : qb.in("bank_account_id", accountIds);
|
|
5549
5561
|
const netOf = (r) => r.direction === "credit" ? (Number(r.paid_amount) || 0) - (Number(r.fee_amount) || 0) : -(Number(r.paid_amount) || 0);
|
|
5550
|
-
const { data: priorRows } = await scopeFilter(pub.from(
|
|
5562
|
+
const { data: priorRows } = await scopeFilter(pub.from(T.movements).select("*").neq("status", "cancelled").lt("payment_date", query.dateRange.from));
|
|
5551
5563
|
const priorNet = (priorRows ?? []).reduce((s, r) => s + netOf(r), 0);
|
|
5552
5564
|
const openingBalance = round22(initialSum + priorNet);
|
|
5553
|
-
const { data: movs } = await scopeFilter(pub.from(
|
|
5565
|
+
const { data: movs } = await scopeFilter(pub.from(T.movements).select("*").neq("status", "cancelled").gte("payment_date", query.dateRange.from).lte("payment_date", query.dateRange.to).order("payment_date").order("created_at"));
|
|
5554
5566
|
const invoiceIds = [...new Set((movs ?? []).map((r) => r.invoice_id).filter(Boolean))];
|
|
5555
5567
|
const invoiceById = /* @__PURE__ */ new Map();
|
|
5556
5568
|
if (invoiceIds.length) {
|
|
@@ -5592,7 +5604,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5592
5604
|
});
|
|
5593
5605
|
const matchedIds = [...new Set(entries.map((e) => e.movement.matchedMovementId).filter(Boolean))];
|
|
5594
5606
|
if (matchedIds.length) {
|
|
5595
|
-
const { data: matched } = await pub.from(
|
|
5607
|
+
const { data: matched } = await pub.from(T.movements).select("id, invoice_id, notes").in("id", matchedIds);
|
|
5596
5608
|
const matchedById = new Map((matched ?? []).map((m) => [m.id, m]));
|
|
5597
5609
|
const matchedInvoiceIds = [...new Set((matched ?? []).map((m) => m.invoice_id).filter(Boolean))];
|
|
5598
5610
|
const invById = /* @__PURE__ */ new Map();
|
|
@@ -5614,7 +5626,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5614
5626
|
};
|
|
5615
5627
|
}
|
|
5616
5628
|
}
|
|
5617
|
-
const { data: todayRows } = await scopeFilter(pub.from(
|
|
5629
|
+
const { data: todayRows } = await scopeFilter(pub.from(T.movements).select("*").neq("status", "cancelled").lte("payment_date", today2));
|
|
5618
5630
|
const accountCurrentBalance = round22(initialSum + (todayRows ?? []).reduce((s, r) => s + netOf(r), 0));
|
|
5619
5631
|
return {
|
|
5620
5632
|
entries,
|
|
@@ -5632,9 +5644,9 @@ function createSupabaseFinancialProvider() {
|
|
|
5632
5644
|
async getSummary(dateRange) {
|
|
5633
5645
|
sweepOverdue();
|
|
5634
5646
|
const { pub } = getClients();
|
|
5635
|
-
const { data: accounts } = await pub.from(
|
|
5647
|
+
const { data: accounts } = await pub.from(T.bankAccounts).select("current_balance").eq("is_active", true);
|
|
5636
5648
|
const totalBalance = (accounts ?? []).reduce((s, a) => s + (a.current_balance ?? 0), 0);
|
|
5637
|
-
const { data: movs } = await pub.from(
|
|
5649
|
+
const { data: movs } = await pub.from(T.movements).select("direction, movement_kind, amount, paid_amount, status, due_date, payment_date");
|
|
5638
5650
|
const allMovs = movs ?? [];
|
|
5639
5651
|
const unpaid = allMovs.filter((m) => ["pending", "partial", "overdue"].includes(m.status));
|
|
5640
5652
|
const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -5667,7 +5679,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5667
5679
|
const tenantId = getTenantId();
|
|
5668
5680
|
let imported = 0, duplicates = 0;
|
|
5669
5681
|
for (const line of input.lines) {
|
|
5670
|
-
const { error } = await pub.from(
|
|
5682
|
+
const { error } = await pub.from(T.movements).insert({
|
|
5671
5683
|
tenant_id: tenantId,
|
|
5672
5684
|
direction: line.direction,
|
|
5673
5685
|
movement_kind: "payment",
|
|
@@ -5690,7 +5702,7 @@ function createSupabaseFinancialProvider() {
|
|
|
5690
5702
|
},
|
|
5691
5703
|
async getUnreconciled(query) {
|
|
5692
5704
|
const { pub } = getClients();
|
|
5693
|
-
let qb = pub.from(
|
|
5705
|
+
let qb = pub.from(T.movements).select("*").not("external_source", "is", null).is("reconciled_at", null);
|
|
5694
5706
|
if (query?.bankAccountId) qb = qb.eq("bank_account_id", query.bankAccountId);
|
|
5695
5707
|
if (query?.dateRange) qb = qb.gte("payment_date", query.dateRange.from).lte("payment_date", query.dateRange.to);
|
|
5696
5708
|
const { data } = await qb.order("payment_date", { ascending: false });
|
|
@@ -5698,12 +5710,12 @@ function createSupabaseFinancialProvider() {
|
|
|
5698
5710
|
},
|
|
5699
5711
|
async suggestReconciliation(bankMovementId) {
|
|
5700
5712
|
const { core, pub } = getClients();
|
|
5701
|
-
const { data: line } = await pub.from(
|
|
5713
|
+
const { data: line } = await pub.from(T.movements).select("*").eq("id", bankMovementId).single();
|
|
5702
5714
|
if (!line) return [];
|
|
5703
5715
|
const amount = Number(line.amount) || 0;
|
|
5704
5716
|
const lineDate = line.payment_date ?? line.due_date;
|
|
5705
5717
|
const tol = Math.max(0.01, round22(amount * 0.02));
|
|
5706
|
-
const { data } = await pub.from(
|
|
5718
|
+
const { data } = await pub.from(T.movements).select("*").is("external_source", null).is("reconciled_at", null).eq("direction", line.direction).gte("amount", round22(amount - tol)).lte("amount", round22(amount + tol)).neq("id", bankMovementId).limit(25);
|
|
5707
5719
|
const candidates = (data ?? []).map((r) => {
|
|
5708
5720
|
const amtDiff = Math.abs((Number(r.amount) || 0) - amount);
|
|
5709
5721
|
const amtScore = amount > 0 ? Math.max(0, 1 - amtDiff / amount) : 0;
|
|
@@ -5729,20 +5741,20 @@ function createSupabaseFinancialProvider() {
|
|
|
5729
5741
|
async reconcileMovement(input) {
|
|
5730
5742
|
const { pub } = getClients();
|
|
5731
5743
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
5732
|
-
await pub.from(
|
|
5744
|
+
await pub.from(T.movements).update({
|
|
5733
5745
|
reconciled_at: now2,
|
|
5734
5746
|
matched_movement_id: input.matchedMovementId ?? null
|
|
5735
5747
|
}).eq("id", input.bankMovementId);
|
|
5736
5748
|
if (input.matchedMovementId) {
|
|
5737
|
-
await pub.from(
|
|
5749
|
+
await pub.from(T.movements).update({ reconciled_at: now2 }).eq("id", input.matchedMovementId);
|
|
5738
5750
|
}
|
|
5739
5751
|
},
|
|
5740
5752
|
async unreconcileMovement(bankMovementId) {
|
|
5741
5753
|
const { pub } = getClients();
|
|
5742
|
-
const { data: line } = await pub.from(
|
|
5743
|
-
await pub.from(
|
|
5754
|
+
const { data: line } = await pub.from(T.movements).select("matched_movement_id").eq("id", bankMovementId).single();
|
|
5755
|
+
await pub.from(T.movements).update({ reconciled_at: null, matched_movement_id: null }).eq("id", bankMovementId);
|
|
5744
5756
|
if (line?.matched_movement_id) {
|
|
5745
|
-
await pub.from(
|
|
5757
|
+
await pub.from(T.movements).update({ reconciled_at: null }).eq("id", line.matched_movement_id);
|
|
5746
5758
|
}
|
|
5747
5759
|
}
|
|
5748
5760
|
};
|
|
@@ -5990,7 +6002,7 @@ var paymentMethodTypeEntity = {
|
|
|
5990
6002
|
{ key: "transactionType", label: "Transaction Type", type: "select", options: ["cash", "credit_card", "debit_card", "pix", "bank_transfer", "check", "voucher"], showInTable: true, required: true },
|
|
5991
6003
|
{ key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
|
|
5992
6004
|
],
|
|
5993
|
-
data: { table:
|
|
6005
|
+
data: { table: T.paymentMethodTypes, tenantScoped: true }
|
|
5994
6006
|
};
|
|
5995
6007
|
var paymentMethodEntity = {
|
|
5996
6008
|
name: "Payment Method",
|
|
@@ -6002,14 +6014,14 @@ var paymentMethodEntity = {
|
|
|
6002
6014
|
{ key: "name", label: "Name", type: "text", required: true, showInTable: true },
|
|
6003
6015
|
// FK to the seeded payment_method_types catalog — load real ids at runtime
|
|
6004
6016
|
// (a static enum select would write the string into the uuid column).
|
|
6005
|
-
{ key: "paymentMethodTypeId", label: "Type", type: "relation", relation: { table:
|
|
6017
|
+
{ key: "paymentMethodTypeId", label: "Type", type: "relation", relation: { table: T.paymentMethodTypes, labelField: "name" }, showInTable: true, required: true },
|
|
6006
6018
|
{ key: "discountValue", label: "Discount %", type: "number", showInTable: true },
|
|
6007
6019
|
{ key: "interestValue", label: "Interest %", type: "number", showInTable: true },
|
|
6008
6020
|
{ key: "minInstallments", label: "Min Installments", type: "number", defaultValue: 1 },
|
|
6009
6021
|
{ key: "maxInstallments", label: "Max Installments", type: "number", defaultValue: 1, showInTable: true },
|
|
6010
6022
|
{ key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
|
|
6011
6023
|
],
|
|
6012
|
-
data: { table:
|
|
6024
|
+
data: { table: T.paymentMethods, tenantScoped: true }
|
|
6013
6025
|
};
|
|
6014
6026
|
var chartOfAccountsEntity = {
|
|
6015
6027
|
name: "Ledger Account",
|
|
@@ -6024,7 +6036,7 @@ var chartOfAccountsEntity = {
|
|
|
6024
6036
|
{ key: "parentId", label: "Parent", type: "text", showInTable: false },
|
|
6025
6037
|
{ key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
|
|
6026
6038
|
],
|
|
6027
|
-
data: { table:
|
|
6039
|
+
data: { table: T.chartOfAccounts, tenantScoped: true }
|
|
6028
6040
|
};
|
|
6029
6041
|
var costCenterEntity = {
|
|
6030
6042
|
name: "Cost Center",
|
|
@@ -6037,7 +6049,7 @@ var costCenterEntity = {
|
|
|
6037
6049
|
{ key: "name", label: "Name", type: "text", required: true, showInTable: true },
|
|
6038
6050
|
{ key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
|
|
6039
6051
|
],
|
|
6040
|
-
data: { table:
|
|
6052
|
+
data: { table: T.costCenters, tenantScoped: true }
|
|
6041
6053
|
};
|
|
6042
6054
|
var bankAccountEntity = {
|
|
6043
6055
|
name: "Bank Account",
|
|
@@ -6062,7 +6074,7 @@ var bankAccountEntity = {
|
|
|
6062
6074
|
{ key: "dueDay", label: "Due Day", type: "number" },
|
|
6063
6075
|
{ key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
|
|
6064
6076
|
],
|
|
6065
|
-
data: { table:
|
|
6077
|
+
data: { table: T.bankAccounts, tenantScoped: true }
|
|
6066
6078
|
};
|
|
6067
6079
|
var cardBrandEntity = {
|
|
6068
6080
|
name: "Card Brand",
|
|
@@ -6074,7 +6086,7 @@ var cardBrandEntity = {
|
|
|
6074
6086
|
{ key: "name", label: "Name", type: "text", required: true, showInTable: true },
|
|
6075
6087
|
{ key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
|
|
6076
6088
|
],
|
|
6077
|
-
data: { table:
|
|
6089
|
+
data: { table: T.cardBrands, tenantScoped: true }
|
|
6078
6090
|
};
|
|
6079
6091
|
var commissionRuleEntity = {
|
|
6080
6092
|
name: "Commission Rule",
|