@hed-hog/finance 0.0.318 → 0.0.321
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/dto/create-bank-account.dto.d.ts +1 -0
- package/dist/dto/create-bank-account.dto.d.ts.map +1 -1
- package/dist/dto/create-bank-account.dto.js +7 -0
- package/dist/dto/create-bank-account.dto.js.map +1 -1
- package/dist/dto/create-bank-statement-entry.dto.d.ts +8 -0
- package/dist/dto/create-bank-statement-entry.dto.d.ts.map +1 -0
- package/dist/dto/create-bank-statement-entry.dto.js +54 -0
- package/dist/dto/create-bank-statement-entry.dto.js.map +1 -0
- package/dist/dto/create-currency.dto.d.ts +6 -0
- package/dist/dto/create-currency.dto.d.ts.map +1 -0
- package/dist/dto/create-currency.dto.js +37 -0
- package/dist/dto/create-currency.dto.js.map +1 -0
- package/dist/dto/update-bank-account.dto.d.ts +1 -0
- package/dist/dto/update-bank-account.dto.d.ts.map +1 -1
- package/dist/dto/update-bank-account.dto.js +7 -0
- package/dist/dto/update-bank-account.dto.js.map +1 -1
- package/dist/dto/update-bank-statement-entry.dto.d.ts +6 -0
- package/dist/dto/update-bank-statement-entry.dto.d.ts.map +1 -0
- package/dist/dto/update-bank-statement-entry.dto.js +42 -0
- package/dist/dto/update-bank-statement-entry.dto.js.map +1 -0
- package/dist/dto/update-currency.dto.d.ts +7 -0
- package/dist/dto/update-currency.dto.d.ts.map +1 -0
- package/dist/dto/update-currency.dto.js +47 -0
- package/dist/dto/update-currency.dto.js.map +1 -0
- package/dist/finance-bank-accounts.controller.d.ts +25 -13
- package/dist/finance-bank-accounts.controller.d.ts.map +1 -1
- package/dist/finance-bank-accounts.controller.js +5 -3
- package/dist/finance-bank-accounts.controller.js.map +1 -1
- package/dist/finance-currencies.controller.d.ts +36 -0
- package/dist/finance-currencies.controller.d.ts.map +1 -0
- package/dist/finance-currencies.controller.js +74 -0
- package/dist/finance-currencies.controller.js.map +1 -0
- package/dist/finance-data.controller.d.ts +4 -0
- package/dist/finance-data.controller.d.ts.map +1 -1
- package/dist/finance-installments.controller.d.ts +3 -2
- package/dist/finance-installments.controller.d.ts.map +1 -1
- package/dist/finance-installments.controller.js +10 -6
- package/dist/finance-installments.controller.js.map +1 -1
- package/dist/finance-statements.controller.d.ts +61 -12
- package/dist/finance-statements.controller.d.ts.map +1 -1
- package/dist/finance-statements.controller.js +50 -8
- package/dist/finance-statements.controller.js.map +1 -1
- package/dist/finance-transfers.controller.d.ts +13 -8
- package/dist/finance-transfers.controller.d.ts.map +1 -1
- package/dist/finance-transfers.controller.js +11 -5
- package/dist/finance-transfers.controller.js.map +1 -1
- package/dist/finance.module.d.ts.map +1 -1
- package/dist/finance.module.js +2 -0
- package/dist/finance.module.js.map +1 -1
- package/dist/finance.service.d.ts +153 -35
- package/dist/finance.service.d.ts.map +1 -1
- package/dist/finance.service.js +468 -55
- package/dist/finance.service.js.map +1 -1
- package/hedhog/data/currency.yaml +14 -0
- package/hedhog/data/menu.yaml +16 -0
- package/hedhog/data/role.yaml +9 -1
- package/hedhog/data/route.yaml +78 -0
- package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +87 -72
- package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +53 -25
- package/hedhog/frontend/app/accounts-receivable/installments/[id]/page.tsx.ejs +8 -0
- package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +60 -24
- package/hedhog/frontend/app/administration/currencies/page.tsx.ejs +490 -0
- package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +243 -65
- package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +25 -3
- package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +732 -61
- package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +101 -15
- package/hedhog/frontend/messages/en.json +58 -0
- package/hedhog/frontend/messages/pt.json +58 -0
- package/hedhog/table/bank_account.yaml +8 -0
- package/hedhog/table/bank_statement_line.yaml +1 -1
- package/hedhog/table/cashflow_projection.yaml +1 -1
- package/hedhog/table/currency.yaml +21 -0
- package/hedhog/table/financial_installment.yaml +2 -2
- package/hedhog/table/financial_title.yaml +1 -1
- package/hedhog/table/installment_allocation.yaml +1 -1
- package/hedhog/table/receivable_schedule.yaml +1 -1
- package/hedhog/table/settlement.yaml +1 -1
- package/hedhog/table/settlement_allocation.yaml +5 -5
- package/package.json +6 -6
- package/src/dto/create-bank-account.dto.ts +18 -1
- package/src/dto/create-bank-statement-entry.dto.ts +50 -0
- package/src/dto/create-currency.dto.ts +21 -0
- package/src/dto/update-bank-account.dto.ts +11 -1
- package/src/dto/update-bank-statement-entry.dto.ts +31 -0
- package/src/dto/update-currency.dto.ts +31 -0
- package/src/finance-bank-accounts.controller.ts +3 -2
- package/src/finance-currencies.controller.ts +44 -0
- package/src/finance-installments.controller.ts +9 -3
- package/src/finance-statements.controller.ts +40 -0
- package/src/finance-transfers.controller.ts +7 -1
- package/src/finance.module.ts +2 -0
- package/src/finance.service.ts +633 -55
package/dist/finance.service.js
CHANGED
|
@@ -419,6 +419,23 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
419
419
|
}
|
|
420
420
|
return dt.toISOString().slice(0, 10);
|
|
421
421
|
}
|
|
422
|
+
parseFilterDate(value, endOfDay = false) {
|
|
423
|
+
if (!value) {
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
const raw = String(value).trim();
|
|
427
|
+
if (!raw) {
|
|
428
|
+
return undefined;
|
|
429
|
+
}
|
|
430
|
+
const normalized = /^\d{4}-\d{2}-\d{2}$/.test(raw)
|
|
431
|
+
? `${raw}T${endOfDay ? '23:59:59.999' : '00:00:00.000'}`
|
|
432
|
+
: raw;
|
|
433
|
+
const parsed = new Date(normalized);
|
|
434
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
435
|
+
return undefined;
|
|
436
|
+
}
|
|
437
|
+
return parsed;
|
|
438
|
+
}
|
|
422
439
|
normalizeMonth(value) {
|
|
423
440
|
if (!value)
|
|
424
441
|
return '';
|
|
@@ -454,6 +471,14 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
454
471
|
card: 'cartao',
|
|
455
472
|
credito: 'cartao',
|
|
456
473
|
debito: 'cartao',
|
|
474
|
+
'debito automatico': 'debito_automatico',
|
|
475
|
+
debito_automatico: 'debito_automatico',
|
|
476
|
+
'debito-automatico': 'debito_automatico',
|
|
477
|
+
'débito automático': 'debito_automatico',
|
|
478
|
+
'debito em conta': 'debito_em_conta',
|
|
479
|
+
debito_em_conta: 'debito_em_conta',
|
|
480
|
+
'debito-em-conta': 'debito_em_conta',
|
|
481
|
+
'débito em conta': 'debito_em_conta',
|
|
457
482
|
dinheiro: 'dinheiro',
|
|
458
483
|
cash: 'dinheiro',
|
|
459
484
|
cheque: 'cheque',
|
|
@@ -513,7 +538,14 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
513
538
|
this.loadCategories(),
|
|
514
539
|
this.loadCostCenters(),
|
|
515
540
|
this.loadBankAccounts(),
|
|
516
|
-
this.listBankStatements(
|
|
541
|
+
this.listBankStatements({
|
|
542
|
+
page: 1,
|
|
543
|
+
pageSize: 1000,
|
|
544
|
+
search: undefined,
|
|
545
|
+
sortField: undefined,
|
|
546
|
+
sortOrder: undefined,
|
|
547
|
+
fields: undefined,
|
|
548
|
+
}),
|
|
517
549
|
this.getAccountsReceivableCollectionsDefault(),
|
|
518
550
|
this.loadTags(),
|
|
519
551
|
this.loadAuditLogs(),
|
|
@@ -528,7 +560,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
528
560
|
const costCenters = costCentersResult.status === 'fulfilled' ? costCentersResult.value : [];
|
|
529
561
|
const bankAccounts = bankAccountsResult.status === 'fulfilled' ? bankAccountsResult.value : [];
|
|
530
562
|
const bankStatements = bankStatementsResult.status === 'fulfilled'
|
|
531
|
-
? bankStatementsResult.value
|
|
563
|
+
? bankStatementsResult.value.data
|
|
532
564
|
: [];
|
|
533
565
|
const collectionsDefault = collectionsDefaultResult.status === 'fulfilled'
|
|
534
566
|
? collectionsDefaultResult.value
|
|
@@ -1446,7 +1478,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
1446
1478
|
if (!person) {
|
|
1447
1479
|
throw new common_1.NotFoundException('Person not found');
|
|
1448
1480
|
}
|
|
1449
|
-
const firstDueDate =
|
|
1481
|
+
const firstDueDate = this.parseLocalDate(data.first_due_date);
|
|
1450
1482
|
if (Number.isNaN(firstDueDate.getTime())) {
|
|
1451
1483
|
throw new common_1.BadRequestException('Invalid first due date');
|
|
1452
1484
|
}
|
|
@@ -1591,11 +1623,11 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
1591
1623
|
next.setMonth(next.getMonth() + months);
|
|
1592
1624
|
return next;
|
|
1593
1625
|
}
|
|
1594
|
-
async listAccountsPayableInstallments(paginationParams, status) {
|
|
1595
|
-
return this.listTitles('payable', paginationParams, status);
|
|
1626
|
+
async listAccountsPayableInstallments(paginationParams, status, filters) {
|
|
1627
|
+
return this.listTitles('payable', paginationParams, status, filters);
|
|
1596
1628
|
}
|
|
1597
|
-
async listAccountsReceivableInstallments(paginationParams, status) {
|
|
1598
|
-
return this.listTitles('receivable', paginationParams, status);
|
|
1629
|
+
async listAccountsReceivableInstallments(paginationParams, status, filters) {
|
|
1630
|
+
return this.listTitles('receivable', paginationParams, status, filters);
|
|
1599
1631
|
}
|
|
1600
1632
|
async getAccountsPayableInstallment(id, locale) {
|
|
1601
1633
|
const title = await this.getTitleById(id, 'payable', locale);
|
|
@@ -1822,23 +1854,27 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
1822
1854
|
async updateAccountsReceivableInstallmentTags(id, tagIds, locale) {
|
|
1823
1855
|
return this.updateTitleTags(id, 'receivable', tagIds, locale);
|
|
1824
1856
|
}
|
|
1825
|
-
async listBankAccounts() {
|
|
1826
|
-
const
|
|
1857
|
+
async listBankAccounts(paginationParams) {
|
|
1858
|
+
const paginated = await this.paginationService.paginate(this.prisma.bank_account, Object.assign(Object.assign({}, paginationParams), { sortField: (paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.sortField) || 'code', sortOrder: (paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.sortOrder) || api_pagination_1.PageOrderDirection.Asc }), {
|
|
1827
1859
|
include: {
|
|
1828
1860
|
bank_statement_line: {
|
|
1829
1861
|
select: {
|
|
1830
1862
|
amount_cents: true,
|
|
1831
1863
|
status: true,
|
|
1864
|
+
posted_date: true,
|
|
1865
|
+
description: true,
|
|
1832
1866
|
},
|
|
1833
1867
|
},
|
|
1834
1868
|
},
|
|
1835
1869
|
orderBy: [{ code: 'asc' }, { name: 'asc' }],
|
|
1836
1870
|
});
|
|
1837
|
-
return
|
|
1871
|
+
return Object.assign(Object.assign({}, paginated), { data: (paginated.data || []).map((bankAccount) => this.mapBankAccountToFront(bankAccount)) });
|
|
1838
1872
|
}
|
|
1839
|
-
async listTransfers(filters) {
|
|
1873
|
+
async listTransfers(paginationParams, filters) {
|
|
1840
1874
|
var _a;
|
|
1841
1875
|
const search = (_a = filters === null || filters === void 0 ? void 0 : filters.search) === null || _a === void 0 ? void 0 : _a.trim();
|
|
1876
|
+
const fromDate = this.parseFilterDate(filters === null || filters === void 0 ? void 0 : filters.from);
|
|
1877
|
+
const toDate = this.parseFilterDate(filters === null || filters === void 0 ? void 0 : filters.to, true);
|
|
1842
1878
|
const parsedBankAccountId = (filters === null || filters === void 0 ? void 0 : filters.bank_account_id)
|
|
1843
1879
|
? Number.parseInt(filters.bank_account_id, 10)
|
|
1844
1880
|
: undefined;
|
|
@@ -1848,7 +1884,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
1848
1884
|
let transferKeys;
|
|
1849
1885
|
if (search || bankAccountId) {
|
|
1850
1886
|
const filteredLines = await this.prisma.bank_statement_line.findMany({
|
|
1851
|
-
where: Object.assign(Object.assign({ external_id: {
|
|
1887
|
+
where: Object.assign(Object.assign(Object.assign({ external_id: {
|
|
1852
1888
|
startsWith: 'transfer:',
|
|
1853
1889
|
} }, (search
|
|
1854
1890
|
? {
|
|
@@ -1857,7 +1893,11 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
1857
1893
|
mode: 'insensitive',
|
|
1858
1894
|
},
|
|
1859
1895
|
}
|
|
1860
|
-
: {})), (bankAccountId ? { bank_account_id: bankAccountId } : {})),
|
|
1896
|
+
: {})), (bankAccountId ? { bank_account_id: bankAccountId } : {})), ((fromDate || toDate)
|
|
1897
|
+
? {
|
|
1898
|
+
posted_date: Object.assign(Object.assign({}, (fromDate ? { gte: fromDate } : {})), (toDate ? { lte: toDate } : {})),
|
|
1899
|
+
}
|
|
1900
|
+
: {})),
|
|
1861
1901
|
select: {
|
|
1862
1902
|
external_id: true,
|
|
1863
1903
|
},
|
|
@@ -1866,11 +1906,13 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
1866
1906
|
.map((line) => line.external_id)
|
|
1867
1907
|
.filter((externalId) => !!externalId)));
|
|
1868
1908
|
if (transferKeys.length === 0) {
|
|
1869
|
-
return []
|
|
1909
|
+
return Object.assign(Object.assign({}, this.paginateCollection([], paginationParams)), { summary: {
|
|
1910
|
+
totalTransferido: 0,
|
|
1911
|
+
} });
|
|
1870
1912
|
}
|
|
1871
1913
|
}
|
|
1872
1914
|
const transferLines = await this.prisma.bank_statement_line.findMany({
|
|
1873
|
-
where: Object.assign({}, (transferKeys
|
|
1915
|
+
where: Object.assign(Object.assign({}, (transferKeys
|
|
1874
1916
|
? {
|
|
1875
1917
|
external_id: {
|
|
1876
1918
|
in: transferKeys,
|
|
@@ -1880,7 +1922,11 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
1880
1922
|
external_id: {
|
|
1881
1923
|
startsWith: 'transfer:',
|
|
1882
1924
|
},
|
|
1883
|
-
})),
|
|
1925
|
+
})), ((fromDate || toDate)
|
|
1926
|
+
? {
|
|
1927
|
+
posted_date: Object.assign(Object.assign({}, (fromDate ? { gte: fromDate } : {})), (toDate ? { lte: toDate } : {})),
|
|
1928
|
+
}
|
|
1929
|
+
: {})),
|
|
1884
1930
|
select: {
|
|
1885
1931
|
id: true,
|
|
1886
1932
|
external_id: true,
|
|
@@ -1913,19 +1959,21 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
1913
1959
|
contaOrigemId: String(sourceLine.bank_account_id),
|
|
1914
1960
|
contaDestinoId: String(destinationLine.bank_account_id),
|
|
1915
1961
|
data: sourceLine.posted_date.toISOString(),
|
|
1916
|
-
valor: this.fromCents(
|
|
1962
|
+
valor: Math.abs(this.fromCents(sourceLine.amount_cents)),
|
|
1917
1963
|
descricao: sourceLine.description || destinationLine.description || '',
|
|
1918
1964
|
};
|
|
1919
1965
|
})
|
|
1920
1966
|
.filter(Boolean);
|
|
1921
|
-
return transfers
|
|
1967
|
+
return Object.assign(Object.assign({}, this.paginateCollection(transfers, paginationParams)), { summary: {
|
|
1968
|
+
totalTransferido: transfers.reduce((acc, transfer) => acc + Number((transfer === null || transfer === void 0 ? void 0 : transfer.valor) || 0), 0),
|
|
1969
|
+
} });
|
|
1922
1970
|
}
|
|
1923
1971
|
async createTransfer(data, userId) {
|
|
1924
1972
|
var _a;
|
|
1925
1973
|
const sourceAccountId = Number(data.source_account_id);
|
|
1926
1974
|
const destinationAccountId = Number(data.destination_account_id);
|
|
1927
1975
|
const amount = Number(data.amount);
|
|
1928
|
-
const postedDate =
|
|
1976
|
+
const postedDate = this.parseLocalDate(data.date);
|
|
1929
1977
|
if (Number.isNaN(sourceAccountId) ||
|
|
1930
1978
|
Number.isNaN(destinationAccountId) ||
|
|
1931
1979
|
sourceAccountId <= 0 ||
|
|
@@ -2168,16 +2216,22 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2168
2216
|
});
|
|
2169
2217
|
return Object.assign(Object.assign({}, paginated), { data: (paginated.data || []).map((period) => this.mapPeriodCloseToFront(period)) });
|
|
2170
2218
|
}
|
|
2171
|
-
async listBankStatements(bankAccountId, search) {
|
|
2219
|
+
async listBankStatements(paginationParams, bankAccountId, search, filters) {
|
|
2172
2220
|
const trimmedSearch = search === null || search === void 0 ? void 0 : search.trim();
|
|
2221
|
+
const fromDate = this.parseFilterDate(filters === null || filters === void 0 ? void 0 : filters.from);
|
|
2222
|
+
const toDate = this.parseFilterDate(filters === null || filters === void 0 ? void 0 : filters.to, true);
|
|
2173
2223
|
const statements = await this.prisma.bank_statement_line.findMany({
|
|
2174
|
-
where: Object.assign(Object.assign({}, (bankAccountId ? { bank_account_id: bankAccountId } : {})), (trimmedSearch
|
|
2224
|
+
where: Object.assign(Object.assign(Object.assign({}, (bankAccountId ? { bank_account_id: bankAccountId } : {})), (trimmedSearch
|
|
2175
2225
|
? {
|
|
2176
2226
|
description: {
|
|
2177
2227
|
contains: trimmedSearch,
|
|
2178
2228
|
mode: 'insensitive',
|
|
2179
2229
|
},
|
|
2180
2230
|
}
|
|
2231
|
+
: {})), ((fromDate || toDate)
|
|
2232
|
+
? {
|
|
2233
|
+
posted_date: Object.assign(Object.assign({}, (fromDate ? { gte: fromDate } : {})), (toDate ? { lte: toDate } : {})),
|
|
2234
|
+
}
|
|
2181
2235
|
: {})),
|
|
2182
2236
|
include: {
|
|
2183
2237
|
bank_account: {
|
|
@@ -2203,8 +2257,8 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2203
2257
|
},
|
|
2204
2258
|
orderBy: [{ posted_date: 'desc' }, { id: 'desc' }],
|
|
2205
2259
|
});
|
|
2206
|
-
|
|
2207
|
-
var _a, _b;
|
|
2260
|
+
const mappedStatements = statements.map((statement) => {
|
|
2261
|
+
var _a, _b, _c, _d, _e;
|
|
2208
2262
|
return ({
|
|
2209
2263
|
id: String(statement.id),
|
|
2210
2264
|
contaBancariaId: String(statement.bank_account_id),
|
|
@@ -2213,14 +2267,27 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2213
2267
|
valor: this.fromCents(statement.amount_cents),
|
|
2214
2268
|
tipo: statement.amount_cents >= 0 ? 'entrada' : 'saida',
|
|
2215
2269
|
statusConciliacao: this.mapStatementStatusToPt(statement.status),
|
|
2216
|
-
|
|
2270
|
+
isTransfer: ((_a = statement.external_id) === null || _a === void 0 ? void 0 : _a.startsWith('transfer:')) || false,
|
|
2271
|
+
canEdit: !((_b = statement.external_id) === null || _b === void 0 ? void 0 : _b.startsWith('transfer:')) &&
|
|
2272
|
+
statement.bank_reconciliation.length === 0,
|
|
2273
|
+
canDelete: !((_c = statement.external_id) === null || _c === void 0 ? void 0 : _c.startsWith('transfer:')) &&
|
|
2274
|
+
statement.bank_reconciliation.length === 0,
|
|
2275
|
+
reconciliationId: ((_d = statement.bank_reconciliation[0]) === null || _d === void 0 ? void 0 : _d.id)
|
|
2217
2276
|
? String(statement.bank_reconciliation[0].id)
|
|
2218
2277
|
: null,
|
|
2219
|
-
settlementId: ((
|
|
2278
|
+
settlementId: ((_e = statement.bank_reconciliation[0]) === null || _e === void 0 ? void 0 : _e.settlement_id)
|
|
2220
2279
|
? String(statement.bank_reconciliation[0].settlement_id)
|
|
2221
2280
|
: null,
|
|
2222
2281
|
});
|
|
2223
2282
|
});
|
|
2283
|
+
return Object.assign(Object.assign({}, this.paginateCollection(mappedStatements, paginationParams)), { summary: {
|
|
2284
|
+
totalEntradas: mappedStatements
|
|
2285
|
+
.filter((statement) => statement.tipo === 'entrada')
|
|
2286
|
+
.reduce((acc, statement) => acc + Number(statement.valor || 0), 0),
|
|
2287
|
+
totalSaidas: mappedStatements
|
|
2288
|
+
.filter((statement) => statement.tipo === 'saida')
|
|
2289
|
+
.reduce((acc, statement) => acc + Number(statement.valor || 0), 0),
|
|
2290
|
+
} });
|
|
2224
2291
|
}
|
|
2225
2292
|
async createBankReconciliation(data, locale, userId) {
|
|
2226
2293
|
var _a;
|
|
@@ -2279,7 +2346,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2279
2346
|
}
|
|
2280
2347
|
return this.settleTitleInstallment(title.id, {
|
|
2281
2348
|
installment_id: installment.id,
|
|
2282
|
-
amount: this.fromCents(
|
|
2349
|
+
amount: Math.abs(this.fromCents(statementLine.amount_cents)),
|
|
2283
2350
|
settled_at: statementLine.posted_date.toISOString(),
|
|
2284
2351
|
bank_account_id: statementLine.bank_account_id,
|
|
2285
2352
|
bank_statement_line_id: statementLine.id,
|
|
@@ -2328,7 +2395,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2328
2395
|
const payableAmounts = new Set();
|
|
2329
2396
|
const receivableAmounts = new Set();
|
|
2330
2397
|
for (const installment of openInstallments) {
|
|
2331
|
-
const amount =
|
|
2398
|
+
const amount = Number(installment.open_amount_cents);
|
|
2332
2399
|
if (installment.financial_title.title_type === 'payable') {
|
|
2333
2400
|
payableAmounts.add(amount);
|
|
2334
2401
|
}
|
|
@@ -2339,8 +2406,8 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2339
2406
|
let discrepancyCount = 0;
|
|
2340
2407
|
let differenceCents = 0;
|
|
2341
2408
|
for (const statement of pendingStatements) {
|
|
2342
|
-
const normalizedAmount = Math.abs(statement.amount_cents);
|
|
2343
|
-
differenceCents += statement.amount_cents;
|
|
2409
|
+
const normalizedAmount = Math.abs(Number(statement.amount_cents));
|
|
2410
|
+
differenceCents += Number(statement.amount_cents);
|
|
2344
2411
|
const hasPossibleMatch = statement.amount_cents < 0
|
|
2345
2412
|
? payableAmounts.has(normalizedAmount)
|
|
2346
2413
|
: receivableAmounts.has(normalizedAmount);
|
|
@@ -2353,8 +2420,16 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2353
2420
|
difference: this.fromCents(differenceCents),
|
|
2354
2421
|
};
|
|
2355
2422
|
}
|
|
2356
|
-
async exportBankStatementsCsv(bankAccountId, search) {
|
|
2357
|
-
const
|
|
2423
|
+
async exportBankStatementsCsv(bankAccountId, search, filters) {
|
|
2424
|
+
const statementsResult = await this.listBankStatements({
|
|
2425
|
+
page: 1,
|
|
2426
|
+
pageSize: 100000,
|
|
2427
|
+
search: undefined,
|
|
2428
|
+
sortField: undefined,
|
|
2429
|
+
sortOrder: undefined,
|
|
2430
|
+
fields: undefined,
|
|
2431
|
+
}, bankAccountId, search, filters);
|
|
2432
|
+
const statements = statementsResult.data;
|
|
2358
2433
|
const headers = [
|
|
2359
2434
|
'id',
|
|
2360
2435
|
'data',
|
|
@@ -2389,7 +2464,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2389
2464
|
var _a;
|
|
2390
2465
|
const bankAccountId = Number(data.bank_account_id);
|
|
2391
2466
|
const amount = Number(data.amount);
|
|
2392
|
-
const postedAt = data.date ?
|
|
2467
|
+
const postedAt = data.date ? this.parseLocalDate(data.date) : new Date();
|
|
2393
2468
|
if (Number.isNaN(bankAccountId) || bankAccountId <= 0) {
|
|
2394
2469
|
throw new common_1.BadRequestException('bank_account_id is required');
|
|
2395
2470
|
}
|
|
@@ -2446,6 +2521,210 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2446
2521
|
statusConciliacao: this.mapStatementStatusToPt(created.status),
|
|
2447
2522
|
};
|
|
2448
2523
|
}
|
|
2524
|
+
async createBankStatementEntry(data, userId) {
|
|
2525
|
+
var _a;
|
|
2526
|
+
const bankAccountId = Number(data.bank_account_id);
|
|
2527
|
+
const amount = Number(data.amount);
|
|
2528
|
+
const postedDate = new Date(`${data.date}T00:00:00`);
|
|
2529
|
+
if (Number.isNaN(bankAccountId) || bankAccountId <= 0) {
|
|
2530
|
+
throw new common_1.BadRequestException('bank_account_id is required');
|
|
2531
|
+
}
|
|
2532
|
+
if (Number.isNaN(amount) || amount <= 0) {
|
|
2533
|
+
throw new common_1.BadRequestException('amount must be greater than zero');
|
|
2534
|
+
}
|
|
2535
|
+
if (Number.isNaN(postedDate.getTime())) {
|
|
2536
|
+
throw new common_1.BadRequestException('Invalid statement date');
|
|
2537
|
+
}
|
|
2538
|
+
const description = (_a = data.description) === null || _a === void 0 ? void 0 : _a.trim();
|
|
2539
|
+
if (!description) {
|
|
2540
|
+
throw new common_1.BadRequestException('description is required');
|
|
2541
|
+
}
|
|
2542
|
+
const bankAccount = await this.prisma.bank_account.findUnique({
|
|
2543
|
+
where: { id: bankAccountId },
|
|
2544
|
+
select: { id: true },
|
|
2545
|
+
});
|
|
2546
|
+
if (!bankAccount) {
|
|
2547
|
+
throw new common_1.NotFoundException('Bank account not found');
|
|
2548
|
+
}
|
|
2549
|
+
const signedAmountCents = data.type === 'saida'
|
|
2550
|
+
? -Math.abs(this.toCents(amount))
|
|
2551
|
+
: Math.abs(this.toCents(amount));
|
|
2552
|
+
const created = await this.prisma.$transaction(async (tx) => {
|
|
2553
|
+
await this.assertDateNotInClosedPeriod(tx, postedDate, 'create bank statement entry');
|
|
2554
|
+
const reference = `manual-entry:${bankAccountId}:${Date.now()}`;
|
|
2555
|
+
const statement = await tx.bank_statement.create({
|
|
2556
|
+
data: {
|
|
2557
|
+
bank_account_id: bankAccountId,
|
|
2558
|
+
source_type: 'manual',
|
|
2559
|
+
imported_at: postedDate,
|
|
2560
|
+
imported_by_user_id: userId,
|
|
2561
|
+
idempotency_key: reference,
|
|
2562
|
+
period_start: postedDate,
|
|
2563
|
+
period_end: postedDate,
|
|
2564
|
+
},
|
|
2565
|
+
});
|
|
2566
|
+
return tx.bank_statement_line.create({
|
|
2567
|
+
data: {
|
|
2568
|
+
bank_statement_id: statement.id,
|
|
2569
|
+
bank_account_id: bankAccountId,
|
|
2570
|
+
posted_date: postedDate,
|
|
2571
|
+
amount_cents: signedAmountCents,
|
|
2572
|
+
description,
|
|
2573
|
+
status: 'pending',
|
|
2574
|
+
dedupe_key: `${reference}:${Math.round(Math.random() * 1000000)}`,
|
|
2575
|
+
},
|
|
2576
|
+
});
|
|
2577
|
+
});
|
|
2578
|
+
return {
|
|
2579
|
+
id: String(created.id),
|
|
2580
|
+
contaBancariaId: String(created.bank_account_id),
|
|
2581
|
+
data: created.posted_date.toISOString(),
|
|
2582
|
+
descricao: created.description,
|
|
2583
|
+
valor: this.fromCents(created.amount_cents),
|
|
2584
|
+
tipo: created.amount_cents >= 0 ? 'entrada' : 'saida',
|
|
2585
|
+
statusConciliacao: this.mapStatementStatusToPt(created.status),
|
|
2586
|
+
isTransfer: false,
|
|
2587
|
+
canEdit: true,
|
|
2588
|
+
canDelete: true,
|
|
2589
|
+
reconciliationId: null,
|
|
2590
|
+
settlementId: null,
|
|
2591
|
+
};
|
|
2592
|
+
}
|
|
2593
|
+
async updateBankStatementEntry(id, data, userId) {
|
|
2594
|
+
if (data.amount !== undefined) {
|
|
2595
|
+
const amount = Number(data.amount);
|
|
2596
|
+
if (Number.isNaN(amount) || amount <= 0) {
|
|
2597
|
+
throw new common_1.BadRequestException('amount must be greater than zero');
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
if (data.amount === undefined && data.description === undefined && data.date === undefined) {
|
|
2601
|
+
throw new common_1.BadRequestException('At least one field must be provided for update');
|
|
2602
|
+
}
|
|
2603
|
+
const updated = await this.prisma.$transaction(async (tx) => {
|
|
2604
|
+
var _a;
|
|
2605
|
+
const statementLine = await tx.bank_statement_line.findUnique({
|
|
2606
|
+
where: { id },
|
|
2607
|
+
include: {
|
|
2608
|
+
bank_reconciliation: {
|
|
2609
|
+
where: {
|
|
2610
|
+
status: {
|
|
2611
|
+
in: ['pending', 'reconciled', 'adjusted'],
|
|
2612
|
+
},
|
|
2613
|
+
},
|
|
2614
|
+
select: {
|
|
2615
|
+
id: true,
|
|
2616
|
+
},
|
|
2617
|
+
take: 1,
|
|
2618
|
+
},
|
|
2619
|
+
},
|
|
2620
|
+
});
|
|
2621
|
+
if (!statementLine) {
|
|
2622
|
+
throw new common_1.NotFoundException('Bank statement line not found');
|
|
2623
|
+
}
|
|
2624
|
+
if ((_a = statementLine.external_id) === null || _a === void 0 ? void 0 : _a.startsWith('transfer:')) {
|
|
2625
|
+
throw new common_1.ConflictException('Transfer movements cannot be edited');
|
|
2626
|
+
}
|
|
2627
|
+
if (statementLine.bank_reconciliation.length > 0) {
|
|
2628
|
+
throw new common_1.ConflictException('Reconciled movements cannot be edited');
|
|
2629
|
+
}
|
|
2630
|
+
const targetDate = data.date ? this.parseLocalDate(data.date) : statementLine.posted_date;
|
|
2631
|
+
await this.assertDateNotInClosedPeriod(tx, targetDate, 'update bank statement entry');
|
|
2632
|
+
const updateData = {};
|
|
2633
|
+
if (data.amount !== undefined) {
|
|
2634
|
+
const amount = Number(data.amount);
|
|
2635
|
+
updateData.amount_cents =
|
|
2636
|
+
statementLine.amount_cents < 0
|
|
2637
|
+
? -Math.abs(this.toCents(amount))
|
|
2638
|
+
: Math.abs(this.toCents(amount));
|
|
2639
|
+
}
|
|
2640
|
+
if (data.description !== undefined) {
|
|
2641
|
+
updateData.description = data.description.trim();
|
|
2642
|
+
}
|
|
2643
|
+
if (data.date !== undefined) {
|
|
2644
|
+
updateData.posted_date = this.parseLocalDate(data.date);
|
|
2645
|
+
}
|
|
2646
|
+
const result = await tx.bank_statement_line.update({
|
|
2647
|
+
where: { id },
|
|
2648
|
+
data: updateData,
|
|
2649
|
+
});
|
|
2650
|
+
await this.createAuditLog(tx, {
|
|
2651
|
+
action: 'UPDATE_BANK_STATEMENT_LINE',
|
|
2652
|
+
entityTable: 'bank_statement_line',
|
|
2653
|
+
entityId: String(result.id),
|
|
2654
|
+
actorUserId: userId,
|
|
2655
|
+
summary: `Updated bank statement line ${result.id}`,
|
|
2656
|
+
});
|
|
2657
|
+
return result;
|
|
2658
|
+
});
|
|
2659
|
+
return {
|
|
2660
|
+
id: String(updated.id),
|
|
2661
|
+
contaBancariaId: String(updated.bank_account_id),
|
|
2662
|
+
data: updated.posted_date.toISOString(),
|
|
2663
|
+
descricao: updated.description,
|
|
2664
|
+
valor: this.fromCents(updated.amount_cents),
|
|
2665
|
+
tipo: updated.amount_cents >= 0 ? 'entrada' : 'saida',
|
|
2666
|
+
statusConciliacao: this.mapStatementStatusToPt(updated.status),
|
|
2667
|
+
isTransfer: false,
|
|
2668
|
+
canEdit: true,
|
|
2669
|
+
canDelete: true,
|
|
2670
|
+
reconciliationId: null,
|
|
2671
|
+
settlementId: null,
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
async deleteBankStatementEntry(id, userId) {
|
|
2675
|
+
return this.prisma.$transaction(async (tx) => {
|
|
2676
|
+
var _a;
|
|
2677
|
+
const statementLine = await tx.bank_statement_line.findUnique({
|
|
2678
|
+
where: { id },
|
|
2679
|
+
include: {
|
|
2680
|
+
bank_reconciliation: {
|
|
2681
|
+
where: {
|
|
2682
|
+
status: {
|
|
2683
|
+
in: ['pending', 'reconciled', 'adjusted'],
|
|
2684
|
+
},
|
|
2685
|
+
},
|
|
2686
|
+
select: {
|
|
2687
|
+
id: true,
|
|
2688
|
+
},
|
|
2689
|
+
take: 1,
|
|
2690
|
+
},
|
|
2691
|
+
},
|
|
2692
|
+
});
|
|
2693
|
+
if (!statementLine) {
|
|
2694
|
+
throw new common_1.NotFoundException('Bank statement line not found');
|
|
2695
|
+
}
|
|
2696
|
+
if ((_a = statementLine.external_id) === null || _a === void 0 ? void 0 : _a.startsWith('transfer:')) {
|
|
2697
|
+
throw new common_1.ConflictException('Transfer movements cannot be deleted');
|
|
2698
|
+
}
|
|
2699
|
+
if (statementLine.bank_reconciliation.length > 0) {
|
|
2700
|
+
throw new common_1.ConflictException('Reconciled movements cannot be deleted');
|
|
2701
|
+
}
|
|
2702
|
+
await this.assertDateNotInClosedPeriod(tx, statementLine.posted_date, 'delete bank statement entry');
|
|
2703
|
+
await tx.bank_statement_line.delete({
|
|
2704
|
+
where: { id },
|
|
2705
|
+
});
|
|
2706
|
+
const remainingLines = await tx.bank_statement_line.count({
|
|
2707
|
+
where: {
|
|
2708
|
+
bank_statement_id: statementLine.bank_statement_id,
|
|
2709
|
+
},
|
|
2710
|
+
});
|
|
2711
|
+
if (remainingLines === 0) {
|
|
2712
|
+
await tx.bank_statement.delete({
|
|
2713
|
+
where: {
|
|
2714
|
+
id: statementLine.bank_statement_id,
|
|
2715
|
+
},
|
|
2716
|
+
});
|
|
2717
|
+
}
|
|
2718
|
+
await this.createAuditLog(tx, {
|
|
2719
|
+
action: 'DELETE_BANK_STATEMENT_LINE',
|
|
2720
|
+
entityTable: 'bank_statement_line',
|
|
2721
|
+
entityId: String(statementLine.id),
|
|
2722
|
+
actorUserId: userId,
|
|
2723
|
+
summary: `Deleted bank statement line ${statementLine.id}`,
|
|
2724
|
+
});
|
|
2725
|
+
return { success: true };
|
|
2726
|
+
});
|
|
2727
|
+
}
|
|
2449
2728
|
async importBankStatements(bankAccountId, file, locale, userId) {
|
|
2450
2729
|
if (!file) {
|
|
2451
2730
|
throw new common_1.BadRequestException('File is required');
|
|
@@ -2790,6 +3069,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2790
3069
|
const accountType = this.mapAccountTypeFromPt(data.type);
|
|
2791
3070
|
const code = this.generateBankAccountCode(data.bank, data.account);
|
|
2792
3071
|
const name = ((_a = data.description) === null || _a === void 0 ? void 0 : _a.trim()) || data.bank;
|
|
3072
|
+
const startDate = this.parseFilterDate(data.start_date) || new Date();
|
|
2793
3073
|
const createdAccount = await this.prisma.$transaction(async (tx) => {
|
|
2794
3074
|
var _a;
|
|
2795
3075
|
const account = await tx.bank_account.create({
|
|
@@ -2805,7 +3085,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2805
3085
|
},
|
|
2806
3086
|
});
|
|
2807
3087
|
if (data.initial_balance && data.initial_balance > 0) {
|
|
2808
|
-
const postedDate =
|
|
3088
|
+
const postedDate = startDate;
|
|
2809
3089
|
await this.assertDateNotInClosedPeriod(tx, postedDate, 'create bank account initial balance');
|
|
2810
3090
|
const statement = await tx.bank_statement.create({
|
|
2811
3091
|
data: {
|
|
@@ -2836,6 +3116,8 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2836
3116
|
select: {
|
|
2837
3117
|
amount_cents: true,
|
|
2838
3118
|
status: true,
|
|
3119
|
+
posted_date: true,
|
|
3120
|
+
description: true,
|
|
2839
3121
|
},
|
|
2840
3122
|
},
|
|
2841
3123
|
},
|
|
@@ -2870,8 +3152,8 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2870
3152
|
}
|
|
2871
3153
|
async createPeriodClose(data, userId) {
|
|
2872
3154
|
var _a;
|
|
2873
|
-
const periodStart =
|
|
2874
|
-
const periodEnd =
|
|
3155
|
+
const periodStart = this.parseLocalDate(data.period_start);
|
|
3156
|
+
const periodEnd = this.parseLocalDate(data.period_end);
|
|
2875
3157
|
if (Number.isNaN(periodStart.getTime()) ||
|
|
2876
3158
|
Number.isNaN(periodEnd.getTime())) {
|
|
2877
3159
|
throw new common_1.BadRequestException('Invalid period dates');
|
|
@@ -2934,6 +3216,8 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
2934
3216
|
select: {
|
|
2935
3217
|
amount_cents: true,
|
|
2936
3218
|
status: true,
|
|
3219
|
+
posted_date: true,
|
|
3220
|
+
description: true,
|
|
2937
3221
|
},
|
|
2938
3222
|
},
|
|
2939
3223
|
},
|
|
@@ -3048,6 +3332,85 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3048
3332
|
});
|
|
3049
3333
|
return { success: true };
|
|
3050
3334
|
}
|
|
3335
|
+
async listCurrencies(paginationParams) {
|
|
3336
|
+
const currencies = await this.prisma.currency.findMany({
|
|
3337
|
+
orderBy: [{ code: 'asc' }],
|
|
3338
|
+
});
|
|
3339
|
+
return currencies.map((c) => ({
|
|
3340
|
+
id: String(c.id),
|
|
3341
|
+
code: c.code,
|
|
3342
|
+
name: c.name,
|
|
3343
|
+
symbol: c.symbol,
|
|
3344
|
+
status: c.status,
|
|
3345
|
+
ativo: c.status === 'active',
|
|
3346
|
+
}));
|
|
3347
|
+
}
|
|
3348
|
+
async createCurrency(data) {
|
|
3349
|
+
const existing = await this.prisma.currency.findUnique({
|
|
3350
|
+
where: { code: data.code.toUpperCase() },
|
|
3351
|
+
select: { id: true },
|
|
3352
|
+
});
|
|
3353
|
+
if (existing) {
|
|
3354
|
+
throw new common_1.ConflictException(`Currency with code ${data.code.toUpperCase()} already exists`);
|
|
3355
|
+
}
|
|
3356
|
+
const created = await this.prisma.currency.create({
|
|
3357
|
+
data: {
|
|
3358
|
+
code: data.code.toUpperCase(),
|
|
3359
|
+
name: data.name.trim(),
|
|
3360
|
+
symbol: data.symbol.trim(),
|
|
3361
|
+
status: 'active',
|
|
3362
|
+
},
|
|
3363
|
+
});
|
|
3364
|
+
return {
|
|
3365
|
+
id: String(created.id),
|
|
3366
|
+
code: created.code,
|
|
3367
|
+
name: created.name,
|
|
3368
|
+
symbol: created.symbol,
|
|
3369
|
+
status: created.status,
|
|
3370
|
+
ativo: created.status === 'active',
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
async updateCurrency(id, data) {
|
|
3374
|
+
var _a, _b, _c;
|
|
3375
|
+
const current = await this.prisma.currency.findUnique({
|
|
3376
|
+
where: { id },
|
|
3377
|
+
select: { id: true },
|
|
3378
|
+
});
|
|
3379
|
+
if (!current) {
|
|
3380
|
+
throw new common_1.NotFoundException('Currency not found');
|
|
3381
|
+
}
|
|
3382
|
+
const updated = await this.prisma.currency.update({
|
|
3383
|
+
where: { id },
|
|
3384
|
+
data: {
|
|
3385
|
+
code: (_a = data.code) === null || _a === void 0 ? void 0 : _a.toUpperCase(),
|
|
3386
|
+
name: (_b = data.name) === null || _b === void 0 ? void 0 : _b.trim(),
|
|
3387
|
+
symbol: (_c = data.symbol) === null || _c === void 0 ? void 0 : _c.trim(),
|
|
3388
|
+
status: data.status,
|
|
3389
|
+
},
|
|
3390
|
+
});
|
|
3391
|
+
return {
|
|
3392
|
+
id: String(updated.id),
|
|
3393
|
+
code: updated.code,
|
|
3394
|
+
name: updated.name,
|
|
3395
|
+
symbol: updated.symbol,
|
|
3396
|
+
status: updated.status,
|
|
3397
|
+
ativo: updated.status === 'active',
|
|
3398
|
+
};
|
|
3399
|
+
}
|
|
3400
|
+
async deleteCurrency(id) {
|
|
3401
|
+
const current = await this.prisma.currency.findUnique({
|
|
3402
|
+
where: { id },
|
|
3403
|
+
select: { id: true },
|
|
3404
|
+
});
|
|
3405
|
+
if (!current) {
|
|
3406
|
+
throw new common_1.NotFoundException('Currency not found');
|
|
3407
|
+
}
|
|
3408
|
+
await this.prisma.currency.update({
|
|
3409
|
+
where: { id },
|
|
3410
|
+
data: { status: 'inactive' },
|
|
3411
|
+
});
|
|
3412
|
+
return { success: true };
|
|
3413
|
+
}
|
|
3051
3414
|
async deleteFinanceCategory(id) {
|
|
3052
3415
|
const current = await this.prisma.finance_category.findUnique({
|
|
3053
3416
|
where: { id },
|
|
@@ -3064,10 +3427,12 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3064
3427
|
});
|
|
3065
3428
|
return { success: true };
|
|
3066
3429
|
}
|
|
3067
|
-
async listTitles(titleType, paginationParams, status) {
|
|
3430
|
+
async listTitles(titleType, paginationParams, status, filters) {
|
|
3068
3431
|
var _a;
|
|
3069
3432
|
const prismaStatus = this.mapStatusFromPt(status);
|
|
3070
3433
|
const search = (_a = paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.search) === null || _a === void 0 ? void 0 : _a.trim();
|
|
3434
|
+
const fromDate = this.parseFilterDate(filters === null || filters === void 0 ? void 0 : filters.from);
|
|
3435
|
+
const toDate = this.parseFilterDate(filters === null || filters === void 0 ? void 0 : filters.to, true);
|
|
3071
3436
|
const where = {
|
|
3072
3437
|
title_type: titleType,
|
|
3073
3438
|
};
|
|
@@ -3092,6 +3457,13 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3092
3457
|
},
|
|
3093
3458
|
];
|
|
3094
3459
|
}
|
|
3460
|
+
if (fromDate || toDate) {
|
|
3461
|
+
where.financial_installment = {
|
|
3462
|
+
some: {
|
|
3463
|
+
due_date: Object.assign(Object.assign({}, (fromDate ? { gte: fromDate } : {})), (toDate ? { lte: toDate } : {})),
|
|
3464
|
+
},
|
|
3465
|
+
};
|
|
3466
|
+
}
|
|
3095
3467
|
const normalizedPaginationParams = Object.assign(Object.assign({}, paginationParams), { sortField: (paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.sortField) || 'created_at', sortOrder: (paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.sortOrder) || api_pagination_1.PageOrderDirection.Desc });
|
|
3096
3468
|
const paginated = await this.paginationService.paginate(this.prisma.financial_title, normalizedPaginationParams, {
|
|
3097
3469
|
where,
|
|
@@ -3160,8 +3532,8 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3160
3532
|
}
|
|
3161
3533
|
}
|
|
3162
3534
|
await this.assertDateNotInClosedPeriod(tx, data.competence_date
|
|
3163
|
-
?
|
|
3164
|
-
:
|
|
3535
|
+
? this.parseLocalDate(data.competence_date)
|
|
3536
|
+
: this.parseLocalDate(installments[0].due_date), 'create title');
|
|
3165
3537
|
const title = await tx.financial_title.create({
|
|
3166
3538
|
data: {
|
|
3167
3539
|
person_id: data.person_id,
|
|
@@ -3170,9 +3542,9 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3170
3542
|
document_number: data.document_number,
|
|
3171
3543
|
description: data.description,
|
|
3172
3544
|
competence_date: data.competence_date
|
|
3173
|
-
?
|
|
3545
|
+
? this.parseLocalDate(data.competence_date)
|
|
3174
3546
|
: null,
|
|
3175
|
-
issue_date: data.issue_date ?
|
|
3547
|
+
issue_date: data.issue_date ? this.parseLocalDate(data.issue_date) : null,
|
|
3176
3548
|
total_amount_cents: this.toCents(data.total_amount),
|
|
3177
3549
|
finance_category_id: data.finance_category_id,
|
|
3178
3550
|
created_by_user_id: userId,
|
|
@@ -3195,12 +3567,12 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3195
3567
|
title_id: title.id,
|
|
3196
3568
|
installment_number: installment.installment_number,
|
|
3197
3569
|
competence_date: data.competence_date
|
|
3198
|
-
?
|
|
3199
|
-
:
|
|
3200
|
-
due_date:
|
|
3570
|
+
? this.parseLocalDate(data.competence_date)
|
|
3571
|
+
: this.parseLocalDate(installment.due_date),
|
|
3572
|
+
due_date: this.parseLocalDate(installment.due_date),
|
|
3201
3573
|
amount_cents: amountCents,
|
|
3202
3574
|
open_amount_cents: amountCents,
|
|
3203
|
-
status: this.resolveInstallmentStatus(amountCents, amountCents,
|
|
3575
|
+
status: this.resolveInstallmentStatus(amountCents, amountCents, this.parseLocalDate(installment.due_date)),
|
|
3204
3576
|
notes: data.description,
|
|
3205
3577
|
},
|
|
3206
3578
|
});
|
|
@@ -3296,7 +3668,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3296
3668
|
}
|
|
3297
3669
|
}
|
|
3298
3670
|
await this.assertDateNotInClosedPeriod(tx, data.competence_date
|
|
3299
|
-
?
|
|
3671
|
+
? this.parseLocalDate(data.competence_date)
|
|
3300
3672
|
: new Date(installments[0].due_date), 'update title');
|
|
3301
3673
|
const installmentIds = title.financial_installment.map((item) => item.id);
|
|
3302
3674
|
if (installmentIds.length > 0) {
|
|
@@ -3321,9 +3693,9 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3321
3693
|
document_number: data.document_number,
|
|
3322
3694
|
description: data.description,
|
|
3323
3695
|
competence_date: data.competence_date
|
|
3324
|
-
?
|
|
3696
|
+
? this.parseLocalDate(data.competence_date)
|
|
3325
3697
|
: null,
|
|
3326
|
-
issue_date: data.issue_date ?
|
|
3698
|
+
issue_date: data.issue_date ? this.parseLocalDate(data.issue_date) : null,
|
|
3327
3699
|
total_amount_cents: this.toCents(data.total_amount),
|
|
3328
3700
|
finance_category_id: data.finance_category_id,
|
|
3329
3701
|
},
|
|
@@ -3356,12 +3728,12 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3356
3728
|
title_id: title.id,
|
|
3357
3729
|
installment_number: installment.installment_number,
|
|
3358
3730
|
competence_date: data.competence_date
|
|
3359
|
-
?
|
|
3360
|
-
:
|
|
3361
|
-
due_date:
|
|
3731
|
+
? this.parseLocalDate(data.competence_date)
|
|
3732
|
+
: this.parseLocalDate(installment.due_date),
|
|
3733
|
+
due_date: this.parseLocalDate(installment.due_date),
|
|
3362
3734
|
amount_cents: amountCents,
|
|
3363
3735
|
open_amount_cents: amountCents,
|
|
3364
|
-
status: this.resolveInstallmentStatus(amountCents, amountCents,
|
|
3736
|
+
status: this.resolveInstallmentStatus(amountCents, amountCents, this.parseLocalDate(installment.due_date)),
|
|
3365
3737
|
notes: data.description,
|
|
3366
3738
|
},
|
|
3367
3739
|
});
|
|
@@ -3721,7 +4093,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3721
4093
|
statementLine.bank_account_id !== data.bank_account_id) {
|
|
3722
4094
|
throw new common_1.ConflictException('Bank statement line does not belong to informed bank account');
|
|
3723
4095
|
}
|
|
3724
|
-
if (Math.abs(statementLine.amount_cents) !== amountCents) {
|
|
4096
|
+
if (Math.abs(Number(statementLine.amount_cents)) !== amountCents) {
|
|
3725
4097
|
throw new common_1.ConflictException('Bank statement amount and settlement amount must match');
|
|
3726
4098
|
}
|
|
3727
4099
|
const hasReconciliation = await tx.bank_reconciliation.findFirst({
|
|
@@ -3812,7 +4184,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
3812
4184
|
if (!updatedInstallment) {
|
|
3813
4185
|
throw new common_1.NotFoundException('Installment not found');
|
|
3814
4186
|
}
|
|
3815
|
-
const nextInstallmentStatus = this.resolveInstallmentStatus(updatedInstallment.amount_cents, updatedInstallment.open_amount_cents, updatedInstallment.due_date);
|
|
4187
|
+
const nextInstallmentStatus = this.resolveInstallmentStatus(Number(updatedInstallment.amount_cents), Number(updatedInstallment.open_amount_cents), updatedInstallment.due_date);
|
|
3816
4188
|
if (updatedInstallment.status !== nextInstallmentStatus) {
|
|
3817
4189
|
await tx.financial_installment.update({
|
|
3818
4190
|
where: {
|
|
@@ -4187,6 +4559,8 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
4187
4559
|
select: {
|
|
4188
4560
|
amount_cents: true,
|
|
4189
4561
|
status: true,
|
|
4562
|
+
posted_date: true,
|
|
4563
|
+
description: true,
|
|
4190
4564
|
},
|
|
4191
4565
|
},
|
|
4192
4566
|
},
|
|
@@ -4484,6 +4858,29 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
4484
4858
|
};
|
|
4485
4859
|
return statusMap[status] || 'aberto';
|
|
4486
4860
|
}
|
|
4861
|
+
paginateCollection(items, paginationParams) {
|
|
4862
|
+
const requestedPage = Number((paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.page) || 1);
|
|
4863
|
+
const requestedPageSize = Number((paginationParams === null || paginationParams === void 0 ? void 0 : paginationParams.pageSize) || 10);
|
|
4864
|
+
const page = Number.isNaN(requestedPage) || requestedPage < 1
|
|
4865
|
+
? 1
|
|
4866
|
+
: requestedPage;
|
|
4867
|
+
const pageSize = Number.isNaN(requestedPageSize) || requestedPageSize < 1
|
|
4868
|
+
? 10
|
|
4869
|
+
: requestedPageSize;
|
|
4870
|
+
const total = items.length;
|
|
4871
|
+
const lastPage = Math.max(1, Math.ceil(total / pageSize));
|
|
4872
|
+
const currentPage = Math.min(page, lastPage);
|
|
4873
|
+
const start = (currentPage - 1) * pageSize;
|
|
4874
|
+
return {
|
|
4875
|
+
data: items.slice(start, start + pageSize),
|
|
4876
|
+
total,
|
|
4877
|
+
page: currentPage,
|
|
4878
|
+
pageSize,
|
|
4879
|
+
prev: currentPage > 1 ? currentPage - 1 : null,
|
|
4880
|
+
next: currentPage < lastPage ? currentPage + 1 : null,
|
|
4881
|
+
lastPage,
|
|
4882
|
+
};
|
|
4883
|
+
}
|
|
4487
4884
|
normalizeTagSlug(value) {
|
|
4488
4885
|
if (!value) {
|
|
4489
4886
|
return '';
|
|
@@ -4566,10 +4963,14 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
4566
4963
|
}
|
|
4567
4964
|
mapBankAccountToFront(bankAccount) {
|
|
4568
4965
|
var _a;
|
|
4569
|
-
const currentCents = (bankAccount.bank_statement_line || []).reduce((acc, line) => acc + line.amount_cents, 0);
|
|
4966
|
+
const currentCents = (bankAccount.bank_statement_line || []).reduce((acc, line) => acc + Number(line.amount_cents), 0);
|
|
4570
4967
|
const reconciledCents = (bankAccount.bank_statement_line || []).reduce((acc, line) => line.status === 'reconciled' || line.status === 'adjusted'
|
|
4571
|
-
? acc + line.amount_cents
|
|
4968
|
+
? acc + Number(line.amount_cents)
|
|
4572
4969
|
: acc, 0);
|
|
4970
|
+
const initialLine = (bankAccount.bank_statement_line || []).find((line) => line.description === 'Saldo inicial');
|
|
4971
|
+
const dataInicial = (initialLine === null || initialLine === void 0 ? void 0 : initialLine.posted_date)
|
|
4972
|
+
? new Date(initialLine.posted_date).toISOString().slice(0, 10)
|
|
4973
|
+
: null;
|
|
4573
4974
|
return {
|
|
4574
4975
|
id: String(bankAccount.id),
|
|
4575
4976
|
codigo: bankAccount.code,
|
|
@@ -4582,6 +4983,7 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
4582
4983
|
saldoAtual: this.fromCents(currentCents),
|
|
4583
4984
|
saldoConciliado: this.fromCents(reconciledCents),
|
|
4584
4985
|
ativo: bankAccount.status === 'active',
|
|
4986
|
+
dataInicial,
|
|
4585
4987
|
};
|
|
4586
4988
|
}
|
|
4587
4989
|
mapCostCenterToFront(costCenter) {
|
|
@@ -4825,6 +5227,17 @@ let FinanceService = FinanceService_1 = class FinanceService {
|
|
|
4825
5227
|
toCents(value) {
|
|
4826
5228
|
return Math.round(value * 100);
|
|
4827
5229
|
}
|
|
5230
|
+
/**
|
|
5231
|
+
* Parses a date-only string (YYYY-MM-DD) as local noon to avoid
|
|
5232
|
+
* timezone shifts that would cause the date to appear as the previous day
|
|
5233
|
+
* in UTC-negative timezones.
|
|
5234
|
+
*/
|
|
5235
|
+
parseLocalDate(dateString) {
|
|
5236
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
|
|
5237
|
+
return new Date(dateString + 'T12:00:00.000Z');
|
|
5238
|
+
}
|
|
5239
|
+
return new Date(dateString);
|
|
5240
|
+
}
|
|
4828
5241
|
fromCents(value) {
|
|
4829
5242
|
if (value === null || value === undefined) {
|
|
4830
5243
|
return 0;
|