@accounter/client 0.0.7-alpha-20250821154938-954b3cb72dbd3ab35c2f363f90aa079483f72196 → 0.0.7-alpha-20250821210320-258a160dff8bd2402bbb8735fcd22f898c604626
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 +1 -8
- package/dist/assets/index-BERPxH5K.css +1 -0
- package/dist/assets/{index-B06NFENr.js → index-C3Jzs8px.js} +330 -370
- package/dist/assets/{index.es-DtQCKFFT.js → index.es-CP2tkYw-.js} +6 -6
- package/dist/index.html +2 -2
- package/package.json +1 -2
- package/src/app.tsx +0 -4
- package/src/components/layout/sidelinks.tsx +0 -15
- package/src/gql/gql.ts +0 -18
- package/src/gql/graphql.ts +0 -61
- package/dist/assets/index-DBmbnNAy.css +0 -1
- package/src/components/screens/operations/annual-audit/annual-audit-filters.tsx +0 -158
- package/src/components/screens/operations/annual-audit/index.tsx +0 -370
- package/src/components/screens/operations/annual-audit/step-01-validate-charges/index.tsx +0 -266
- package/src/components/screens/operations/annual-audit/step-02-ledger-changes/index.tsx +0 -121
- package/src/components/screens/operations/annual-audit/step-03-opening-balance/index.tsx +0 -171
- package/src/components/screens/operations/annual-audit/step-base.tsx +0 -149
- package/src/components/screens/operations/annual-audit/step-simple.tsx +0 -43
- package/src/components/ui/progress.tsx +0 -28
- package/src/hooks/use-get-admin-businesses.ts +0 -57
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useCallback,
|
|
3
|
-
useContext,
|
|
4
|
-
useEffect,
|
|
5
|
-
useMemo,
|
|
6
|
-
useRef,
|
|
7
|
-
useState,
|
|
8
|
-
type ReactElement,
|
|
9
|
-
} from 'react';
|
|
10
|
-
import { Calculator, Download, Eye, FileText, Lock, Settings, Upload, Users } from 'lucide-react';
|
|
11
|
-
import { useUrlQuery } from '../../../../hooks/use-url-query.js';
|
|
12
|
-
import { FiltersContext } from '../../../../providers/filters-context.js';
|
|
13
|
-
import { UserContext } from '../../../../providers/user-provider.js';
|
|
14
|
-
import { PageLayout } from '../../../layout/page-layout.js';
|
|
15
|
-
import { Button } from '../../../ui/button.js';
|
|
16
|
-
import { Card, CardContent, CardHeader, CardTitle } from '../../../ui/card.js';
|
|
17
|
-
import { Progress } from '../../../ui/progress.js';
|
|
18
|
-
import {
|
|
19
|
-
ANNUAL_AUDIT_FLOW_FILTERS_QUERY_PARAM,
|
|
20
|
-
AnnualAuditFlowFilters,
|
|
21
|
-
encodeAnnualAuditFlowFilters,
|
|
22
|
-
type AnnualAuditFlowFilter,
|
|
23
|
-
} from './annual-audit-filters.js';
|
|
24
|
-
// Import step components
|
|
25
|
-
import { Step01ValidateCharges } from './step-01-validate-charges/index.js';
|
|
26
|
-
import { Step02LedgerChanges } from './step-02-ledger-changes/index.js';
|
|
27
|
-
import Step03OpeningBalance from './step-03-opening-balance/index.js';
|
|
28
|
-
import type { StepStatus } from './step-base.js';
|
|
29
|
-
import SimpleStep from './step-simple.js';
|
|
30
|
-
|
|
31
|
-
export function getAnnualAuditFlowHref(filter?: AnnualAuditFlowFilter | null): string {
|
|
32
|
-
const params = new URLSearchParams();
|
|
33
|
-
|
|
34
|
-
const annualAuditFlowFilters = encodeAnnualAuditFlowFilters(filter);
|
|
35
|
-
if (annualAuditFlowFilters) {
|
|
36
|
-
// Add it as a single encoded parameter
|
|
37
|
-
params.append(ANNUAL_AUDIT_FLOW_FILTERS_QUERY_PARAM, annualAuditFlowFilters);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const queryParams = params.size > 0 ? `?${params}` : '';
|
|
41
|
-
return `/workflows/annual-audit${queryParams}`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const AnnualAuditFlow = (): ReactElement => {
|
|
45
|
-
const { setFiltersContext } = useContext(FiltersContext);
|
|
46
|
-
const { userContext } = useContext(UserContext);
|
|
47
|
-
const { get } = useUrlQuery();
|
|
48
|
-
const initialFilters = useMemo(() => {
|
|
49
|
-
const defaultFilters: AnnualAuditFlowFilter = {
|
|
50
|
-
year: new Date().getFullYear() - 1,
|
|
51
|
-
adminBusinessId: userContext?.context.adminBusinessId,
|
|
52
|
-
};
|
|
53
|
-
const uriFilters = get(ANNUAL_AUDIT_FLOW_FILTERS_QUERY_PARAM);
|
|
54
|
-
if (uriFilters) {
|
|
55
|
-
try {
|
|
56
|
-
return JSON.parse(decodeURIComponent(uriFilters)) as AnnualAuditFlowFilter;
|
|
57
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
58
|
-
} catch (error) {
|
|
59
|
-
console.error('Failed to parse filters from URI:', error);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return defaultFilters;
|
|
63
|
-
}, [userContext?.context.adminBusinessId]);
|
|
64
|
-
const [filter, setFilter] = useState<AnnualAuditFlowFilter>(initialFilters);
|
|
65
|
-
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
setFiltersContext(
|
|
68
|
-
<div className="flex flex-row gap-x-5">
|
|
69
|
-
<AnnualAuditFlowFilters filter={filter} setFilter={setFilter} />
|
|
70
|
-
</div>,
|
|
71
|
-
);
|
|
72
|
-
}, [filter, setFiltersContext, setFilter]);
|
|
73
|
-
|
|
74
|
-
const totalSteps = 21;
|
|
75
|
-
const YEAR = 2024; // TODO: Example year, should be dynamic
|
|
76
|
-
|
|
77
|
-
// Track step statuses to avoid double counting
|
|
78
|
-
const stepStatusesRef = useRef<Map<string, StepStatus>>(new Map());
|
|
79
|
-
const [completedSteps, setCompletedSteps] = useState(0);
|
|
80
|
-
|
|
81
|
-
const handleStatusChange = useCallback((stepId: string, status: StepStatus) => {
|
|
82
|
-
const previousStatus = stepStatusesRef.current.get(stepId);
|
|
83
|
-
|
|
84
|
-
// Only update if status actually changed
|
|
85
|
-
if (previousStatus !== status) {
|
|
86
|
-
stepStatusesRef.current.set(stepId, status);
|
|
87
|
-
|
|
88
|
-
// Recalculate completed steps count
|
|
89
|
-
const completedCount = Array.from(stepStatusesRef.current.values()).filter(
|
|
90
|
-
s => s === 'completed',
|
|
91
|
-
).length;
|
|
92
|
-
|
|
93
|
-
setCompletedSteps(completedCount);
|
|
94
|
-
}
|
|
95
|
-
}, []);
|
|
96
|
-
|
|
97
|
-
const progressPercentage = (completedSteps / totalSteps) * 100;
|
|
98
|
-
|
|
99
|
-
return (
|
|
100
|
-
<PageLayout
|
|
101
|
-
title="Annual Audit Flow"
|
|
102
|
-
description="Complete audit process for annual financial reporting and compliance"
|
|
103
|
-
>
|
|
104
|
-
<div className="container mx-auto p-6 max-w-6xl">
|
|
105
|
-
<div className="mb-8">
|
|
106
|
-
<Card className="mb-6">
|
|
107
|
-
<CardHeader>
|
|
108
|
-
<CardTitle className="text-lg">Progress Overview</CardTitle>
|
|
109
|
-
</CardHeader>
|
|
110
|
-
<CardContent>
|
|
111
|
-
<div className="space-y-2">
|
|
112
|
-
<div className="flex justify-between text-sm">
|
|
113
|
-
<span>Completed Steps</span>
|
|
114
|
-
<span>
|
|
115
|
-
{completedSteps} of {totalSteps}
|
|
116
|
-
</span>
|
|
117
|
-
</div>
|
|
118
|
-
<Progress value={progressPercentage} className="h-2" />
|
|
119
|
-
<div className="text-xs text-muted-foreground">
|
|
120
|
-
{progressPercentage.toFixed(1)}% Complete
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
</CardContent>
|
|
124
|
-
</Card>
|
|
125
|
-
</div>
|
|
126
|
-
|
|
127
|
-
<div className="space-y-4">
|
|
128
|
-
{/* Step 1 - Custom component with server data */}
|
|
129
|
-
<Step01ValidateCharges
|
|
130
|
-
id="1"
|
|
131
|
-
year={YEAR}
|
|
132
|
-
adminBusinessId={userContext?.context.adminBusinessId}
|
|
133
|
-
title="Validate All Charges"
|
|
134
|
-
description="Ensure all charges of the year were reviewed, handle pending charges"
|
|
135
|
-
onStatusChange={handleStatusChange}
|
|
136
|
-
/>
|
|
137
|
-
|
|
138
|
-
{/* Step 2 - Custom component with server data */}
|
|
139
|
-
<Step02LedgerChanges
|
|
140
|
-
id="2"
|
|
141
|
-
year={YEAR}
|
|
142
|
-
adminBusinessId={userContext?.context.adminBusinessId}
|
|
143
|
-
title="Check Pending Ledger Changes"
|
|
144
|
-
description="Ensure no pending ledger changes exist"
|
|
145
|
-
onStatusChange={handleStatusChange}
|
|
146
|
-
/>
|
|
147
|
-
|
|
148
|
-
{/* Step 3 - Custom component with substeps */}
|
|
149
|
-
<Step03OpeningBalance
|
|
150
|
-
id="3"
|
|
151
|
-
year={YEAR}
|
|
152
|
-
adminBusinessId={userContext?.context.adminBusinessId}
|
|
153
|
-
title="Verify Opening Balance"
|
|
154
|
-
description="Handle opening balance verification based on user type"
|
|
155
|
-
onStatusChange={handleStatusChange}
|
|
156
|
-
/>
|
|
157
|
-
|
|
158
|
-
{/* Step 4 - Simple step with static data */}
|
|
159
|
-
<SimpleStep
|
|
160
|
-
id="4"
|
|
161
|
-
title="Generate Financial Charges"
|
|
162
|
-
description="Create various financial charges and reserves"
|
|
163
|
-
icon={<Calculator className="h-4 w-4" />}
|
|
164
|
-
onStatusChange={handleStatusChange}
|
|
165
|
-
actions={[
|
|
166
|
-
{ label: 'Calculate Vacation Reserves', href: '/reserves/vacation' },
|
|
167
|
-
{ label: 'Calculate Recovery Reserves', href: '/reserves/recovery' },
|
|
168
|
-
{ label: 'Process Bank Deposits', href: '/deposits/bank' },
|
|
169
|
-
{ label: 'Perform Revaluation', href: '/revaluation' },
|
|
170
|
-
{ label: 'Calculate Tax Expenses', href: '/tax/expenses' },
|
|
171
|
-
{ label: 'Calculate Depreciation', href: '/depreciation/calculate' },
|
|
172
|
-
]}
|
|
173
|
-
/>
|
|
174
|
-
|
|
175
|
-
{/* Step 5 - Simple step */}
|
|
176
|
-
<SimpleStep
|
|
177
|
-
id="5"
|
|
178
|
-
title="Audit Main Process"
|
|
179
|
-
description="Task management system for comprehensive audit checks"
|
|
180
|
-
icon={<FileText className="h-4 w-4" />}
|
|
181
|
-
onStatusChange={handleStatusChange}
|
|
182
|
-
actions={[
|
|
183
|
-
{ label: 'Manage Conto Tree', href: '/conto/tree' },
|
|
184
|
-
{ label: 'Open Checklist', href: '/validations/checklist' },
|
|
185
|
-
{ label: 'Compare VAT', href: '/vat/comparison' },
|
|
186
|
-
{ label: 'Generate Draft', href: '/depreciation/draft' },
|
|
187
|
-
{ label: 'Manage Audit Checks', href: '/audit/checks' },
|
|
188
|
-
{ label: 'Review Tax Report', href: '/tax/review' },
|
|
189
|
-
{ label: 'Cash Flow Analysis', href: '/cashflow/analysis' },
|
|
190
|
-
]}
|
|
191
|
-
/>
|
|
192
|
-
|
|
193
|
-
{/* Steps 6-21 - Simple steps with basic configuration */}
|
|
194
|
-
<SimpleStep
|
|
195
|
-
id="6"
|
|
196
|
-
title="Add Shareholders Data (1214)"
|
|
197
|
-
description="For 1214 report preparation"
|
|
198
|
-
icon={<Users className="h-4 w-4" />}
|
|
199
|
-
onStatusChange={handleStatusChange}
|
|
200
|
-
actions={[
|
|
201
|
-
{ label: 'Manage Shareholders', href: '/shareholders/manage' },
|
|
202
|
-
{ label: 'Import Data', href: '/shareholders/import' },
|
|
203
|
-
]}
|
|
204
|
-
/>
|
|
205
|
-
|
|
206
|
-
<SimpleStep
|
|
207
|
-
id="7"
|
|
208
|
-
title="Revalidate Pending Items"
|
|
209
|
-
description="Ensure no charges approval or ledger regeneration pending"
|
|
210
|
-
icon={<Eye className="h-4 w-4" />}
|
|
211
|
-
onStatusChange={handleStatusChange}
|
|
212
|
-
actions={[
|
|
213
|
-
{ label: 'Check Pending Approvals', href: '/approvals/pending' },
|
|
214
|
-
{ label: 'Ledger Status', href: '/ledger/status' },
|
|
215
|
-
]}
|
|
216
|
-
/>
|
|
217
|
-
|
|
218
|
-
<SimpleStep
|
|
219
|
-
id="8"
|
|
220
|
-
title="Lock Ledger"
|
|
221
|
-
description="Lock ledger by records and by date"
|
|
222
|
-
icon={<Lock className="h-4 w-4" />}
|
|
223
|
-
onStatusChange={handleStatusChange}
|
|
224
|
-
actions={[
|
|
225
|
-
{ label: 'Lock by Records', href: '/ledger/lock-records' },
|
|
226
|
-
{ label: 'Lock by Date', href: '/ledger/lock-date' },
|
|
227
|
-
]}
|
|
228
|
-
/>
|
|
229
|
-
|
|
230
|
-
<SimpleStep
|
|
231
|
-
id="9"
|
|
232
|
-
title="Save Final Dynamic Report Template"
|
|
233
|
-
icon={<FileText className="h-4 w-4" />}
|
|
234
|
-
onStatusChange={handleStatusChange}
|
|
235
|
-
actions={[{ label: 'Save Template', href: '/reports/save-template' }]}
|
|
236
|
-
/>
|
|
237
|
-
|
|
238
|
-
<SimpleStep
|
|
239
|
-
id="10"
|
|
240
|
-
title="Export Year-end Trial Balance"
|
|
241
|
-
description="For future validations"
|
|
242
|
-
icon={<Download className="h-4 w-4" />}
|
|
243
|
-
onStatusChange={handleStatusChange}
|
|
244
|
-
actions={[{ label: 'Export Trial Balance', href: '/export/trial-balance' }]}
|
|
245
|
-
/>
|
|
246
|
-
|
|
247
|
-
<SimpleStep
|
|
248
|
-
id="11"
|
|
249
|
-
title="Generate Final Depreciation Report"
|
|
250
|
-
icon={<FileText className="h-4 w-4" />}
|
|
251
|
-
onStatusChange={handleStatusChange}
|
|
252
|
-
actions={[{ label: 'Generate Report', href: '/depreciation/final' }]}
|
|
253
|
-
/>
|
|
254
|
-
|
|
255
|
-
<SimpleStep
|
|
256
|
-
id="12"
|
|
257
|
-
title="Generate Financial Reports"
|
|
258
|
-
description="With comparison numbers from last year"
|
|
259
|
-
icon={<FileText className="h-4 w-4" />}
|
|
260
|
-
onStatusChange={handleStatusChange}
|
|
261
|
-
actions={[{ label: 'Generate Reports', href: '/reports/financial' }]}
|
|
262
|
-
/>
|
|
263
|
-
|
|
264
|
-
<SimpleStep
|
|
265
|
-
id="13"
|
|
266
|
-
title="Generate Tax Report"
|
|
267
|
-
icon={<FileText className="h-4 w-4" />}
|
|
268
|
-
onStatusChange={handleStatusChange}
|
|
269
|
-
actions={[{ label: 'Generate Tax Report', href: '/tax/generate' }]}
|
|
270
|
-
/>
|
|
271
|
-
|
|
272
|
-
<SimpleStep
|
|
273
|
-
id="14"
|
|
274
|
-
title="Generate Tax Compliance Reports"
|
|
275
|
-
description="For Yossi's review"
|
|
276
|
-
icon={<FileText className="h-4 w-4" />}
|
|
277
|
-
onStatusChange={handleStatusChange}
|
|
278
|
-
actions={[{ label: 'Generate Report', href: '/compliance/clients-country' }]}
|
|
279
|
-
/>
|
|
280
|
-
|
|
281
|
-
<SimpleStep
|
|
282
|
-
id="15"
|
|
283
|
-
title="Generate Tax Compliance Report"
|
|
284
|
-
icon={<FileText className="h-4 w-4" />}
|
|
285
|
-
onStatusChange={handleStatusChange}
|
|
286
|
-
actions={[
|
|
287
|
-
{ label: 'Generate 973', href: '/reports/973' },
|
|
288
|
-
{ label: 'Generate 901א', href: '/reports/901a' },
|
|
289
|
-
]}
|
|
290
|
-
/>
|
|
291
|
-
|
|
292
|
-
<SimpleStep
|
|
293
|
-
id="16"
|
|
294
|
-
title="Generate 6111 Report"
|
|
295
|
-
icon={<FileText className="h-4 w-4" />}
|
|
296
|
-
onStatusChange={handleStatusChange}
|
|
297
|
-
actions={[{ label: 'Generate 6111', href: '/reports/6111' }]}
|
|
298
|
-
/>
|
|
299
|
-
|
|
300
|
-
<SimpleStep
|
|
301
|
-
id="17"
|
|
302
|
-
title="Generate Dividend Report 1214ב"
|
|
303
|
-
icon={<FileText className="h-4 w-4" />}
|
|
304
|
-
onStatusChange={handleStatusChange}
|
|
305
|
-
actions={[{ label: 'Generate Dividend Report', href: '/reports/dividend-1214b' }]}
|
|
306
|
-
/>
|
|
307
|
-
|
|
308
|
-
<SimpleStep
|
|
309
|
-
id="18"
|
|
310
|
-
title="Generate 1214 Report"
|
|
311
|
-
icon={<FileText className="h-4 w-4" />}
|
|
312
|
-
onStatusChange={handleStatusChange}
|
|
313
|
-
actions={[{ label: 'Generate 1214', href: '/reports/1214' }]}
|
|
314
|
-
/>
|
|
315
|
-
|
|
316
|
-
<SimpleStep
|
|
317
|
-
id="19"
|
|
318
|
-
title="Compare Tax Expenses"
|
|
319
|
-
description="Compare 1214 tax expenses with ledger tax expenses"
|
|
320
|
-
icon={<Calculator className="h-4 w-4" />}
|
|
321
|
-
onStatusChange={handleStatusChange}
|
|
322
|
-
actions={[{ label: 'Compare Expenses', href: '/tax/compare-expenses' }]}
|
|
323
|
-
/>
|
|
324
|
-
|
|
325
|
-
<SimpleStep
|
|
326
|
-
id="20"
|
|
327
|
-
title="Signing Process"
|
|
328
|
-
description="Handle signing process and accompanying documents"
|
|
329
|
-
icon={<FileText className="h-4 w-4" />}
|
|
330
|
-
onStatusChange={handleStatusChange}
|
|
331
|
-
actions={[
|
|
332
|
-
{ label: 'Prepare Documents', href: '/signing/prepare' },
|
|
333
|
-
{ label: 'Digital Signing', href: '/signing/digital' },
|
|
334
|
-
]}
|
|
335
|
-
/>
|
|
336
|
-
|
|
337
|
-
<SimpleStep
|
|
338
|
-
id="21"
|
|
339
|
-
title="File Annual Report"
|
|
340
|
-
description="Submit annual report to companies government office"
|
|
341
|
-
icon={<Upload className="h-4 w-4" />}
|
|
342
|
-
onStatusChange={handleStatusChange}
|
|
343
|
-
actions={[
|
|
344
|
-
{ label: 'Prepare Filing', href: '/filing/prepare' },
|
|
345
|
-
{ label: 'Submit Report', href: '/filing/submit' },
|
|
346
|
-
]}
|
|
347
|
-
/>
|
|
348
|
-
</div>
|
|
349
|
-
|
|
350
|
-
<div className="mt-8 p-4 bg-muted rounded-lg">
|
|
351
|
-
<h3 className="font-semibold mb-2">Quick Actions</h3>
|
|
352
|
-
<div className="flex flex-wrap gap-2">
|
|
353
|
-
<Button variant="outline" size="sm">
|
|
354
|
-
<Download className="h-4 w-4 mr-2" />
|
|
355
|
-
Export Progress Report
|
|
356
|
-
</Button>
|
|
357
|
-
<Button variant="outline" size="sm">
|
|
358
|
-
<Settings className="h-4 w-4 mr-2" />
|
|
359
|
-
Configure Workflow
|
|
360
|
-
</Button>
|
|
361
|
-
<Button variant="outline" size="sm">
|
|
362
|
-
<Eye className="h-4 w-4 mr-2" />
|
|
363
|
-
View All Reports
|
|
364
|
-
</Button>
|
|
365
|
-
</div>
|
|
366
|
-
</div>
|
|
367
|
-
</div>
|
|
368
|
-
</PageLayout>
|
|
369
|
-
);
|
|
370
|
-
};
|
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
import { useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import { AlertCircle, ChevronDown, ChevronRight, Eye } from 'lucide-react';
|
|
3
|
-
import { useQuery } from 'urql';
|
|
4
|
-
import {
|
|
5
|
-
AccountantApprovalStatusDocument,
|
|
6
|
-
AccountantStatus,
|
|
7
|
-
ChargeSortByField,
|
|
8
|
-
} from '../../../../../gql/graphql.js';
|
|
9
|
-
import type { TimelessDateString } from '../../../../../helpers/dates.js';
|
|
10
|
-
import { Badge } from '../../../../ui/badge.jsx';
|
|
11
|
-
import { Button } from '../../../../ui/button.jsx';
|
|
12
|
-
import { CardContent } from '../../../../ui/card.jsx';
|
|
13
|
-
import { Collapsible, CollapsibleContent } from '../../../../ui/collapsible.js';
|
|
14
|
-
import { getAllChargesHref } from '../../../charges/all-charges.jsx';
|
|
15
|
-
import {
|
|
16
|
-
BaseStepCard,
|
|
17
|
-
type BaseStepProps,
|
|
18
|
-
type StepAction,
|
|
19
|
-
type StepStatus,
|
|
20
|
-
} from '../step-base.jsx';
|
|
21
|
-
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- used by codegen
|
|
23
|
-
/* GraphQL */ `
|
|
24
|
-
query AccountantApprovalStatus($fromDate: TimelessDate!, $toDate: TimelessDate!) {
|
|
25
|
-
accountantApprovalStatus(from: $fromDate, to: $toDate) {
|
|
26
|
-
totalCharges
|
|
27
|
-
approvedCount
|
|
28
|
-
pendingCount
|
|
29
|
-
unapprovedCount
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
`;
|
|
33
|
-
|
|
34
|
-
interface ChargeValidationData {
|
|
35
|
-
approvedPercentage: number;
|
|
36
|
-
pendingPercentage: number;
|
|
37
|
-
unapprovedPercentage: number;
|
|
38
|
-
totalCharges: number;
|
|
39
|
-
approvedCount: number;
|
|
40
|
-
pendingCount: number;
|
|
41
|
-
unapprovedCount: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface Step01Props extends BaseStepProps {
|
|
45
|
-
year: number;
|
|
46
|
-
adminBusinessId?: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function Step01ValidateCharges(props: Step01Props) {
|
|
50
|
-
const [status, setStatus] = useState<StepStatus>('loading');
|
|
51
|
-
const [chargeData, setChargeData] = useState<ChargeValidationData>({
|
|
52
|
-
approvedPercentage: 0,
|
|
53
|
-
pendingPercentage: 0,
|
|
54
|
-
unapprovedPercentage: 100,
|
|
55
|
-
totalCharges: 1,
|
|
56
|
-
approvedCount: 0,
|
|
57
|
-
pendingCount: 0,
|
|
58
|
-
unapprovedCount: 1,
|
|
59
|
-
});
|
|
60
|
-
const [isDetailsExpanded, setIsDetailsExpanded] = useState(false);
|
|
61
|
-
const [hasReportedCompletion, setHasReportedCompletion] = useState(false);
|
|
62
|
-
|
|
63
|
-
// Report status changes to parent
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
if (props.onStatusChange) {
|
|
66
|
-
props.onStatusChange(props.id, status);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Track if we've reported completion to avoid double counting
|
|
70
|
-
if (status === 'completed' && !hasReportedCompletion) {
|
|
71
|
-
setHasReportedCompletion(true);
|
|
72
|
-
} else if (status !== 'completed' && hasReportedCompletion) {
|
|
73
|
-
setHasReportedCompletion(false);
|
|
74
|
-
}
|
|
75
|
-
}, [status, props.onStatusChange, props.id, hasReportedCompletion]);
|
|
76
|
-
|
|
77
|
-
const [{ data, fetching }, fetchStatus] = useQuery({
|
|
78
|
-
query: AccountantApprovalStatusDocument,
|
|
79
|
-
variables: {
|
|
80
|
-
fromDate: `${props.year}-01-01` as TimelessDateString,
|
|
81
|
-
toDate: `${props.year}-12-31` as TimelessDateString,
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
if (!props.adminBusinessId) {
|
|
87
|
-
setStatus('blocked');
|
|
88
|
-
} else if (fetching) {
|
|
89
|
-
setStatus('loading');
|
|
90
|
-
}
|
|
91
|
-
}, [props.adminBusinessId, fetching]);
|
|
92
|
-
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
if (data?.accountantApprovalStatus) {
|
|
95
|
-
const { totalCharges, approvedCount, pendingCount, unapprovedCount } =
|
|
96
|
-
data.accountantApprovalStatus;
|
|
97
|
-
const accountantApprovalStatus: ChargeValidationData = {
|
|
98
|
-
approvedPercentage: (approvedCount / totalCharges) * 100 || 0,
|
|
99
|
-
pendingPercentage: (pendingCount / totalCharges) * 100 || 0,
|
|
100
|
-
unapprovedPercentage: (unapprovedCount / totalCharges) * 100 || 0,
|
|
101
|
-
totalCharges,
|
|
102
|
-
approvedCount,
|
|
103
|
-
pendingCount,
|
|
104
|
-
unapprovedCount,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
setChargeData(accountantApprovalStatus);
|
|
108
|
-
|
|
109
|
-
// Determine status based on data
|
|
110
|
-
if (
|
|
111
|
-
accountantApprovalStatus.pendingPercentage === 0 &&
|
|
112
|
-
accountantApprovalStatus.unapprovedPercentage === 0
|
|
113
|
-
) {
|
|
114
|
-
setStatus('completed');
|
|
115
|
-
} else if (
|
|
116
|
-
accountantApprovalStatus.pendingPercentage + accountantApprovalStatus.unapprovedPercentage <
|
|
117
|
-
30
|
|
118
|
-
) {
|
|
119
|
-
setStatus('in-progress');
|
|
120
|
-
} else {
|
|
121
|
-
setStatus('pending');
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}, [data]);
|
|
125
|
-
|
|
126
|
-
const href = useMemo(() => {
|
|
127
|
-
return getAllChargesHref({
|
|
128
|
-
byOwners: props.adminBusinessId ? [props.adminBusinessId] : undefined,
|
|
129
|
-
fromAnyDate: `${props.year}-01-01` as TimelessDateString,
|
|
130
|
-
toAnyDate: `${props.year}-12-31` as TimelessDateString,
|
|
131
|
-
accountantStatus: [AccountantStatus.Pending, AccountantStatus.Unapproved],
|
|
132
|
-
sortBy: {
|
|
133
|
-
field: ChargeSortByField.Date,
|
|
134
|
-
asc: false,
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
}, [props.adminBusinessId, props.year]);
|
|
138
|
-
|
|
139
|
-
const actions: StepAction[] = [{ label: 'Review Charges', href }];
|
|
140
|
-
|
|
141
|
-
const refreshData = async () => {
|
|
142
|
-
await fetchStatus();
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
return (
|
|
146
|
-
<BaseStepCard {...props} status={status} icon={<Eye className="h-4 w-4" />} actions={actions}>
|
|
147
|
-
<Collapsible open={isDetailsExpanded}>
|
|
148
|
-
<CardContent className="pt-0 border-t">
|
|
149
|
-
<Button
|
|
150
|
-
variant="ghost"
|
|
151
|
-
size="sm"
|
|
152
|
-
onClick={() => setIsDetailsExpanded(!isDetailsExpanded)}
|
|
153
|
-
className="w-full justify-between p-2 h-auto"
|
|
154
|
-
>
|
|
155
|
-
<div className="flex items-center gap-2">
|
|
156
|
-
<span className="text-sm font-medium">Charge Validation Details</span>
|
|
157
|
-
<Badge variant="outline" className="text-xs">
|
|
158
|
-
{chargeData.pendingCount + chargeData.unapprovedCount} need attention
|
|
159
|
-
</Badge>
|
|
160
|
-
</div>
|
|
161
|
-
{isDetailsExpanded ? (
|
|
162
|
-
<ChevronDown className="h-4 w-4" />
|
|
163
|
-
) : (
|
|
164
|
-
<ChevronRight className="h-4 w-4" />
|
|
165
|
-
)}
|
|
166
|
-
</Button>
|
|
167
|
-
</CardContent>
|
|
168
|
-
<CollapsibleContent>
|
|
169
|
-
<CardContent className="pt-0">
|
|
170
|
-
<div className="space-y-4">
|
|
171
|
-
<div className="space-y-3">
|
|
172
|
-
<div className="flex justify-between items-center text-sm">
|
|
173
|
-
<span className="font-medium">Charge Review Progress</span>
|
|
174
|
-
<div className="flex items-center gap-2">
|
|
175
|
-
<span className="text-muted-foreground">
|
|
176
|
-
{chargeData.totalCharges.toLocaleString()} total charges
|
|
177
|
-
</span>
|
|
178
|
-
<Button
|
|
179
|
-
variant="ghost"
|
|
180
|
-
size="sm"
|
|
181
|
-
onClick={refreshData}
|
|
182
|
-
disabled={status === 'loading'}
|
|
183
|
-
>
|
|
184
|
-
Refresh
|
|
185
|
-
</Button>
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
|
|
189
|
-
{/* Combined Progress Bar */}
|
|
190
|
-
<div className="relative h-6 bg-gray-200 rounded-full overflow-hidden">
|
|
191
|
-
<div
|
|
192
|
-
className="absolute left-0 top-0 h-full bg-green-500 transition-all duration-300"
|
|
193
|
-
style={{ width: `${chargeData.approvedPercentage}%` }}
|
|
194
|
-
/>
|
|
195
|
-
<div
|
|
196
|
-
className="absolute top-0 h-full bg-orange-500 transition-all duration-300"
|
|
197
|
-
style={{
|
|
198
|
-
left: `${chargeData.approvedPercentage}%`,
|
|
199
|
-
width: `${chargeData.pendingPercentage}%`,
|
|
200
|
-
}}
|
|
201
|
-
/>
|
|
202
|
-
<div
|
|
203
|
-
className="absolute top-0 h-full bg-red-500 transition-all duration-300"
|
|
204
|
-
style={{
|
|
205
|
-
left: `${chargeData.approvedPercentage + chargeData.pendingPercentage}%`,
|
|
206
|
-
width: `${chargeData.unapprovedPercentage}%`,
|
|
207
|
-
}}
|
|
208
|
-
/>
|
|
209
|
-
</div>
|
|
210
|
-
|
|
211
|
-
{/* Legend */}
|
|
212
|
-
<div className="grid grid-cols-3 gap-4 text-sm">
|
|
213
|
-
<div className="flex items-center gap-2">
|
|
214
|
-
<div className="w-3 h-3 bg-green-500 rounded-full" />
|
|
215
|
-
<div>
|
|
216
|
-
<div className="font-medium text-green-700">
|
|
217
|
-
Approved ({chargeData.approvedPercentage}%)
|
|
218
|
-
</div>
|
|
219
|
-
<div className="text-xs text-muted-foreground">
|
|
220
|
-
{chargeData.approvedCount.toLocaleString()} charges
|
|
221
|
-
</div>
|
|
222
|
-
</div>
|
|
223
|
-
</div>
|
|
224
|
-
|
|
225
|
-
<div className="flex items-center gap-2">
|
|
226
|
-
<div className="w-3 h-3 bg-orange-500 rounded-full" />
|
|
227
|
-
<div>
|
|
228
|
-
<div className="font-medium text-orange-700">
|
|
229
|
-
Pending ({chargeData.pendingPercentage}%)
|
|
230
|
-
</div>
|
|
231
|
-
<div className="text-xs text-muted-foreground">
|
|
232
|
-
{chargeData.pendingCount.toLocaleString()} charges
|
|
233
|
-
</div>
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
|
|
237
|
-
<div className="flex items-center gap-2">
|
|
238
|
-
<div className="w-3 h-3 bg-red-500 rounded-full" />
|
|
239
|
-
<div>
|
|
240
|
-
<div className="font-medium text-red-700">
|
|
241
|
-
Unapproved ({chargeData.unapprovedPercentage}%)
|
|
242
|
-
</div>
|
|
243
|
-
<div className="text-xs text-muted-foreground">
|
|
244
|
-
{chargeData.unapprovedCount.toLocaleString()} charges
|
|
245
|
-
</div>
|
|
246
|
-
</div>
|
|
247
|
-
</div>
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
|
|
251
|
-
{(chargeData.pendingPercentage > 0 || chargeData.unapprovedPercentage > 0) && (
|
|
252
|
-
<div className="flex items-center gap-2 p-3 bg-orange-50 rounded-lg border border-orange-200">
|
|
253
|
-
<AlertCircle className="h-4 w-4 text-orange-600" />
|
|
254
|
-
<span className="text-sm text-orange-800">
|
|
255
|
-
{chargeData.pendingCount + chargeData.unapprovedCount} charges need review
|
|
256
|
-
before proceeding
|
|
257
|
-
</span>
|
|
258
|
-
</div>
|
|
259
|
-
)}
|
|
260
|
-
</div>
|
|
261
|
-
</CardContent>
|
|
262
|
-
</CollapsibleContent>
|
|
263
|
-
</Collapsible>
|
|
264
|
-
</BaseStepCard>
|
|
265
|
-
);
|
|
266
|
-
}
|