@accounter/server 0.0.9-alpha-20251210173458-9f3d75bb8729ec6038c777f7dbf9a1b5fa727888 → 0.0.9-alpha-20251210173721-a5bb944d9abd3f354daf897072b78bea4d8269c9
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/CHANGELOG.md +5 -21
- package/dist/server/src/__tests__/helpers/db-setup.d.ts +1 -0
- package/dist/server/src/__tests__/helpers/db-setup.js +2 -0
- package/dist/server/src/__tests__/helpers/db-setup.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js +31 -23
- package/dist/server/src/__tests__/helpers/seed-helpers.business.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js +8 -8
- package/dist/server/src/__tests__/helpers/seed-helpers.concurrent.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js +50 -41
- package/dist/server/src/__tests__/helpers/seed-helpers.financial-entity.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js +31 -23
- package/dist/server/src/__tests__/helpers/seed-helpers.tax-category.test.js.map +1 -1
- package/dist/server/src/__tests__/helpers/test-db-config.js +1 -1
- package/dist/server/src/__tests__/helpers/test-db-config.js.map +1 -1
- package/dist/server/src/__tests__/seed-admin-context.integration.test.js +131 -128
- package/dist/server/src/__tests__/seed-admin-context.integration.test.js.map +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.d.ts +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.js +1 -1
- package/dist/server/src/modules/business-trips/providers/business-trips.provider.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/helpers/db-setup.ts +3 -0
- package/src/__tests__/helpers/seed-helpers.business.test.ts +147 -145
- package/src/__tests__/helpers/seed-helpers.concurrent.test.ts +10 -10
- package/src/__tests__/helpers/seed-helpers.financial-entity.test.ts +231 -218
- package/src/__tests__/helpers/seed-helpers.tax-category.test.ts +164 -162
- package/src/__tests__/helpers/test-db-config.ts +1 -1
- package/src/__tests__/seed-admin-context.integration.test.ts +208 -199
- package/src/modules/business-trips/providers/business-trips.provider.ts +1 -1
|
@@ -1,231 +1,240 @@
|
|
|
1
|
-
import { describe, expect, it, beforeAll, afterAll } from 'vitest';
|
|
2
|
-
import
|
|
1
|
+
import { describe, expect, it, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import pg from 'pg';
|
|
3
|
+
import { testDbConfig } from './helpers/test-db-config.js';
|
|
3
4
|
import { seedAdminCore } from '../../scripts/seed-admin-context.js';
|
|
4
5
|
|
|
5
6
|
describe('seedAdminCore integration', () => {
|
|
6
|
-
let
|
|
7
|
+
let pool: pg.Pool;
|
|
8
|
+
let client: pg.PoolClient;
|
|
7
9
|
|
|
8
10
|
beforeAll(async () => {
|
|
9
|
-
|
|
10
|
-
await
|
|
11
|
+
pool = new pg.Pool(testDbConfig);
|
|
12
|
+
client = await pool.connect();
|
|
11
13
|
});
|
|
12
14
|
|
|
13
15
|
afterAll(async () => {
|
|
14
|
-
|
|
16
|
+
client.release();
|
|
17
|
+
await pool.end();
|
|
15
18
|
});
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
await
|
|
19
|
-
|
|
20
|
-
const { adminEntityId } = await seedAdminCore(client);
|
|
21
|
-
|
|
22
|
-
// Verify admin entity exists
|
|
23
|
-
expect(adminEntityId).toBeTruthy();
|
|
24
|
-
expect(adminEntityId).toMatch(
|
|
25
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
// Verify admin financial entity
|
|
29
|
-
const adminEntity = await client.query(
|
|
30
|
-
`SELECT * FROM accounter_schema.financial_entities WHERE id = $1`,
|
|
31
|
-
[adminEntityId],
|
|
32
|
-
);
|
|
33
|
-
expect(adminEntity.rows).toHaveLength(1);
|
|
34
|
-
expect(adminEntity.rows[0].name).toBe('Admin Business');
|
|
35
|
-
expect(adminEntity.rows[0].type).toBe('business');
|
|
36
|
-
expect(adminEntity.rows[0].owner_id).toBe(adminEntityId); // self-owned
|
|
37
|
-
|
|
38
|
-
// Verify admin business record
|
|
39
|
-
const adminBusiness = await client.query(
|
|
40
|
-
`SELECT * FROM accounter_schema.businesses WHERE id = $1`,
|
|
41
|
-
[adminEntityId],
|
|
42
|
-
);
|
|
43
|
-
expect(adminBusiness.rows).toHaveLength(1);
|
|
44
|
-
|
|
45
|
-
// Verify user_context exists and has required fields
|
|
46
|
-
const userContext = await client.query(
|
|
47
|
-
`SELECT * FROM accounter_schema.user_context WHERE owner_id = $1`,
|
|
48
|
-
[adminEntityId],
|
|
49
|
-
);
|
|
50
|
-
expect(userContext.rows).toHaveLength(1);
|
|
51
|
-
|
|
52
|
-
const context = userContext.rows[0];
|
|
53
|
-
|
|
54
|
-
// Verify currencies
|
|
55
|
-
expect(context.default_local_currency).toBe('ILS');
|
|
56
|
-
expect(context.default_fiat_currency_for_crypto_conversions).toBe('USD');
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
await client.query('BEGIN');
|
|
22
|
+
});
|
|
57
23
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
[context.vat_business_id],
|
|
62
|
-
);
|
|
63
|
-
expect(vatBusiness.rows).toHaveLength(1);
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
await client.query('ROLLBACK');
|
|
26
|
+
});
|
|
64
27
|
|
|
65
|
-
|
|
66
|
-
`SELECT * FROM accounter_schema.businesses WHERE id = $1`,
|
|
67
|
-
[context.tax_business_id],
|
|
68
|
-
);
|
|
69
|
-
expect(taxBusiness.rows).toHaveLength(1);
|
|
28
|
+
it('should create admin business context with all required entities', async () => {
|
|
70
29
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
30
|
+
// Execute seed
|
|
31
|
+
const { adminEntityId } = await seedAdminCore(client);
|
|
32
|
+
|
|
33
|
+
// Verify admin entity exists
|
|
34
|
+
expect(adminEntityId).toBeTruthy();
|
|
35
|
+
expect(adminEntityId).toMatch(
|
|
36
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Verify admin financial entity
|
|
40
|
+
const adminEntity = await client.query(
|
|
41
|
+
`SELECT * FROM accounter_schema.financial_entities WHERE id = $1`,
|
|
42
|
+
[adminEntityId],
|
|
43
|
+
);
|
|
44
|
+
expect(adminEntity.rows).toHaveLength(1);
|
|
45
|
+
expect(adminEntity.rows[0].name).toBe('Admin Business');
|
|
46
|
+
expect(adminEntity.rows[0].type).toBe('business');
|
|
47
|
+
expect(adminEntity.rows[0].owner_id).toBe(adminEntityId); // self-owned
|
|
48
|
+
|
|
49
|
+
// Verify admin business record
|
|
50
|
+
const adminBusiness = await client.query(
|
|
51
|
+
`SELECT * FROM accounter_schema.businesses WHERE id = $1`,
|
|
52
|
+
[adminEntityId],
|
|
53
|
+
);
|
|
54
|
+
expect(adminBusiness.rows).toHaveLength(1);
|
|
55
|
+
|
|
56
|
+
// Verify user_context exists and has required fields
|
|
57
|
+
const userContext = await client.query(
|
|
58
|
+
`SELECT * FROM accounter_schema.user_context WHERE owner_id = $1`,
|
|
59
|
+
[adminEntityId],
|
|
60
|
+
);
|
|
61
|
+
expect(userContext.rows).toHaveLength(1);
|
|
62
|
+
|
|
63
|
+
const context = userContext.rows[0];
|
|
64
|
+
|
|
65
|
+
// Verify currencies
|
|
66
|
+
expect(context.default_local_currency).toBe('ILS');
|
|
67
|
+
expect(context.default_fiat_currency_for_crypto_conversions).toBe('USD');
|
|
68
|
+
|
|
69
|
+
// Verify required authority businesses exist
|
|
70
|
+
const vatBusiness = await client.query(
|
|
71
|
+
`SELECT * FROM accounter_schema.businesses WHERE id = $1`,
|
|
72
|
+
[context.vat_business_id],
|
|
73
|
+
);
|
|
74
|
+
expect(vatBusiness.rows).toHaveLength(1);
|
|
75
|
+
|
|
76
|
+
const taxBusiness = await client.query(
|
|
77
|
+
`SELECT * FROM accounter_schema.businesses WHERE id = $1`,
|
|
78
|
+
[context.tax_business_id],
|
|
79
|
+
);
|
|
80
|
+
expect(taxBusiness.rows).toHaveLength(1);
|
|
81
|
+
|
|
82
|
+
const socialSecurityBusiness = await client.query(
|
|
83
|
+
`SELECT * FROM accounter_schema.businesses WHERE id = $1`,
|
|
84
|
+
[context.social_security_business_id],
|
|
85
|
+
);
|
|
86
|
+
expect(socialSecurityBusiness.rows).toHaveLength(1);
|
|
87
|
+
|
|
88
|
+
// Verify required tax categories exist
|
|
89
|
+
const requiredTaxCategoryFields = [
|
|
90
|
+
'default_tax_category_id',
|
|
91
|
+
'input_vat_tax_category_id',
|
|
92
|
+
'output_vat_tax_category_id',
|
|
93
|
+
'tax_expenses_tax_category_id',
|
|
94
|
+
'exchange_rate_tax_category_id',
|
|
95
|
+
'income_exchange_rate_tax_category_id',
|
|
96
|
+
'exchange_rate_revaluation_tax_category_id',
|
|
97
|
+
'fee_tax_category_id',
|
|
98
|
+
'general_fee_tax_category_id',
|
|
99
|
+
'fine_tax_category_id',
|
|
100
|
+
'untaxable_gifts_tax_category_id',
|
|
101
|
+
'balance_cancellation_tax_category_id',
|
|
102
|
+
'development_foreign_tax_category_id',
|
|
103
|
+
'development_local_tax_category_id',
|
|
104
|
+
'expenses_to_pay_tax_category_id',
|
|
105
|
+
'expenses_in_advance_tax_category_id',
|
|
106
|
+
'income_to_collect_tax_category_id',
|
|
107
|
+
'income_in_advance_tax_category_id',
|
|
108
|
+
'salary_excess_expenses_tax_category_id',
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
for (const field of requiredTaxCategoryFields) {
|
|
112
|
+
const taxCategoryId = context[field];
|
|
113
|
+
expect(taxCategoryId).toBeTruthy();
|
|
114
|
+
|
|
115
|
+
const taxCategory = await client.query(
|
|
116
|
+
`SELECT * FROM accounter_schema.tax_categories WHERE id = $1`,
|
|
117
|
+
[taxCategoryId],
|
|
74
118
|
);
|
|
75
|
-
expect(
|
|
76
|
-
|
|
77
|
-
// Verify required tax categories exist
|
|
78
|
-
const requiredTaxCategoryFields = [
|
|
79
|
-
'default_tax_category_id',
|
|
80
|
-
'input_vat_tax_category_id',
|
|
81
|
-
'output_vat_tax_category_id',
|
|
82
|
-
'tax_expenses_tax_category_id',
|
|
83
|
-
'exchange_rate_tax_category_id',
|
|
84
|
-
'income_exchange_rate_tax_category_id',
|
|
85
|
-
'exchange_rate_revaluation_tax_category_id',
|
|
86
|
-
'fee_tax_category_id',
|
|
87
|
-
'general_fee_tax_category_id',
|
|
88
|
-
'fine_tax_category_id',
|
|
89
|
-
'untaxable_gifts_tax_category_id',
|
|
90
|
-
'balance_cancellation_tax_category_id',
|
|
91
|
-
'development_foreign_tax_category_id',
|
|
92
|
-
'development_local_tax_category_id',
|
|
93
|
-
'expenses_to_pay_tax_category_id',
|
|
94
|
-
'expenses_in_advance_tax_category_id',
|
|
95
|
-
'income_to_collect_tax_category_id',
|
|
96
|
-
'income_in_advance_tax_category_id',
|
|
97
|
-
'salary_excess_expenses_tax_category_id',
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
for (const field of requiredTaxCategoryFields) {
|
|
101
|
-
const taxCategoryId = context[field];
|
|
102
|
-
expect(taxCategoryId).toBeTruthy();
|
|
103
|
-
|
|
104
|
-
const taxCategory = await client.query(
|
|
105
|
-
`SELECT * FROM accounter_schema.tax_categories WHERE id = $1`,
|
|
106
|
-
[taxCategoryId],
|
|
107
|
-
);
|
|
108
|
-
expect(taxCategory.rows).toHaveLength(1);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
119
|
+
expect(taxCategory.rows).toHaveLength(1);
|
|
120
|
+
}
|
|
111
121
|
});
|
|
112
122
|
|
|
113
123
|
it('should be idempotent (safe to call multiple times)', async () => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
expect(userContextCount.rows[0].count).toBe('1');
|
|
141
|
-
});
|
|
124
|
+
// Call seed twice in same transaction
|
|
125
|
+
await seedAdminCore(client);
|
|
126
|
+
|
|
127
|
+
// Count entities before second call
|
|
128
|
+
const countBefore = await client.query(
|
|
129
|
+
`SELECT COUNT(*) as count FROM accounter_schema.financial_entities`,
|
|
130
|
+
);
|
|
131
|
+
const entitiesBeforeSecondCall = parseInt(countBefore.rows[0].count);
|
|
132
|
+
|
|
133
|
+
// Second call should reuse existing entities
|
|
134
|
+
await seedAdminCore(client);
|
|
135
|
+
|
|
136
|
+
// Count entities after second call - should be same
|
|
137
|
+
const countAfter = await client.query(
|
|
138
|
+
`SELECT COUNT(*) as count FROM accounter_schema.financial_entities`,
|
|
139
|
+
);
|
|
140
|
+
const entitiesAfterSecondCall = parseInt(countAfter.rows[0].count);
|
|
141
|
+
|
|
142
|
+
// Idempotent: no new entities created on second call
|
|
143
|
+
expect(entitiesAfterSecondCall).toBe(entitiesBeforeSecondCall);
|
|
144
|
+
|
|
145
|
+
// Verify only one user_context exists
|
|
146
|
+
const userContextCount = await client.query(
|
|
147
|
+
`SELECT COUNT(*) as count FROM accounter_schema.user_context`,
|
|
148
|
+
);
|
|
149
|
+
expect(userContextCount.rows[0].count).toBe('1');
|
|
142
150
|
});
|
|
143
151
|
|
|
144
152
|
it('should not leak data between tests (transactional isolation)', async () => {
|
|
145
|
-
|
|
146
|
-
const TEMP_NAME = 'seed-admin-context.integration.test.ts: temp rollback entity';
|
|
153
|
+
const TEMP_NAME = 'seed-admin-context.integration.test.ts: temp rollback entity';
|
|
147
154
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
// Insert a throwaway entity inside a transaction
|
|
156
|
+
const insertEntity = await client.query(
|
|
157
|
+
`INSERT INTO accounter_schema.financial_entities (name, type)
|
|
151
158
|
VALUES ($1, 'business')
|
|
152
159
|
RETURNING id`,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
160
|
+
[TEMP_NAME],
|
|
161
|
+
);
|
|
162
|
+
const tempId = insertEntity.rows[0].id;
|
|
163
|
+
await client.query(
|
|
164
|
+
`INSERT INTO accounter_schema.businesses (id) VALUES ($1)`,
|
|
165
|
+
[tempId],
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// Verify exists within the same transaction
|
|
169
|
+
const inTx = await client.query(
|
|
170
|
+
`SELECT COUNT(*) as count FROM accounter_schema.financial_entities WHERE name = $1`,
|
|
171
|
+
[TEMP_NAME],
|
|
172
|
+
);
|
|
173
|
+
expect(inTx.rows[0].count).toBe('1');
|
|
174
|
+
|
|
175
|
+
// Note: The afterEach hook will rollback this transaction,
|
|
176
|
+
// and the next test will start with a clean slate
|
|
168
177
|
});
|
|
169
178
|
|
|
170
179
|
it('should create all expected entity counts', async () => {
|
|
171
|
-
await
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
expect(parseInt(taxCategoryCount.rows[0].count)).toBeGreaterThanOrEqual(19);
|
|
185
|
-
});
|
|
180
|
+
await seedAdminCore(client);
|
|
181
|
+
|
|
182
|
+
// Count businesses (Admin + 3 authorities = 4)
|
|
183
|
+
const businessCount = await client.query(
|
|
184
|
+
`SELECT COUNT(*) as count FROM accounter_schema.businesses`,
|
|
185
|
+
);
|
|
186
|
+
expect(parseInt(businessCount.rows[0].count)).toBeGreaterThanOrEqual(4);
|
|
187
|
+
|
|
188
|
+
// Count tax categories (3 authority + 12 general + 4 cross-year = 19)
|
|
189
|
+
const taxCategoryCount = await client.query(
|
|
190
|
+
`SELECT COUNT(*) as count FROM accounter_schema.tax_categories`,
|
|
191
|
+
);
|
|
192
|
+
expect(parseInt(taxCategoryCount.rows[0].count)).toBeGreaterThanOrEqual(19);
|
|
186
193
|
});
|
|
187
194
|
|
|
188
195
|
it('should validate foreign key relationships', async () => {
|
|
189
|
-
await
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
const { adminEntityId } = await seedAdminCore(client);
|
|
197
|
+
|
|
198
|
+
// Get user_context
|
|
199
|
+
const userContext = await client.query(
|
|
200
|
+
`SELECT * FROM accounter_schema.user_context WHERE owner_id = $1`,
|
|
201
|
+
[adminEntityId],
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
const context = userContext.rows[0];
|
|
205
|
+
|
|
206
|
+
// Verify all business FKs point to valid financial_entities
|
|
207
|
+
const businessFields = [
|
|
208
|
+
'vat_business_id',
|
|
209
|
+
'tax_business_id',
|
|
210
|
+
'social_security_business_id',
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
for (const field of businessFields) {
|
|
214
|
+
const businessId = context[field];
|
|
215
|
+
const entity = await client.query(
|
|
216
|
+
`SELECT * FROM accounter_schema.financial_entities WHERE id = $1`,
|
|
217
|
+
[businessId],
|
|
196
218
|
);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
'output_vat_tax_category_id',
|
|
218
|
-
];
|
|
219
|
-
|
|
220
|
-
for (const field of taxCategoryFields) {
|
|
221
|
-
const taxCategoryId = context[field];
|
|
222
|
-
const entity = await client.query(
|
|
223
|
-
`SELECT * FROM accounter_schema.financial_entities WHERE id = $1`,
|
|
224
|
-
[taxCategoryId],
|
|
225
|
-
);
|
|
226
|
-
expect(entity.rows).toHaveLength(1);
|
|
227
|
-
expect(entity.rows[0].type).toBe('tax_category');
|
|
228
|
-
}
|
|
229
|
-
});
|
|
219
|
+
expect(entity.rows).toHaveLength(1);
|
|
220
|
+
expect(entity.rows[0].type).toBe('business');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Verify all tax_category FKs point to valid financial_entities
|
|
224
|
+
const taxCategoryFields = [
|
|
225
|
+
'default_tax_category_id',
|
|
226
|
+
'input_vat_tax_category_id',
|
|
227
|
+
'output_vat_tax_category_id',
|
|
228
|
+
];
|
|
229
|
+
|
|
230
|
+
for (const field of taxCategoryFields) {
|
|
231
|
+
const taxCategoryId = context[field];
|
|
232
|
+
const entity = await client.query(
|
|
233
|
+
`SELECT * FROM accounter_schema.financial_entities WHERE id = $1`,
|
|
234
|
+
[taxCategoryId],
|
|
235
|
+
);
|
|
236
|
+
expect(entity.rows).toHaveLength(1);
|
|
237
|
+
expect(entity.rows[0].type).toBe('tax_category');
|
|
238
|
+
}
|
|
230
239
|
});
|
|
231
240
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import DataLoader from 'dataloader';
|
|
2
2
|
import { Injectable, Scope } from 'graphql-modules';
|
|
3
3
|
import { sql } from '@pgtyped/runtime';
|
|
4
|
+
import { DBProvider } from '../../../modules/app-providers/db.provider.js';
|
|
4
5
|
import { getCacheInstance } from '../../../shared/helpers/index.js';
|
|
5
|
-
import { DBProvider } from '../../app-providers/db.provider.js';
|
|
6
6
|
import type {
|
|
7
7
|
BusinessTripProto,
|
|
8
8
|
IDeleteChargeBusinessTripQuery,
|