Expand sales, treasury, and parties modules with Jalali calendar and FunZone integrations

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Shayan Azadi
2026-07-03 03:15:52 +03:30
parent d7252f1d21
commit 4508be582a
55 changed files with 5083 additions and 799 deletions

View File

@@ -0,0 +1,51 @@
import { useEffect, useRef } from 'react'
import { acct, asList, apiGet } from '../api/client'
import { ENDPOINTS, ACCOUNTING_ENDPOINTS } from '../api/config'
import type { ApiCustomer, ApiOwner } from '../api/types'
import type { Party } from '../types'
import { useStore } from '../store/AppStore'
import { createId } from '../utils/id'
import { findExistingParty, mergeFunZoneParties, partyNeedsSync } from './funzonePartySync'
/** Syncs FunZone owners/customers into accounting parties on app load. */
export function GlobalPartySync() {
const { ready, upsertPartyAsync, reload } = useStore()
const synced = useRef(false)
useEffect(() => {
if (!ready || synced.current) return
synced.current = true
const run = async () => {
try {
const [owners, customersRaw, currentParties] = await Promise.all([
apiGet<unknown>(ENDPOINTS.OWNERS).then(asList<ApiOwner>),
apiGet<unknown>(ENDPOINTS.CUSTOMERS),
acct.get(ACCOUNTING_ENDPOINTS.PARTIES).then(asList<Party>),
])
const customers: ApiCustomer[] = Array.isArray(customersRaw)
? (customersRaw as ApiCustomer[])
: ((customersRaw as { results?: ApiCustomer[] }).results ?? [])
const batches = [
...mergeFunZoneParties(owners, currentParties, 'supplier'),
...mergeFunZoneParties(customers, currentParties, 'customer'),
]
for (const incoming of batches) {
const existing = findExistingParty(currentParties, incoming.externalId!, incoming.externalSource)
if (existing && !partyNeedsSync(existing, incoming)) continue
await upsertPartyAsync({ ...incoming, id: existing?.id ?? createId('party-') })
}
reload()
} catch {
synced.current = false
}
}
void run()
}, [ready, upsertPartyAsync, reload])
return null
}