import {z} from 'zod' export type DocumentType = 'JOURNAL_ENTRY' | 'PAYMENT' | 'CREDIT_MEMO' | 'INVOICE' | 'PURCHASE_ORDER' | 'TRANSFER' | 'EXPENSE_REPORT'; export type CurrencyCode = string; export type AmountIntegerValueInput = {currency: CurrencyCode, value: number}; export type AmountStringValueInput = {currency: CurrencyCode, stringValue: string}; export type AmountInput = AmountIntegerValueInput | AmountStringValueInput; export type MultiCurrencyAmountInput = {baseAmount: AmountInput, instructedAmount: AmountInput}; export type Date = string; export type CounterpartyType = 'VENDOR' | 'CUSTOMER' | 'EMPLOYEE' | 'GL_ENTITY'; export type AccountingCounterparty = {name: string, type: CounterpartyType, erpId: string}; export type ResourceID = string; export type GLEntryAmountInput = {baseAmount: AmountInput, instructedAmount?: AmountInput | undefined}; export type GLEntryType = 'DEBIT' | 'CREDIT'; export type CreateGLEntryRequest = {vendorId: string, glAccountId: string, vendorBankAccountId?: ResourceID | undefined, glClassificationIds?: Array | undefined, amount: GLEntryAmountInput, type: GLEntryType}; export type CreateAppliedDocumentRequest = {amount: AmountInput, targetDocumentId?: string | undefined, targetDocumentType: DocumentType, targetDocumentExternalId: string, date?: Date | undefined}; export type DocumentProvenanceResourceType = 'FILE' | 'API'; export type ContentType = 'application/vnd.iso20022.pain.001.001.03+xml' | 'application/vnd.iso20022.pain.001.001.03.ch.02+xml' | 'application/vnd.iso20022.pain.001.001.09+xml' | 'application/vnd.iso20022.pain.001.001.09.ch.03+xml' | 'application/vnd.iso20022.pain.002.001.03+xml' | 'application/vnd.iso20022.pain.002.001.10+xml' | 'application/vnd.iso20022.pain.008.001.02+xml' | 'application/vnd.iso20022.pain.008.001.02.ch.03+xml' | 'application/vnd.iso20022.pain.008.001.03+xml' | 'application/vnd.iso20022.pain.008.001.08+xml' | 'application/vnd.iso20022.camt.052.001.02+xml' | 'application/vnd.iso20022.camt.052.001.03+xml' | 'application/vnd.iso20022.camt.052.001.04+xml' | 'application/vnd.iso20022.camt.052.001.08+xml' | 'application/vnd.iso20022.camt.053.001.02+xml' | 'application/vnd.iso20022.camt.053.001.03+xml' | 'application/vnd.iso20022.camt.053.001.04+xml' | 'application/vnd.iso20022.camt.053.001.08+xml' | 'application/vnd.iso20022.camt.053.001.10+xml' | 'application/vnd.iso20022.camt.053.001.11+xml' | 'application/vnd.iso20022.camt.053.001.12+xml' | 'application/vnd.iso20022.camt.054.001.02+xml' | 'application/vnd.iso20022.pacs.002.001.10+xml' | 'application/vnd.iso20022.pacs.008.001.02+xml' | 'application/vnd.iso20022.pacs.008.001.08+xml' | 'application/vnd.swift.mt.101' | 'application/vnd.swift.mt.103' | 'application/vnd.swift.mt.900' | 'application/vnd.swift.mt.940' | 'application/vnd.swift.mt.942' | 'application/vnd.bai.bai2' | 'application/vnd.bgc.autogiro.payee' | 'application/vnd.bgc.autogiro.payments.rejected' | 'application/vnd.bgc.autogiro.payments.spec' | 'application/vnd.bgc.autogiro.mandate' | 'application/vnd.bgc.payins.bgmax' | 'application/vnd.nacha.ach' | 'application/vnd.atlar.testbank.mandate+json' | 'application/vnd.atlar.testbank.transaction+json' | 'application/vnd.atlar.connectivity.proprietary' | 'application/vnd.atlar.connectivity.proprietary+json' | 'application/vnd.atlar.connectivity.proprietary+xml' | 'application/vnd.atlar.connectivity.proprietary+csv' | 'application/vnd.atlar.connectivity.v2.investment-statement+json' | 'application/vnd.atlar.connectivity.v2.accounting-statement+json' | 'application/vnd.atlar.connectivity.v2.fx-rate-statement+json' | 'application/vnd.atlar.connectivity.v2.benchmark-rate-statement+json' | 'application/vnd.atlar.connectivity.v2.instrument-product-statement+json' | 'application/vnd.atlar.connectivity.v2.statement+json' | 'application/vnd.atlar.connectivity.v2.statement+csv' | 'application/vnd.deutsche.wealth-online+csv' | 'application/vnd.m2.m006.m001+xml' | 'application/vnd.m2.m006.m005+xml' | 'application/vnd.ebics.htd.v30+xml' | 'application/vnd.ebics.hac.v25+xml' | 'application/vnd.ebics.hac.v30+xml' | 'application/vnd.jpm.daily-feed+zip' | 'application/vnd.jpm.morgan-money.balance-report+csv' | 'application/vnd.jpm.morgan-money.transaction-report+csv' | 'application/vnd.jpm.soci.holdings+csv' | 'application/vnd.jpm.soci.transactions+csv' | 'application/vnd.jpm.soci.cash-balance+csv' | 'application/vnd.nordea.investments.abasec.pos+csv' | 'application/vnd.nordea.investments.abasec.tra+csv' | 'application/vnd.blackrock.cachematrix.balance+csv' | 'application/vnd.blackrock.cachematrix.transactions+csv' | 'application/vnd.adyen.balance-platform.statement-report+csv' | 'application/vnd.ms-excel' | 'application/x-ofx' | 'application/json' | 'application/zip' | 'application/pdf' | 'text/plain' | 'text/csv' | 'application/vnd.edi.820' | 'application/vnd.edi.824' | 'application/vnd.edi.997'; export type DocumentProvenance = {vendorId: string, vendorTimestamp: string, resource: {type: DocumentProvenanceResourceType, name: string, contentType: ContentType, timestamp: string} | {type: DocumentProvenanceResourceType, url: string, contentType: ContentType, timestamp: string}}; export type CurrencyExchange = {exchangeRate: string, sourceCurrency: CurrencyCode, targetCurrency?: CurrencyCode | undefined, unitCurrency?: CurrencyCode | undefined}; export type CreateDocumentRequest = {glEntityId: string, type: DocumentType, amount: MultiCurrencyAmountInput, remainingAmount?: MultiCurrencyAmountInput | undefined, date: Date, issueDate?: Date | undefined, description: string, reference?: string | undefined, references: {[key: string]: string}, counterparty?: AccountingCounterparty | undefined, voided: boolean, reconciliationMatchId?: string | undefined, outgoingDocumentId?: string | undefined, glEntries: Array, appliedDocuments?: Array | undefined, provenance: DocumentProvenance, vendorCreated: string, vendorResourceUrl?: string | undefined, currencyExchange?: CurrencyExchange | undefined}; export type CreateApiAccountingV2betaDocumentsArgs = {body: CreateDocumentRequest}; export type CreateApiAccountingV2betaDocumentsOptions = {baseUrl?: string | undefined, basicAuth?: {username: string, password: string} | undefined, fetch?: typeof fetch | undefined}; export const resourceID = z.string().min(32).max(64); export const organizationID = z.string(); export const documentType = z.enum(["JOURNAL_ENTRY", "PAYMENT", "CREDIT_MEMO", "INVOICE", "PURCHASE_ORDER", "TRANSFER", "EXPENSE_REPORT"]); export const documentClassification = z.enum(["SOURCE", "INSTRUCTION"]); export const currencyCode = z.string().min(3).max(3); export const amount = z.object({currency: currencyCode, stringValue: z.string(), value: z.number().int()}); export const multiCurrencyAmount = z.object({baseAmount: amount, instructedAmount: amount}); export const date = z.string(); export const documentInvoiceDetails = z.object({settledDate: date.optional(), daysToDue: z.number().int().optional(), daysToSettled: z.number().int().optional(), settlementDaysPastDue: z.number().int().optional()}); export const counterpartyType = z.enum(["VENDOR", "CUSTOMER", "EMPLOYEE", "GL_ENTITY"]); export const accountingCounterparty = z.object({name: z.string(), type: counterpartyType, erpId: z.string()}); export const documentReconciliationStatus = z.enum(["OPEN", "MATCHED", "RECONCILED", "IGNORED"]); export const gLEntryAmount = z.object({baseAmount: amount, instructedAmount: amount.optional()}); export const gLEntryType = z.enum(["DEBIT", "CREDIT"]); export const gLEntry = z.object({id: resourceID, vendorId: z.string(), glAccountId: resourceID, vendorBankAccountId: resourceID.optional(), glClassificationIds: z.array(resourceID).optional(), amount: gLEntryAmount, type: gLEntryType}); export const appliedDocument = z.object({amount: amount, targetDocumentId: resourceID.optional(), targetDocumentType: documentType, targetDocumentExternalId: z.string(), date: date.optional()}); export const documentProvenanceResourceType = z.enum(["FILE", "API"]); export const contentType = z.enum(["application/vnd.iso20022.pain.001.001.03+xml", "application/vnd.iso20022.pain.001.001.03.ch.02+xml", "application/vnd.iso20022.pain.001.001.09+xml", "application/vnd.iso20022.pain.001.001.09.ch.03+xml", "application/vnd.iso20022.pain.002.001.03+xml", "application/vnd.iso20022.pain.002.001.10+xml", "application/vnd.iso20022.pain.008.001.02+xml", "application/vnd.iso20022.pain.008.001.02.ch.03+xml", "application/vnd.iso20022.pain.008.001.03+xml", "application/vnd.iso20022.pain.008.001.08+xml", "application/vnd.iso20022.camt.052.001.02+xml", "application/vnd.iso20022.camt.052.001.03+xml", "application/vnd.iso20022.camt.052.001.04+xml", "application/vnd.iso20022.camt.052.001.08+xml", "application/vnd.iso20022.camt.053.001.02+xml", "application/vnd.iso20022.camt.053.001.03+xml", "application/vnd.iso20022.camt.053.001.04+xml", "application/vnd.iso20022.camt.053.001.08+xml", "application/vnd.iso20022.camt.053.001.10+xml", "application/vnd.iso20022.camt.053.001.11+xml", "application/vnd.iso20022.camt.053.001.12+xml", "application/vnd.iso20022.camt.054.001.02+xml", "application/vnd.iso20022.pacs.002.001.10+xml", "application/vnd.iso20022.pacs.008.001.02+xml", "application/vnd.iso20022.pacs.008.001.08+xml", "application/vnd.swift.mt.101", "application/vnd.swift.mt.103", "application/vnd.swift.mt.900", "application/vnd.swift.mt.940", "application/vnd.swift.mt.942", "application/vnd.bai.bai2", "application/vnd.bgc.autogiro.payee", "application/vnd.bgc.autogiro.payments.rejected", "application/vnd.bgc.autogiro.payments.spec", "application/vnd.bgc.autogiro.mandate", "application/vnd.bgc.payins.bgmax", "application/vnd.nacha.ach", "application/vnd.atlar.testbank.mandate+json", "application/vnd.atlar.testbank.transaction+json", "application/vnd.atlar.connectivity.proprietary", "application/vnd.atlar.connectivity.proprietary+json", "application/vnd.atlar.connectivity.proprietary+xml", "application/vnd.atlar.connectivity.proprietary+csv", "application/vnd.atlar.connectivity.v2.investment-statement+json", "application/vnd.atlar.connectivity.v2.accounting-statement+json", "application/vnd.atlar.connectivity.v2.fx-rate-statement+json", "application/vnd.atlar.connectivity.v2.benchmark-rate-statement+json", "application/vnd.atlar.connectivity.v2.instrument-product-statement+json", "application/vnd.atlar.connectivity.v2.statement+json", "application/vnd.atlar.connectivity.v2.statement+csv", "application/vnd.deutsche.wealth-online+csv", "application/vnd.m2.m006.m001+xml", "application/vnd.m2.m006.m005+xml", "application/vnd.ebics.htd.v30+xml", "application/vnd.ebics.hac.v25+xml", "application/vnd.ebics.hac.v30+xml", "application/vnd.jpm.daily-feed+zip", "application/vnd.jpm.morgan-money.balance-report+csv", "application/vnd.jpm.morgan-money.transaction-report+csv", "application/vnd.jpm.soci.holdings+csv", "application/vnd.jpm.soci.transactions+csv", "application/vnd.jpm.soci.cash-balance+csv", "application/vnd.nordea.investments.abasec.pos+csv", "application/vnd.nordea.investments.abasec.tra+csv", "application/vnd.blackrock.cachematrix.balance+csv", "application/vnd.blackrock.cachematrix.transactions+csv", "application/vnd.adyen.balance-platform.statement-report+csv", "application/vnd.ms-excel", "application/x-ofx", "application/json", "application/zip", "application/pdf", "text/plain", "text/csv", "application/vnd.edi.820", "application/vnd.edi.824", "application/vnd.edi.997"]); export const documentProvenance = z.object({vendorId: z.string(), vendorTimestamp: z.string(), resource: z.discriminatedUnion("type", [z.object({type: documentProvenanceResourceType, name: z.string(), contentType: contentType, timestamp: z.string()}), z.object({type: documentProvenanceResourceType, url: z.string(), contentType: contentType, timestamp: z.string()})])}); export const currencyExchange = z.object({exchangeRate: z.string(), sourceCurrency: currencyCode, targetCurrency: currencyCode.optional(), unitCurrency: currencyCode.optional()}); export const resourceVersion = z.number().int().gte(1); export const eTag = z.string(); export const createdTimestamp = z.string(); export const updatedTimestamp = z.string(); export const document = z.object({id: resourceID, organizationId: organizationID, glEntityId: z.string(), type: documentType, classification: documentClassification, amount: multiCurrencyAmount, remainingAmount: multiCurrencyAmount.optional(), date: date, issueDate: date, invoiceDetails: documentInvoiceDetails.optional(), description: z.string().min(1).max(255), reference: z.string().min(1).max(255).optional(), references: z.record(z.string(), z.string()), counterparty: accountingCounterparty.optional(), voided: z.boolean(), reconciliationStatus: documentReconciliationStatus, reconciliationMatchId: resourceID.optional(), outgoingDocumentId: resourceID.optional(), glEntries: z.array(gLEntry), appliedDocuments: z.array(appliedDocument).optional(), provenance: documentProvenance, vendorCreated: z.string(), vendorResourceUrl: z.string().optional(), currencyExchange: currencyExchange.optional(), version: resourceVersion, etag: eTag, created: createdTimestamp, updated: updatedTimestamp}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Create document * * POST /accounting/v2beta/documents */ export const createApiAccountingV2betaDocuments = async (args: CreateApiAccountingV2betaDocumentsArgs, options?: CreateApiAccountingV2betaDocumentsOptions) => { const {baseUrl = "https://api.atlar.com", fetch: fetchFn = fetch, basicAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (basicAuth !== undefined) headers.set('authorization', `Basic ${btoa(`${basicAuth.username}:${basicAuth.password}`)}`) const url = `${baseUrl.replace(/\/+$/, '')}/accounting/v2beta/documents${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(document, await res.json()) };