Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds getPaymentMethods, saveInvoice, getTags, getSevUsers, getContactAddresses, getStaticCountries, getParts #2

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"singleQuote": false
}
182 changes: 182 additions & 0 deletions src/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ import * as env from "./tests/env.js";
import {
ModelCommunicationWay,
ModelContact,
ModelContactAddress,
ModelDocument,
ModelDocumentFolder,
ModelInvoice,
ModelPart,
ModelPaymentMethod,
ModelSevUser,
ModelStaticCountry,
ModelTag,
ModelUnity,
} from "./interfaces.js";

Expand Down Expand Up @@ -46,6 +52,105 @@ test("Get next invoice number", async () => {
assert.type(nextInvoiceNumber, "string");
});

test("Create a new invoice", async () => {
const invoiceNumber = `TEST-${new Date().toISOString()}`;
const { objects: contacts } = await sevDeskClient.getContacts();

const {
objects: { invoice },
} = await sevDeskClient.saveInvoice({
invoice: {
// id: null,
objectName: "Invoice",
invoiceNumber,
contact: {
id: contacts[0].id,
objectName: "Contact",
},
contactPerson: {
id: env.CONTACT_PERSON_ID,
objectName: "SevUser",
},
invoiceDate: "01.01.2022",
header: `Invoice ${invoiceNumber}`,
headText: "header information",
footText: "footer information",
timeToPay: 20,
discount: 0,
address: "name\nstreet\npostCode city",
addressCountry: {
id: 1,
objectName: "StaticCountry",
},
payDate: "2019-08-24T14:15:22Z",
deliveryDate: "01.01.2022",
deliveryDateUntil: null,
status: "100",
smallSettlement: 0,
taxRate: 0,
taxRule: {
id: "1",
objectName: "TaxRule",
},
taxText: "Umsatzsteuer 19%",
taxType: "default",
taxSet: null,
paymentMethod: {
id: 21919,
objectName: "PaymentMethod",
},
sendDate: "01.01.2020",
invoiceType: "RE",
currency: "EUR",
showNet: "1",
sendType: "VPR",
origin: null,
customerInternalNote: null,
propertyIsEInvoice: false,
mapAll: true,
},
invoicePosSave: [
{
id: null,
objectName: "InvoicePos",
mapAll: true,
// part: {
// id: 0,
// objectName: 'Part',
// },
quantity: 1,
price: 100,
name: "Dragonglass",
unity: {
id: 1,
objectName: "Unity",
},
positionNumber: 0,
text: "string",
discount: 0.1,
taxRate: 19,
priceGross: 100,
priceTax: 0.1,
},
],
invoicePosDelete: null,
filename: "string",
discountSave: [
{
discount: "true",
text: "string",
percentage: true,
value: 0,
objectName: "Discounts",
mapAll: "true",
},
],
discountDelete: null,
});

assertIsInvoice(invoice);
});

