From 85d93868234898723549caae5b67157471185d36 Mon Sep 17 00:00:00 2001 From: Victor Felder Date: Mon, 7 Oct 2019 16:56:30 +0200 Subject: [PATCH 1/6] adds projects --- src/constants/Scopes.ts | 2 + src/index.ts | 5 ++ src/interfaces/ProjectsStatic.ts | 58 +++++++++++++++++ src/resources/Projects.ts | 17 +++++ src/tests/Projects.test.ts | 104 +++++++++++++++++++++++++++++++ 5 files changed, 186 insertions(+) create mode 100644 src/interfaces/ProjectsStatic.ts create mode 100644 src/resources/Projects.ts create mode 100644 src/tests/Projects.test.ts diff --git a/src/constants/Scopes.ts b/src/constants/Scopes.ts index 8ef7387..7371d23 100644 --- a/src/constants/Scopes.ts +++ b/src/constants/Scopes.ts @@ -23,6 +23,8 @@ enum Scopes { MONITORING_EDIT = 'monitoring_edit', NOTE_SHOW = 'note_show', NOTE_EDIT = 'note_edit', + PROJECT_SHOW = 'project_show', + PROJECT_EDIT = 'project_edit', TASK_SHOW = 'task_show', TASK_EDIT = 'task_edit', GENERAL = 'general' diff --git a/src/index.ts b/src/index.ts index 48aa4a8..c29a675 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ import ContactRelations from "./resources/ContactRelations"; import Expenses from "./resources/Expenses"; import Bills from "./resources/Bills"; import Orders from "./resources/Orders"; +import Projects from "./resources/Projects"; import request from "request-promise-native"; import { CookieJar } from "request"; import Timetrackings from "./resources/Timetrackings"; @@ -23,6 +24,7 @@ export * from "./interfaces/ContactsStatic"; export * from "./interfaces/ExpensesStatic"; export * from "./interfaces/NotesStatic"; export * from "./interfaces/OrdersStatic"; +export * from "./interfaces/ProjectsStatic"; export * from "./interfaces/SalesOrderManagementStatic"; export * from "./interfaces/TimetrackingsStatic"; export * from "./interfaces/TimetrackingStatusesStatic"; @@ -49,6 +51,8 @@ export default class Bexio { public expenses: Expenses; public bills: Bills; + public projects: Projects; + // Timesheets public timetrackings: Timetrackings; public timetrackingStatuses: TimetrackingStatuses; @@ -81,6 +85,7 @@ export default class Bexio { this.contactGroups = new ContactGroups(this.bexioAuth); this.contactRelations = new ContactRelations(this.bexioAuth); this.orders = new Orders(this.bexioAuth); + this.projects = new Projects(this.bexioAuth); this.expenses = new Expenses(this.bexioAuth); this.bills = new Bills(this.bexioAuth); this.timetrackings = new Timetrackings(this.bexioAuth); diff --git a/src/interfaces/ProjectsStatic.ts b/src/interfaces/ProjectsStatic.ts new file mode 100644 index 0000000..fa3bfad --- /dev/null +++ b/src/interfaces/ProjectsStatic.ts @@ -0,0 +1,58 @@ +export namespace ProjectsStatic { + export interface Project { + id: number; + nr: string; + name: string; + start_date?: string; + end_date?: string; + comment: string; + pr_state_id: number; + pr_project_type_id: number; + contact_id: number; + contact_sub_id?: number; + pr_invoice_type_id?: number; + pr_invoice_type_amount: number; + pr_budget_type_id?: number; + pr_budget_type_amount: number; + } + + export interface ProjectCreate { + contact_id: number; + name: string; + pr_project_type_id: number; + pr_state_id: number; + user_id: number; + comment?: string; + contact_sub_id?: number; + end_date?: string; + pr_budget_type_amount?: number; + pr_budget_type_id?: number; + pr_invoice_type_amount?: number; + pr_invoice_type_id?: number; + pr_sub_state_id?: number; + start_date?: string; + } + + export interface ProjectOverwrite { + contact_id: number; + name: string; + pr_project_type_id: number; + pr_state_id: number; + user_id: number; + comment?: string; + contact_sub_id?: number; + end_date?: string; + pr_budget_type_amount?: number; + pr_budget_type_id?: number; + pr_invoice_type_amount?: number; + pr_invoice_type_id?: number; + pr_sub_state_id?: number; + start_date?: string; + } + + export enum ProjectSearchParameters { + name = "name", + contact_id = "contact_id", + pr_state_id = "pr_state_id", + } +} diff --git a/src/resources/Projects.ts b/src/resources/Projects.ts new file mode 100644 index 0000000..3c996d6 --- /dev/null +++ b/src/resources/Projects.ts @@ -0,0 +1,17 @@ +import { ProjectsStatic } from "../interfaces/ProjectsStatic"; +import BaseCrud from "./BaseCrud"; +import OAuth2 from "../libs/OAuth2"; +import Scopes from "../constants/Scopes"; + +export default class Projects extends BaseCrud< + ProjectsStatic.Project, + ProjectsStatic.Project, + ProjectsStatic.Project, + ProjectsStatic.ProjectSearchParameters, + ProjectsStatic.ProjectCreate, + ProjectsStatic.ProjectOverwrite +> { + constructor(bexioAuth: OAuth2) { + super(bexioAuth, "/pr_project", Scopes.PROJECT_SHOW, Scopes.PROJECT_EDIT); + } +} diff --git a/src/tests/Projects.test.ts b/src/tests/Projects.test.ts new file mode 100644 index 0000000..0688dc4 --- /dev/null +++ b/src/tests/Projects.test.ts @@ -0,0 +1,104 @@ +import Bexio, { Scopes } from ".."; +import { expect } from "chai"; +import Projects from "../resources/Projects"; +import { ProjectsStatic } from "../interfaces/ProjectsStatic"; +import dotenv from "dotenv"; + +dotenv.config(); + +describe("Projects", function() { + // increasing timeout to 60s + this.timeout(60000); + + let api: Bexio; + let moduleToTest: Projects; + let project: ProjectsStatic.Project; + const { + BEXIO_CLIENTID, + BEXIO_CLIENTSECRET, + HOSTNAME, + BEXIO_USERNAME, + BEXIO_PASSWORD + } = process.env; + + before(async () => { + if ( + !BEXIO_CLIENTID || + !BEXIO_CLIENTSECRET || + !HOSTNAME || + !BEXIO_USERNAME || + !BEXIO_PASSWORD + ) + throw new Error("not all necessary variables defined"); + + api = new Bexio( + BEXIO_CLIENTID, + BEXIO_CLIENTSECRET, + `http://${HOSTNAME}/callback`, + [Scopes.PROJECT_SHOW, Scopes.PROJECT_EDIT] + ); + await api.fakeLogin(BEXIO_USERNAME, BEXIO_PASSWORD); + }); + + it("init Projects object", () => { + moduleToTest = new Projects(api["bexioAuth"]); + }); + + it("create new project", async () => { + const name = `test-${Date.now()}`; + project = await moduleToTest.create({ + contact_id: 1, + pr_project_type_id: 1, + pr_state_id: 1, + user_id: 1, + name: name + }); + expect(project.name).to.be.eq(name); + }); + + it("list projects", async () => { + const list = await moduleToTest.list({}); + expect(list.map(el => el.id)).includes(project.id); + }); + + it("search project", async () => { + const searchResult = await moduleToTest.search({}, [ + { + field: ProjectsStatic.ProjectSearchParameters.id, + value: project.id, + criteria: "=" + } + ]); + expect(searchResult.length).to.be.eq(1); + expect(searchResult[0].id).to.be.eq(project.id); + expect(searchResult[0].name).to.be.eq(project.name); + }); + + it("show project", async () => { + const show = await moduleToTest.show({}, project.id); + expect(show.id).to.be.eq(project.id); + }); + + it("overwrite project", async () => { + const overwritten = await moduleToTest.overwrite(project.id, { + contact_id: 1, + pr_project_type_id: 1, + pr_state_id: 1, + user_id: 1, + name: `overwritten-${Date.now()}` + }); + expect(overwritten.name).include("overwritten-"); + }); + + it("edit project", async () => { + const edited = await moduleToTest.edit(project.id, { + name: `edited-${Date.now()}` + }); + expect(edited.name).include("edited-"); + }); + + it("delete project", async () => { + const result = await moduleToTest.delete(project.id); + expect(result).to.be.true; + }); +}); From 359bea641051d7057d586c6fa57d37dfe2aab3b0 Mon Sep 17 00:00:00 2001 From: Victor Felder Date: Mon, 7 Oct 2019 20:54:04 +0200 Subject: [PATCH 2/6] adds project statuses and project types --- src/index.ts | 9 ++ src/interfaces/ProjectStatusesStatic.ts | 10 ++ src/interfaces/ProjectTypesStatic.ts | 10 ++ src/resources/ProjectStatuses.ts | 76 +++++++++++++ src/resources/ProjectTypes.ts | 64 +++++++++++ src/tests/ProjectStatuses.test.ts | 139 ++++++++++++++++++++++++ src/tests/ProjectTypes.test.ts | 131 ++++++++++++++++++++++ src/tests/Projects.test.ts | 4 +- 8 files changed, 441 insertions(+), 2 deletions(-) create mode 100644 src/interfaces/ProjectStatusesStatic.ts create mode 100644 src/interfaces/ProjectTypesStatic.ts create mode 100644 src/resources/ProjectStatuses.ts create mode 100644 src/resources/ProjectTypes.ts create mode 100644 src/tests/ProjectStatuses.test.ts create mode 100644 src/tests/ProjectTypes.test.ts diff --git a/src/index.ts b/src/index.ts index c29a675..4630193 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,8 @@ import Expenses from "./resources/Expenses"; import Bills from "./resources/Bills"; import Orders from "./resources/Orders"; import Projects from "./resources/Projects"; +import ProjectStatuses from "./resources/ProjectStatuses"; +import ProjectTypes from "./resources/ProjectTypes"; import request from "request-promise-native"; import { CookieJar } from "request"; import Timetrackings from "./resources/Timetrackings"; @@ -25,6 +27,8 @@ export * from "./interfaces/ExpensesStatic"; export * from "./interfaces/NotesStatic"; export * from "./interfaces/OrdersStatic"; export * from "./interfaces/ProjectsStatic"; +export * from "./interfaces/ProjectStatusesStatic"; +export * from "./interfaces/ProjectTypesStatic"; export * from "./interfaces/SalesOrderManagementStatic"; export * from "./interfaces/TimetrackingsStatic"; export * from "./interfaces/TimetrackingStatusesStatic"; @@ -51,7 +55,10 @@ export default class Bexio { public expenses: Expenses; public bills: Bills; + // Projects public projects: Projects; + public projectStatuses: ProjectStatuses; + public projectTypes: ProjectTypes; // Timesheets public timetrackings: Timetrackings; @@ -86,6 +93,8 @@ export default class Bexio { this.contactRelations = new ContactRelations(this.bexioAuth); this.orders = new Orders(this.bexioAuth); this.projects = new Projects(this.bexioAuth); + this.projectStatuses = new ProjectStatuses(this.bexioAuth); + this.projectTypes = new ProjectTypes(this.bexioAuth); this.expenses = new Expenses(this.bexioAuth); this.bills = new Bills(this.bexioAuth); this.timetrackings = new Timetrackings(this.bexioAuth); diff --git a/src/interfaces/ProjectStatusesStatic.ts b/src/interfaces/ProjectStatusesStatic.ts new file mode 100644 index 0000000..27aaa3f --- /dev/null +++ b/src/interfaces/ProjectStatusesStatic.ts @@ -0,0 +1,10 @@ +export namespace ProjectStatusesStatic { + export interface ProjectStatus { + id: number; + name: string; + } + + export enum ProjectStatusSearchParameters { + text = 'text' + } +} diff --git a/src/interfaces/ProjectTypesStatic.ts b/src/interfaces/ProjectTypesStatic.ts new file mode 100644 index 0000000..67e0469 --- /dev/null +++ b/src/interfaces/ProjectTypesStatic.ts @@ -0,0 +1,10 @@ +export namespace ProjectTypesStatic { + export interface ProjectType { + id: number; + name: string; + } + + export enum ProjectTypeSearchParameters { + project_type = 'project_type' + } +} diff --git a/src/resources/ProjectStatuses.ts b/src/resources/ProjectStatuses.ts new file mode 100644 index 0000000..fb50bf9 --- /dev/null +++ b/src/resources/ProjectStatuses.ts @@ -0,0 +1,76 @@ +import BaseCrud from "./BaseCrud"; +import OAuth2 from "../libs/OAuth2"; +import { Scopes } from ".."; +import { ProjectStatusesStatic } from "../interfaces/ProjectStatusesStatic"; + +export default class ProjectStatuses extends BaseCrud< + ProjectStatusesStatic.ProjectStatus, + ProjectStatusesStatic.ProjectStatus, + ProjectStatusesStatic.ProjectStatus, + ProjectStatusesStatic.ProjectStatusSearchParameters, + {}, + {} +> { + constructor(bexioAuth: OAuth2) { + super( + bexioAuth, + "/pr_project_state", + Scopes.PROJECT_SHOW, + Scopes.PROJECT_EDIT + ); + } + + /** + * Not implemented by Bexio yet + * + * @param {number} id + * @param {{}} ressource + * @returns {Promise} + * @memberof ProjectStatuses + */ + public async overwrite( + id: number, + ressource: {} + ): Promise { + throw new Error("not implemented by Bexio yet"); + } + + /** + * Not implemented by Bexio yet + * + * @param {number} id + * @param {{}} ressource + * @returns {Promise} + * @memberof ProjectStatuses + */ + public async edit( + id: number, + ressource: {} + ): Promise { + throw new Error("not implemented by Bexio yet"); + } + + /** + * Not implemented by Bexio yet + * + * @param {{}} ressource + * @returns {Promise} + * @memberof ProjectStatuses + */ + public async create(ressource: {}): Promise< + ProjectStatusesStatic.ProjectStatus + > { + throw new Error("not implemented by Bexio yet"); + } + + /** + * Not implemented by Bexio yet + * + * @param {number} id + * @returns {Promise} + * @memberof ProjectStatuses + */ + public async delete(id: number): Promise { + throw new Error("not implemented by Bexio yet"); + } +} diff --git a/src/resources/ProjectTypes.ts b/src/resources/ProjectTypes.ts new file mode 100644 index 0000000..4a76f7d --- /dev/null +++ b/src/resources/ProjectTypes.ts @@ -0,0 +1,64 @@ +import { ProjectTypesStatic } from "../interfaces/ProjectTypesStatic"; +import BaseCrud from "./BaseCrud"; +import OAuth2 from "../libs/OAuth2"; +import Scopes from "../constants/Scopes"; + +export default class ProjectTypes extends BaseCrud< + ProjectTypesStatic.ProjectType, + ProjectTypesStatic.ProjectType, + ProjectTypesStatic.ProjectType, + ProjectTypesStatic.ProjectTypeSearchParameters, + {}, + ProjectTypesStatic.ProjectType +> { + constructor(bexioAuth: OAuth2) { + super(bexioAuth, "/pr_project_type", Scopes.PROJECT_SHOW, Scopes.PROJECT_EDIT); + } + + + /** + * Not implemented by Bexio yet + * + * @param {{}} ressource + * @returns {Promise} + * @memberof ProjectTypes + */ + public async create(ressource: {}): Promise { + throw new Error('not implemented by Bexio yet') + } + + /** + * Not implemented by Bexio yet + * + * @param {number} id + * @param {{}} ressource + * @returns {Promise} + * @memberof ProjectTypes + */ + public async edit(id: number, ressource: {}): Promise { + throw new Error('not implemented by Bexio yet') + } + + /** + * Not implemented by Bexio yet + * + * @param {number} id + * @param {{}} ressource + * @returns {Promise} + * @memberof ProjectTypes + */ + public async overwrite(id: number, ressource: {}): Promise { + throw new Error('not implemented by Bexio yet') + } + + /** + * Not implemented by Bexio yet + * + * @param {number} id + * @returns {Promise} + * @memberof ProjectTypes + */ + public async delete(id: number): Promise { + throw new Error('not implemented by Bexio yet') + } +} diff --git a/src/tests/ProjectStatuses.test.ts b/src/tests/ProjectStatuses.test.ts new file mode 100644 index 0000000..dd6f3e5 --- /dev/null +++ b/src/tests/ProjectStatuses.test.ts @@ -0,0 +1,139 @@ +import Bexio, { Scopes } from ".."; +import { expect } from "chai"; +import dotenv from "dotenv"; +import { ProjectStatusesStatic } from "../interfaces/ProjectStatusesStatic"; +import ProjectStatuses from "../resources/ProjectStatuses"; + +dotenv.config(); + +describe("ProjectStatuses", function() { + // increasing timeout to 60s + this.timeout(60000); + + let api: Bexio; + let moduleToTest: ProjectStatuses; + let projectStatusEntry: ProjectStatusesStatic.ProjectStatus; + const { + BEXIO_CLIENTID, + BEXIO_CLIENTSECRET, + HOSTNAME, + BEXIO_USERNAME, + BEXIO_PASSWORD + } = process.env; + + before(async () => { + if ( + !BEXIO_CLIENTID || + !BEXIO_CLIENTSECRET || + !HOSTNAME || + !BEXIO_USERNAME || + !BEXIO_PASSWORD + ) + throw new Error("not all necessary variables defined"); + + api = new Bexio( + BEXIO_CLIENTID, + BEXIO_CLIENTSECRET, + `http://${HOSTNAME}/callback`, + [Scopes.PROJECT_EDIT, Scopes.PROJECT_SHOW] + ); + await api.fakeLogin(BEXIO_USERNAME, BEXIO_PASSWORD); + }); + + it("init project", () => { + moduleToTest = new ProjectStatuses(api["bexioAuth"]); + }); + + it.skip("create new project status (not implemented by Bexio yet)", async () => { + projectStatusEntry = await moduleToTest.create({ + name: "test" + }); + }); + + it("should return a not implemented error on creation", async () => { + projectStatusEntry = { + id: 1, + name: "Offen" + }; + try { + await moduleToTest.create({ + name: "test" + }); + } catch (err) { + expect(err.message).to.be.eq("not implemented by Bexio yet"); + } + }); + + it("list project statuses", async () => { + const list = await moduleToTest.list({}); + expect(list.map(el => el.id)).includes(projectStatusEntry.id); + }); + + // search is currently broken on bexio side + it.skip("search project statuses", async () => { + const searchResult = await moduleToTest.search({}, [ + { + field: ProjectStatusesStatic.ProjectStatusSearchParameters.text, + value: projectStatusEntry.name, + criteria: "=" + } + ]); + expect(searchResult.length).to.be.greaterThan(0); + expect(searchResult[0].id).to.be.eq(projectStatusEntry.id); + }); + + it("show project statuses", async () => { + const showedEntry = await moduleToTest.show({}, projectStatusEntry.id); + expect(showedEntry.name).to.be.eq(projectStatusEntry.name); + }); + + it.skip("overwrite a project status (not implemented by Bexio yet)", async () => { + const overwritten = await moduleToTest.overwrite( + projectStatusEntry.id, + { + name: "test" + } + ); + expect(overwritten.name).to.be.eq("test"); + }); + + it("should return a not implemented error on overwrite", async () => { + try { + await moduleToTest.overwrite(projectStatusEntry.id, { + name: "test" + }); + } catch (err) { + expect(err.message).to.be.eq("not implemented by Bexio yet"); + } + }); + + it.skip("edit project status (not implemented by Bexio yet)", async () => { + const edited = await moduleToTest.edit(projectStatusEntry.id, { + name: "test" + }); + expect(edited.name).to.be.eq("test"); + }); + + it("should return a not implemented error on edit", async () => { + try { + await moduleToTest.edit(projectStatusEntry.id, { + name: "test" + }); + } catch (err) { + expect(err.message).to.be.eq("not implemented by Bexio yet"); + } + }); + + it.skip("delete project status (not implemented by Bexio yet)", async () => { + const result = await moduleToTest.delete(projectStatusEntry.id); + expect(result).to.be.true; + }); + + it("should return a not implemented error on deletion", async () => { + try { + await moduleToTest.delete(projectStatusEntry.id); + } catch (err) { + expect(err.message).to.be.eq("not implemented by Bexio yet"); + } + }); +}); diff --git a/src/tests/ProjectTypes.test.ts b/src/tests/ProjectTypes.test.ts new file mode 100644 index 0000000..8941dea --- /dev/null +++ b/src/tests/ProjectTypes.test.ts @@ -0,0 +1,131 @@ +import Bexio, { Scopes } from ".."; +import { expect } from "chai"; +import ProjectTypes from "../resources/ProjectTypes"; +import { ProjectTypesStatic } from "../interfaces/ProjectTypesStatic"; +import dotenv from "dotenv"; + +dotenv.config(); + +describe("ProjectTypes", function() { + // increasing timeout to 60s + this.timeout(60000); + + let api: Bexio; + let moduleToTest: ProjectTypes; + let projectType: ProjectTypesStatic.ProjectType = { id: 1, name: "Client work" }; + const { + BEXIO_CLIENTID, + BEXIO_CLIENTSECRET, + HOSTNAME, + BEXIO_USERNAME, + BEXIO_PASSWORD + } = process.env; + + before(async () => { + if ( + !BEXIO_CLIENTID || + !BEXIO_CLIENTSECRET || + !HOSTNAME || + !BEXIO_USERNAME || + !BEXIO_PASSWORD + ) + throw new Error("not all necessary variables defined"); + + api = new Bexio( + BEXIO_CLIENTID, + BEXIO_CLIENTSECRET, + `http://${HOSTNAME}/callback`, + [Scopes.PROJECT_SHOW, Scopes.PROJECT_EDIT] + ); + await api.fakeLogin(BEXIO_USERNAME, BEXIO_PASSWORD); + }); + + it("init ProjectTypes object", () => { + moduleToTest = new ProjectTypes(api["bexioAuth"]); + }); + + it.skip("create new project type (not implemented by Bexio yet)", async () => { + projectType = await moduleToTest.create({ name: `type-${Date.now()}` }); + expect(projectType.name).include("type-"); + }); + + it("should return a not implemented error on creation", async () => { + try { + projectType = await moduleToTest.create({ name: `type-${Date.now()}` }); + } catch (err) { + expect(err.message).to.be.eq("not implemented by Bexio yet"); + } + }); + + it("list project types", async () => { + const list = await moduleToTest.list({}); + expect(list.map(el => el.id)).includes(projectType.id); + }); + + it("search project type", async () => { + const searchResult = await moduleToTest.search({}, [ + { + field: ProjectTypesStatic.ProjectTypeSearchParameters.project_type, + value: projectType.name, + criteria: "=" + } + ]); + expect(searchResult.length).to.be.eq(1); + expect(searchResult[0].id).to.be.eq(projectType.id); + }); + + it("show project type", async () => { + const show = await moduleToTest.show({}, projectType.id); + expect(show.id).to.be.eq(projectType.id); + expect(show.name).to.be.eq(projectType.name); + }); + + it.skip("overwrite project type (not implemented by Bexio yet)", async () => { + const overwritten = await moduleToTest.overwrite(projectType.id, { + name: `overwritten-${Date.now()}`, + id: 1 + }); + expect(overwritten.name).include("overwritten"); + }); + + it("should return a not implemented error on overwrite", async () => { + try { + const overwritten = await moduleToTest.overwrite(projectType.id, { + name: `overwritten-${Date.now()}`, + id: 1 + }); + } catch (err) { + expect(err.message).to.be.eq("not implemented by Bexio yet"); + } + }); + + it.skip("edit project type (not implemented by Bexio yet)", async () => { + const edited = await moduleToTest.edit(projectType.id, { + name: `edited-${Date.now()}` + }); + expect(edited.name).include("edited-"); + }); + + it("should return a not implemented error on edit", async () => { + try { + const edited = await moduleToTest.edit(projectType.id, { + name: `edited-${Date.now()}` + }); + } catch (err) { + expect(err.message).to.be.eq("not implemented by Bexio yet"); + } + }); + + it.skip("delete project type (not implemented by Bexio yet)", async () => { + const result = await moduleToTest.delete(projectType.id); + expect(result).to.be.true; + }); + + it("should return a not implemented error on delete", async () => { + try { + const result = await moduleToTest.delete(projectType.id); + } catch (err) { + expect(err.message).to.be.eq("not implemented by Bexio yet"); + } + }); +}); diff --git a/src/tests/Projects.test.ts b/src/tests/Projects.test.ts index 0688dc4..20eb656 100644 --- a/src/tests/Projects.test.ts +++ b/src/tests/Projects.test.ts @@ -64,8 +64,8 @@ describe("Projects", function() { it("search project", async () => { const searchResult = await moduleToTest.search({}, [ { - field: ProjectsStatic.ProjectSearchParameters.id, - value: project.id, + field: ProjectsStatic.ProjectSearchParameters.name, + value: project.name, criteria: "=" } ]); From f9179b0b5b50422c5adbe183c43a901505d5c52f Mon Sep 17 00:00:00 2001 From: Victor Felder Date: Sun, 13 Oct 2019 16:26:19 +0200 Subject: [PATCH 3/6] adds business activities --- src/index.ts | 6 ++ src/interfaces/BusinessActivitiesStatic.ts | 27 ++++++ src/resources/BusinessActivities.ts | 17 ++++ src/tests/BusinessActivities.test.ts | 99 ++++++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 src/interfaces/BusinessActivitiesStatic.ts create mode 100644 src/resources/BusinessActivities.ts create mode 100644 src/tests/BusinessActivities.test.ts diff --git a/src/index.ts b/src/index.ts index 4630193..5ab1065 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import Scopes from "./constants/Scopes"; import OAuth2, { AuthorizationResponse } from "./libs/OAuth2"; +import BusinessActivities from "./resources/BusinessActivities"; import Contacts from "./resources/Contacts"; import ContactTypes from "./resources/ContactTypes"; import ContactSectors from "./resources/ContactSectors"; @@ -18,6 +19,7 @@ import TimetrackingStatuses from "./resources/TimetrackingStatuses"; export * from "./interfaces/BillsStatic"; export * from "./interfaces/CalendarStatic"; +export * from "./interfaces/BusinessActivitiesStatic"; export * from "./interfaces/ContactGroupsStatic"; export * from "./interfaces/ContactRelationsStatic"; export * from "./interfaces/ContactSectorsStatic"; @@ -43,6 +45,9 @@ export default class Bexio { private bexioAuth: OAuth2; // Resources + // Client Services + public businessActivities: BusinessActivities; + // Contacts public contacts: Contacts; public contactTypes: ContactTypes; @@ -86,6 +91,7 @@ export default class Bexio { ); // Init resources + this.businessActivities = new BusinessActivities(this.bexioAuth); this.contacts = new Contacts(this.bexioAuth); this.contactTypes = new ContactTypes(this.bexioAuth); this.contactSectors = new ContactSectors(this.bexioAuth); diff --git a/src/interfaces/BusinessActivitiesStatic.ts b/src/interfaces/BusinessActivitiesStatic.ts new file mode 100644 index 0000000..c948ded --- /dev/null +++ b/src/interfaces/BusinessActivitiesStatic.ts @@ -0,0 +1,27 @@ +export namespace BusinessActivitiesStatic { + export interface BusinessActivity { + id: number; + name: string; + default_is_billable?: boolean; + default_price_per_hour?: string; + account_id?: number; + } + + export interface BusinessActivityCreate { + name: string; + default_is_billable?: boolean; + default_price_per_hour?: string; + account_id?: number; + } + + export interface BusinessActivityOverwrite { + name: string; + default_is_billable?: boolean; + default_price_per_hour?: string; + account_id?: number; + } + + export enum BusinessActivitySearchParameters { + name = "name", + } +} diff --git a/src/resources/BusinessActivities.ts b/src/resources/BusinessActivities.ts new file mode 100644 index 0000000..ebf7c4d --- /dev/null +++ b/src/resources/BusinessActivities.ts @@ -0,0 +1,17 @@ +import { BusinessActivitiesStatic } from "../interfaces/BusinessActivitiesStatic"; +import BaseCrud from "./BaseCrud"; +import OAuth2 from "../libs/OAuth2"; +import Scopes from "../constants/Scopes"; + +export default class ClientServices extends BaseCrud< + BusinessActivitiesStatic.BusinessActivity, + BusinessActivitiesStatic.BusinessActivity, + BusinessActivitiesStatic.BusinessActivity, + BusinessActivitiesStatic.BusinessActivitySearchParameters, + BusinessActivitiesStatic.BusinessActivityCreate, + BusinessActivitiesStatic.BusinessActivityOverwrite +> { + constructor(bexioAuth: OAuth2) { + super(bexioAuth, "/client_service", Scopes.GENERAL, Scopes.GENERAL); + } +} diff --git a/src/tests/BusinessActivities.test.ts b/src/tests/BusinessActivities.test.ts new file mode 100644 index 0000000..5fec412 --- /dev/null +++ b/src/tests/BusinessActivities.test.ts @@ -0,0 +1,99 @@ +import Bexio, { Scopes } from ".."; +import { expect } from "chai"; +import BusinessActivities from "../resources/BusinessActivities"; +import { BusinessActivitiesStatic } from "../interfaces/BusinessActivitiesStatic"; +import dotenv from "dotenv"; + +dotenv.config(); + +describe("BusinessActivities", function() { + // increasing timeout to 60s + this.timeout(60000); + + let api: Bexio; + let moduleToTest: BusinessActivities; + let businessActivities: BusinessActivitiesStatic.BusinessActivity; + const { + BEXIO_CLIENTID, + BEXIO_CLIENTSECRET, + HOSTNAME, + BEXIO_USERNAME, + BEXIO_PASSWORD + } = process.env; + + before(async () => { + if ( + !BEXIO_CLIENTID || + !BEXIO_CLIENTSECRET || + !HOSTNAME || + !BEXIO_USERNAME || + !BEXIO_PASSWORD + ) + throw new Error("not all necessary variables defined"); + + api = new Bexio( + BEXIO_CLIENTID, + BEXIO_CLIENTSECRET, + `http://${HOSTNAME}/callback`, + [Scopes.PROJECT_SHOW, Scopes.PROJECT_EDIT] + ); + await api.fakeLogin(BEXIO_USERNAME, BEXIO_PASSWORD); + }); + + it("init BusinessActivities object", () => { + moduleToTest = new BusinessActivities(api["bexioAuth"]); + }); + + it("create new business activity", async () => { + const name = `test-${Date.now()}`; + businessActivities = await moduleToTest.create({ + name: name, + account_id: 1, + default_is_billable: false, + default_price_per_hour: "10.50" + }); + expect(businessActivities.name).to.be.eq(name); + }); + + it("list business activities", async () => { + const list = await moduleToTest.list({}); + expect(list.map(el => el.id)).includes(businessActivities.id); + }); + + it("search business activity", async () => { + const searchResult = await moduleToTest.search({}, [ + { + field: BusinessActivitiesStatic.BusinessActivitySearchParameters.name, + value: businessActivities.name, + criteria: "=" + } + ]); + expect(searchResult.length).to.be.eq(1); + expect(searchResult[0].id).to.be.eq(businessActivities.id); + expect(searchResult[0].name).to.be.eq(businessActivities.name); + }); + + it("show business activity", async () => { + const show = await moduleToTest.show({}, businessActivities.id); + expect(show.id).to.be.eq(businessActivities.id); + }); + + it("overwrite business activity", async () => { + const overwritten = await moduleToTest.overwrite(businessActivities.id, { + name: `overwritten-${Date.now()}` + }); + expect(overwritten.name).include("overwritten-"); + }); + + it("edit business activity", async () => { + const edited = await moduleToTest.edit(businessActivities.id, { + name: `edited-${Date.now()}` + }); + expect(edited.name).include("edited-"); + }); + + it("delete business activity", async () => { + const result = await moduleToTest.delete(businessActivities.id); + expect(result).to.be.true; + }); +}); From e4fc2ce899b5771d90f11e0ed3ec587fbf84eae1 Mon Sep 17 00:00:00 2001 From: Victor Felder Date: Sun, 13 Oct 2019 16:35:01 +0200 Subject: [PATCH 4/6] project types: fix tests --- src/tests/ProjectTypes.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/ProjectTypes.test.ts b/src/tests/ProjectTypes.test.ts index 8941dea..cf7b290 100644 --- a/src/tests/ProjectTypes.test.ts +++ b/src/tests/ProjectTypes.test.ts @@ -12,7 +12,7 @@ describe("ProjectTypes", function() { let api: Bexio; let moduleToTest: ProjectTypes; - let projectType: ProjectTypesStatic.ProjectType = { id: 1, name: "Client work" }; + let projectType: ProjectTypesStatic.ProjectType = { id: 1, name: "Internes Projekt" }; const { BEXIO_CLIENTID, BEXIO_CLIENTSECRET, From 669d97fb46d3362b1ed9da74368472169b6af08b Mon Sep 17 00:00:00 2001 From: Victor Felder Date: Sun, 13 Oct 2019 16:36:45 +0200 Subject: [PATCH 5/6] business activities: fix tests --- src/tests/BusinessActivities.test.ts | 3 +-- src/tests/ProjectTypes.test.ts | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/BusinessActivities.test.ts b/src/tests/BusinessActivities.test.ts index 5fec412..9dee01b 100644 --- a/src/tests/BusinessActivities.test.ts +++ b/src/tests/BusinessActivities.test.ts @@ -35,7 +35,7 @@ describe("BusinessActivities", function() { BEXIO_CLIENTID, BEXIO_CLIENTSECRET, `http://${HOSTNAME}/callback`, - [Scopes.PROJECT_SHOW, Scopes.PROJECT_EDIT] + [Scopes.GENERAL, Scopes.GENERAL] ); await api.fakeLogin(BEXIO_USERNAME, BEXIO_PASSWORD); }); @@ -48,7 +48,6 @@ describe("BusinessActivities", function() { const name = `test-${Date.now()}`; businessActivities = await moduleToTest.create({ name: name, - account_id: 1, default_is_billable: false, default_price_per_hour: "10.50" }); diff --git a/src/tests/ProjectTypes.test.ts b/src/tests/ProjectTypes.test.ts index cf7b290..859d6c1 100644 --- a/src/tests/ProjectTypes.test.ts +++ b/src/tests/ProjectTypes.test.ts @@ -62,7 +62,8 @@ describe("ProjectTypes", function() { expect(list.map(el => el.id)).includes(projectType.id); }); - it("search project type", async () => { + // search is currently broken on bexio side + it.skip("search project type", async () => { const searchResult = await moduleToTest.search({}, [ { field: ProjectTypesStatic.ProjectTypeSearchParameters.project_type, From ea5c20e4d6ad89475d4cd69d57bfeca72acc640f Mon Sep 17 00:00:00 2001 From: Victor Felder Date: Sun, 13 Oct 2019 16:54:08 +0200 Subject: [PATCH 6/6] fix comments --- src/index.ts | 4 ++-- src/resources/ProjectTypes.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index 5ab1065..ee816f2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,8 +18,8 @@ import Timetrackings from "./resources/Timetrackings"; import TimetrackingStatuses from "./resources/TimetrackingStatuses"; export * from "./interfaces/BillsStatic"; -export * from "./interfaces/CalendarStatic"; export * from "./interfaces/BusinessActivitiesStatic"; +export * from "./interfaces/CalendarStatic"; export * from "./interfaces/ContactGroupsStatic"; export * from "./interfaces/ContactRelationsStatic"; export * from "./interfaces/ContactSectorsStatic"; @@ -45,7 +45,7 @@ export default class Bexio { private bexioAuth: OAuth2; // Resources - // Client Services + // Business Activities public businessActivities: BusinessActivities; // Contacts diff --git a/src/resources/ProjectTypes.ts b/src/resources/ProjectTypes.ts index 4a76f7d..f2fb5bd 100644 --- a/src/resources/ProjectTypes.ts +++ b/src/resources/ProjectTypes.ts @@ -20,7 +20,7 @@ export default class ProjectTypes extends BaseCrud< * Not implemented by Bexio yet * * @param {{}} ressource - * @returns {Promise} + * @returns {Promise} * @memberof ProjectTypes */ public async create(ressource: {}): Promise { @@ -32,7 +32,7 @@ export default class ProjectTypes extends BaseCrud< * * @param {number} id * @param {{}} ressource - * @returns {Promise} + * @returns {Promise} * @memberof ProjectTypes */ public async edit(id: number, ressource: {}): Promise { @@ -44,7 +44,7 @@ export default class ProjectTypes extends BaseCrud< * * @param {number} id * @param {{}} ressource - * @returns {Promise} + * @returns {Promise} * @memberof ProjectTypes */ public async overwrite(id: number, ressource: {}): Promise {