Skip to content

Commit ad4cd5e

Browse files
committed
feat: add all required methods to create vouchers
1 parent 3b0b0fd commit ad4cd5e

File tree

5 files changed

+488
-3
lines changed

5 files changed

+488
-3
lines changed

src/SevdeskApiClient.ts

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
import {
2+
SavedVoucher,
3+
CreateVoucherPayload,
4+
ExtractedVoucherInformation,
5+
TemporaryVoucherFile,
6+
VoucherCreditDebit,
7+
VoucherTaxRule,
8+
} from './types/voucher';
9+
110
/**
211
* A client for the sevdesk API.
312
* @link https://api.sevdesk.de/
@@ -25,9 +34,77 @@ export default class XentralApiClient {
2534
* @returns The bookkeeping system version
2635
*/
2736
getBookkeepingSystemVersion(): Promise<{ version: '1.0' | '2.0' }> {
28-
return this.apiRequest('/Tools/bookkeepingSystemVersion')
29-
.then((res) => res.json())
30-
.then(({ objects }) => objects);
37+
return this.apiRequest('/Tools/bookkeepingSystemVersion').then(
38+
extractObjectsFromRes,
39+
);
40+
}
41+
//#endregion
42+
43+
//#region Voucher
44+
/**
45+
* Upload a PDF file for creating a voucher.
46+
* @param file.blob PDF blob
47+
* @param file.filename PDF filename
48+
* @returns Temporary voucher file to be used with {@link extractVoucherInformationFromPdf} or {@link createVoucher}
49+
*/
50+
uploadTemporaryVoucherFile({
51+
blob,
52+
filename,
53+
}: {
54+
blob: Blob;
55+
filename: string;
56+
}): Promise<TemporaryVoucherFile> {
57+
const body = new FormData();
58+
body.append('file', blob, filename);
59+
return this.apiRequest('/Voucher/Factory/uploadTempFile', {
60+
method: 'POST',
61+
body,
62+
}).then(extractObjectsFromRes);
63+
}
64+
65+
/**
66+
* Extract voucher information from a previously uploaded voucher file.
67+
* @param temporaryVoucherFile Temporary voucher file previously created using {@link uploadTemporaryVoucherFile}
68+
* @returns Extracted voucher information
69+
*/
70+
extractVoucherInformationFromPdf(
71+
temporaryVoucherFile: Pick<TemporaryVoucherFile, 'filename' | 'mimeType'>,
72+
): Promise<ExtractedVoucherInformation> {
73+
const body = new FormData();
74+
body.append('fileName', temporaryVoucherFile.filename);
75+
body.append('mimeType', temporaryVoucherFile.mimeType);
76+
return this.apiRequest('/Voucher/Factory/createFromPdf', {
77+
method: 'POST',
78+
body: body,
79+
}).then(extractObjectsFromRes);
80+
}
81+
82+
/**
83+
* Create a new voucher.
84+
* @param voucher Voucher information
85+
* @returns The created voucher
86+
*/
87+
createVoucher(voucher: CreateVoucherPayload): Promise<SavedVoucher> {
88+
return this.apiRequest('/Voucher/Factory/saveVoucher', {
89+
method: 'POST',
90+
body: JSON.stringify(voucher),
91+
headers: {
92+
'Content-Type': 'application/json',
93+
},
94+
}).then(extractObjectsFromRes);
95+
}
96+
97+
/**
98+
* Get the default tax rule for vouchers.
99+
* Only applies to Sevdesk 2.0 (check with {@link getBookkeepingSystemVersion}).
100+
* @param voucherType Voucher type
101+
*/
102+
getDefaultVoucherTaxRule(
103+
voucherType: VoucherCreditDebit,
104+
): Promise<VoucherTaxRule> {
105+
return this.apiRequest(
106+
`/Voucher/Factory/getDefaultTaxRule?voucherType=${voucherType}`,
107+
).then(extractObjectsFromRes);
31108
}
32109
//#endregion
33110

@@ -74,3 +151,7 @@ export default class XentralApiClient {
74151
});
75152
}
76153
}
154+
155+
function extractObjectsFromRes(res: Response) {
156+
return res.json().then(({ objects }) => objects);
157+
}

src/helpers.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { MixedNumber, NumericBoolean } from './types/common';
2+
3+
export function parseNumber(number: MixedNumber): number {
4+
if (typeof number === 'number') {
5+
return number;
6+
}
7+
return parseFloat(number);
8+
}
9+
10+
export function parseOptionalNumber(
11+
number: MixedNumber | null | undefined,
12+
): number | null {
13+
if (number == null) {
14+
return null;
15+
}
16+
if (typeof number === 'number') {
17+
return number;
18+
}
19+
return parseFloat(number);
20+
}
21+
22+
export function parseBoolean(boolean: NumericBoolean): boolean {
23+
return boolean === '1';
24+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { default } from './SevdeskApiClient';
2+
export * from './helpers';

src/types/common.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface ObjectReference<T extends string> {
2+
id: string | number;
3+
objectName: T;
4+
}
5+
6+
export type NumericBoolean = '1' | '0';
7+
8+
export type MixedNumber = string | number;

0 commit comments

Comments
 (0)