test("Get document folders", async () => {
const { objects: documentFolders } = await sevDeskClient.getDocumentFolders();

Expand Down Expand Up @@ -78,6 +183,24 @@ test("Get contacts", async () => {
contacts.forEach(assertIsContact);
});

test("Get contact addresses (without contact ID)", async () => {
const { objects: contactAddresses } =
await sevDeskClient.getContactAddresses();

assert.is(contactAddresses.length > 0, true);
contactAddresses.forEach(assertIsContactAddress);
});

test("Get contact addresses (with contact ID)", async () => {
const { objects: contacts } = await sevDeskClient.getContacts();
const { objects: contactAddresses } = await sevDeskClient.getContactAddresses(
{ contactId: contacts[0].id }
);

assert.is(contactAddresses.length > 0, true);
contactAddresses.forEach(assertIsContactAddress);
});

test("Get communication ways", async () => {
const { objects: communicationWays } =
await sevDeskClient.getCommunicationWays();
Expand All @@ -93,6 +216,41 @@ test("Get unities", async () => {
unities.forEach(assertIsUnity);
});

test("Get payment methods", async () => {
const { objects: paymentMethods } = await sevDeskClient.getPaymentMethods();

assert.is(paymentMethods.length > 0, true);
paymentMethods.forEach(assertIsPaymentMethod);
});

test("Get tags", async () => {
const { objects: tags } = await sevDeskClient.getTags();

assert.is(tags.length > 0, true);
tags.forEach(assertIsTag);
});

test("Get users", async () => {
const { objects: users } = await sevDeskClient.getSevUsers();

assert.is(users.length > 0, true);
users.forEach(assertIsSevUser);
});

test("Get static countries", async () => {
const { objects: countries } = await sevDeskClient.getStaticCountries();

assert.is(countries.length > 0, true);
countries.forEach(assertIsStaticCountry);
});

test("Get parts", async () => {
const { objects: parts } = await sevDeskClient.getParts();

assert.is(parts.length > 0, true);
parts.forEach(assertIsPart);
});

const assertIsInvoice = (invoice: ModelInvoice) => {
assert.is(invoice.objectName, "Invoice");
};
Expand All @@ -109,6 +267,10 @@ const assertIsContact = (contact: ModelContact) => {
assert.is(contact.objectName, "Contact");
};

const assertIsContactAddress = (contact: ModelContactAddress) => {
assert.is(contact.objectName, "ContactAddress");
};

const assertIsCommunicationWay = (communicationWay: ModelCommunicationWay) => {
assert.is(communicationWay.objectName, "CommunicationWay");
};
Expand All @@ -117,4 +279,24 @@ const assertIsUnity = (unity: ModelUnity) => {
assert.is(unity.objectName, "Unity");
};

const assertIsPaymentMethod = (paymentMethod: ModelPaymentMethod) => {
assert.is(paymentMethod.objectName, "PaymentMethod");
};

const assertIsTag = (tag: ModelTag) => {
assert.is(tag.objectName, "Tag");
};

const assertIsSevUser = (user: ModelSevUser) => {
assert.is(user.objectName, "SevUser");
};

const assertIsStaticCountry = (user: ModelStaticCountry) => {
assert.is(user.objectName, "StaticCountry");
};

const assertIsPart = (part: ModelPart) => {
assert.is(part.objectName, "Part");
};

test.run();
127 changes: 126 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ import { UnknownApiError } from "./errors.js";
import {
ModelCommunicationWay,
ModelContact,
ModelContactAddress,
ModelDocument,
ModelDocumentFolder,
ModelInvoice,
ModelInvoicePos,
ModelPart,
ModelPaymentMethod,
ModelSevUser,
ModelStaticCountry,
ModelTag,
ModelUnity,
} from "./interfaces.js";
import { SevDeskUrls } from "./urls.js";
Expand Down Expand Up @@ -63,7 +70,7 @@ export class SevDeskClient {
throw error;
}
if (response.ok === false || error) {
const message = error?.message ?? body?.error?.message;
const message = error?.message ?? body?.error?.message ?? body.message;

throw new UnknownApiError(message, { response });
}
Expand Down Expand Up @@ -112,6 +119,25 @@ export class SevDeskClient {
}>(url, { method: "GET" });
}

/**
* Create a new invoice
*/
async saveInvoice(body: unknown) {
const url = this.urls.apiSaveInvoiceUrl();

return this.request<{
objects: {
invoice: Required<ModelInvoice>;
invoicePos: Array<Required<ModelInvoicePos>>;
filename: string;
};
}>(url, {
method: "POST",
body: JSON.stringify(body),
headers: { "Content-Type": "application/json" },
});
}

// -------------------------------------------------------
// DocumentFolder
// -------------------------------------------------------
Expand Down Expand Up @@ -189,6 +215,26 @@ export class SevDeskClient {
});
}

// -------------------------------------------------------
// ContactAddress
// -------------------------------------------------------

/**
* Get an overview of all contact addresses
*/
async getContactAddresses(
params: UrlParamsFor<"apiGetContactAddressesUrl"> = {}
) {
const url = this.urls.apiGetContactAddressesUrl(params);

return this.request<{ objects: Array<Required<ModelContactAddress>> }>(
url,
{
method: "GET",
}
);
}

// -------------------------------------------------------
// CommunicationWay
// -------------------------------------------------------
Expand Down Expand Up @@ -228,6 +274,85 @@ export class SevDeskClient {
});
}

// -------------------------------------------------------
// PaymentMethod
// -------------------------------------------------------

/**
* Get an overview of all payment methods
*/
async getPaymentMethods(
params: UrlParamsFor<"apiGetPaymentMethodsUrl"> = {}
) {
const url = this.urls.apiGetPaymentMethodsUrl(params);

return this.request<{ objects: Array<Required<ModelPaymentMethod>> }>(url, {
method: "GET",
});
}

// -------------------------------------------------------
// Tag
// -------------------------------------------------------

/**
* Get an overview of all tags
*/
async getTags(params: UrlParamsFor<"apiGetTagsUrl"> = {}) {
const url = this.urls.apiGetTagsUrl(params);

return this.request<{ objects: Array<Required<ModelTag>> }>(url, {
method: "GET",
});
}

// -------------------------------------------------------
// SevUser
// -------------------------------------------------------

/**
* Get an overview of all users
*/
async getSevUsers(params: UrlParamsFor<"apiGetSevUsersUrl"> = {}) {
const url = this.urls.apiGetSevUsersUrl(params);

return this.request<{ objects: Array<Required<ModelSevUser>> }>(url, {
method: "GET",
});
}

// -------------------------------------------------------
// StaticCountry
// -------------------------------------------------------

/**
* Get an overview of all static countries
*/
async getStaticCountries(
params: UrlParamsFor<"apiGetStaticCountriesUrl"> = {}
) {
const url = this.urls.apiGetStaticCountriesUrl(params);

return this.request<{ objects: Array<Required<ModelStaticCountry>> }>(url, {
method: "GET",
});
}

// -------------------------------------------------------
// Part
// -------------------------------------------------------

/**
* Get an overview of all parts
*/
async getParts(params: UrlParamsFor<"apiGetPartsUrl"> = {}) {
const url = this.urls.apiGetPartsUrl(params);

return this.request<{ objects: Array<Required<ModelPart>> }>(url, {
method: "GET",
});
}

// // pending invoices from sevdesk includes also outstanding / due invoices
// // we remove them with a filter but you could also include the if you only need everything pending
// async getPendingInvoices(options = { includeOutstanding: false }) {
Expand Down
Loading