From bb95b53bad0a162defb19a65bbea35c90e73b897 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 5 Jun 2024 09:56:39 -0400 Subject: [PATCH] New Components - upbooks (#12078) * upbooks init * [Components] upbooks #12071 Sources - New Data Actions - Add Outward Payment - Create Expense Category - Add Employee * pnpm update * Fix prop description * some adjusts --------- Co-authored-by: Lucas Caresia Co-authored-by: Leo Vu <18277920+vunguyenhung@users.noreply.github.com> --- .../actions/add-employee/add-employee.mjs | 120 +++++++++++++ .../create-expense-category.mjs | 55 ++++++ .../record-outward-payment.mjs | 88 ++++++++++ components/upbooks/common/constants.mjs | 22 +++ components/upbooks/common/utils.mjs | 24 +++ components/upbooks/package.json | 8 +- .../upbooks/sources/new-data/new-data.mjs | 61 +++++++ .../upbooks/sources/new-data/test-event.mjs | 31 ++++ components/upbooks/upbooks.app.mjs | 158 +++++++++++++++++- pnpm-lock.yaml | 5 +- 10 files changed, 565 insertions(+), 7 deletions(-) create mode 100644 components/upbooks/actions/add-employee/add-employee.mjs create mode 100644 components/upbooks/actions/create-expense-category/create-expense-category.mjs create mode 100644 components/upbooks/actions/record-outward-payment/record-outward-payment.mjs create mode 100644 components/upbooks/common/constants.mjs create mode 100644 components/upbooks/common/utils.mjs create mode 100644 components/upbooks/sources/new-data/new-data.mjs create mode 100644 components/upbooks/sources/new-data/test-event.mjs diff --git a/components/upbooks/actions/add-employee/add-employee.mjs b/components/upbooks/actions/add-employee/add-employee.mjs new file mode 100644 index 0000000000000..3d7e99fd1006b --- /dev/null +++ b/components/upbooks/actions/add-employee/add-employee.mjs @@ -0,0 +1,120 @@ +import upbooks from "../../upbooks.app.mjs"; + +export default { + key: "upbooks-add-employee", + name: "Add New Employee", + description: "Adds a new employee to Upbooks. [See the documentation](https://www.postman.com/scrrum/workspace/upbooks-io/request/13284127-a51a907a-0648-477d-96f6-f5a9e79262fd)", + version: "0.0.1", + type: "action", + props: { + upbooks, + name: { + type: "string", + label: "Name", + description: "Full name of the employee.", + }, + employeeNumber: { + type: "string", + label: "Employee Number", + description: "The identification number of the employee.", + optional: true, + }, + type: { + type: "string", + label: "Type", + description: "The employee's type.", + options: [ + "full-time", + "part-time", + ], + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "The employee's email.", + optional: true, + }, + phone: { + type: "string", + label: "Phone", + description: "The employee's phone.", + optional: true, + }, + dob: { + type: "string", + label: "DOB", + description: "The employee's date of birth. Format: YYYY-MM-DD", + optional: true, + }, + dateOfJoining: { + type: "string", + label: "Date Of Joining", + description: "The employee's start date. Format: YYYY-MM-DDTHH:MM:SSZ", + optional: true, + }, + dateOfLeaving: { + type: "string", + label: "Date Of Leaving", + description: "The employee's end date. Format: YYYY-MM-DDTHH:MM:SSZ", + optional: true, + }, + ctc: { + type: "integer", + label: "CTC", + description: "Cost to company in cents.", + }, + salaryComponentId: { + propDefinition: [ + upbooks, + "salaryComponentId", + ], + }, + designation: { + type: "string", + label: "Designation", + description: "In which position the employee will work.", + optional: true, + }, + role: { + type: "string", + label: "Role", + description: "The identification of the employee's role.", + options: [ + "staff", + "admin", + "others", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.upbooks.addNewEmployee({ + $, + data: { + name: this.name, + employeeNumber: this.employeeNumber, + type: this.type, + email: this.email, + phone: this.phone, + dob: this.dob, + employment: [ + { + dateOfJoining: this.dateOfJoining, + dateOfLeaving: this.dateOfLeaving, + salary: { + ctc: (this.ctc / 100).toFixed(2), + componentGroup: { + id: this.salaryComponentId, + }, + }, + designation: this.designation, + role: this.role, + }, + ], + }, + }); + $.export("$summary", `Successfully added a new employee with Id: ${response.data._id}`); + return response; + }, +}; diff --git a/components/upbooks/actions/create-expense-category/create-expense-category.mjs b/components/upbooks/actions/create-expense-category/create-expense-category.mjs new file mode 100644 index 0000000000000..7b2234c62cd20 --- /dev/null +++ b/components/upbooks/actions/create-expense-category/create-expense-category.mjs @@ -0,0 +1,55 @@ +import upbooks from "../../upbooks.app.mjs"; + +export default { + key: "upbooks-create-expense-category", + name: "Create Expense Category", + description: "Creates a new expense category in UpBooks. [See the documentation](https://www.postman.com/scrrum/workspace/upbooks-io/request/13284127-a07ae2fc-f712-42aa-bcf5-6ce63c7a0929)", + version: "0.0.1", + type: "action", + props: { + upbooks, + title: { + type: "string", + label: "Title", + description: "The expense category's title.", + }, + subCategory: { + type: "string", + label: "Sub Category", + description: "subCategory", + options: [ + { + label: "Operating Expense", + value: "operating-expense", + }, + { + label: "Non Operating Expense", + value: "non-operating-expense", + }, + { + label: "Cost Of Goods Sold", + value: "cost-of-goods-sold", + }, + ], + }, + summary: { + type: "string", + label: "Summary", + description: "summary", + optional: true, + }, + }, + async run({ $ }) { + const { + upbooks, + ...data + } = this; + + const response = await upbooks.createExpenseCategory({ + $, + data, + }); + $.export("$summary", `Successfully created new expense category with Id: ${response.data._id}`); + return response; + }, +}; diff --git a/components/upbooks/actions/record-outward-payment/record-outward-payment.mjs b/components/upbooks/actions/record-outward-payment/record-outward-payment.mjs new file mode 100644 index 0000000000000..0ce4e31764532 --- /dev/null +++ b/components/upbooks/actions/record-outward-payment/record-outward-payment.mjs @@ -0,0 +1,88 @@ +import { CURRENCY_OPTIONS } from "../../common/constants.mjs"; +import { parseObject } from "../../common/utils.mjs"; +import upbooks from "../../upbooks.app.mjs"; + +export default { + key: "upbooks-record-outward-payment", + name: "Record Outward Payment", + description: "Records an outward payment in UpBooks. [See the documentation](https://www.postman.com/scrrum/workspace/upbooks-io/request/13284127-3fc82d7a-2173-4b3a-a8ec-4c812c928810)", + version: "0.0.1", + type: "action", + props: { + upbooks, + mode: { + type: "string", + label: "Mode", + description: "The outward payment mode.", + options: [ + { + label: "Cash", + value: "cash", + }, + { + label: "Cheque", + value: "cheque", + }, + { + label: "Neft", + value: "neft", + }, + { + label: "Imps", + value: "imps", + }, + { + label: "Wire Transfer", + value: "wire transfer", + }, + ], + }, + amount: { + type: "string", + label: "Amount", + description: "The outwart payment amount in cents.", + }, + date: { + type: "string", + label: "Date", + description: "The date of the outward payment. Format: YYYY-MM-DD", + }, + expenseIds: { + propDefinition: [ + upbooks, + "expenseIds", + ], + }, + account: { + propDefinition: [ + upbooks, + "accountId", + ], + }, + currency: { + type: "string", + label: "Currency", + description: "The currency of the outward payment.", + options: CURRENCY_OPTIONS, + }, + }, + async run({ $ }) { + const currency = CURRENCY_OPTIONS.filter((item) => item.value === this.currency)[0]; + const response = await this.upbooks.recordOutwardPayment({ + $, + data: { + mode: this.mode, + amount: (this.amount / 100).toFixed(2), + date: this.date, + expenseIds: parseObject(this.expenseIds), + accountId: this.account, + currency: { + name: currency.label, + symbol: currency.value, + }, + }, + }); + $.export("$summary", `Successfully recorded outward payment with Id: ${response.data._id}`); + return response; + }, +}; diff --git a/components/upbooks/common/constants.mjs b/components/upbooks/common/constants.mjs new file mode 100644 index 0000000000000..46fd49769bbcd --- /dev/null +++ b/components/upbooks/common/constants.mjs @@ -0,0 +1,22 @@ +export const CURRENCY_OPTIONS = [ + { + label: "Indian Rupees", + value: "INR", + }, + { + label: "US Dollar", + value: "USD", + }, + { + label: "Euro", + value: "EUR", + }, + { + label: "Australian Dollar", + value: "AUD", + }, + { + label: "Emirati Dirham", + value: "AED", + }, +]; diff --git a/components/upbooks/common/utils.mjs b/components/upbooks/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/upbooks/common/utils.mjs @@ -0,0 +1,24 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; diff --git a/components/upbooks/package.json b/components/upbooks/package.json index 13a832d4e6cc7..88d23e10777c5 100644 --- a/components/upbooks/package.json +++ b/components/upbooks/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/upbooks", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream UpBooks Components", "main": "upbooks.app.mjs", "keywords": [ @@ -11,5 +11,9 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^1.6.5" } -} \ No newline at end of file +} + diff --git a/components/upbooks/sources/new-data/new-data.mjs b/components/upbooks/sources/new-data/new-data.mjs new file mode 100644 index 0000000000000..9a8c97dbf48ed --- /dev/null +++ b/components/upbooks/sources/new-data/new-data.mjs @@ -0,0 +1,61 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import upbooks from "../../upbooks.app.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + key: "upbooks-new-data", + name: "New Data Available", + description: "Emit new event when fresh data is available for a specific collection.", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + upbooks, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastDate() { + return this.db.get("lastDate") || "1970-01-01T00:00:00Z"; + }, + _setLastDate(created) { + this.db.set("lastDate", created); + }, + generateMeta(item) { + return { + id: item._id, + summary: `New ${item.title}`, + ts: item.occurredAt, + }; + }, + async startEvent(maxResults = 0) { + const lastDate = this._getLastDate(); + const { data } = await this.upbooks.listActivities({ + params: { + fromDate: lastDate, + }, + }); + + if (maxResults && maxResults.length > maxResults) maxResults.length = maxResults; + if (data.length) this._setLastDate(data[0].occurredAt); + + for (const item of data.reverse()) { + this.$emit(item, this.generateMeta(item)); + } + }, + }, + hooks: { + async deploy() { + await this.startEvent(25); + }, + }, + async run() { + await this.startEvent(); + }, + sampleEmit, +}; diff --git a/components/upbooks/sources/new-data/test-event.mjs b/components/upbooks/sources/new-data/test-event.mjs new file mode 100644 index 0000000000000..d0ab64f2805c9 --- /dev/null +++ b/components/upbooks/sources/new-data/test-event.mjs @@ -0,0 +1,31 @@ +export default { + "_id":"0d6f5e4038f7eb902bfa651b", + "user":{ + "_id":"0d6f5e4038f7eb902bfa651b", + "id":"0d6f5e4038f7eb902bfa651b", + "role":"organization-admin", + "name":"Sergio Wong", + "email":"sergio@pipekit.pro", + "ipAddress":"12.345.678.901", + }, + "organization":{ + "_id":"0d6f5e4038f7eb902bfa651b", + "organizationId":"123456" + }, + "occurredAt":"2024-05-24T21:15:59.347Z", + "eventCode":"EV-1234", + "eventCategory":"Outward-Payment", + "actionType":"Create", + "initiator":"User", + "title":"Outward Payment Recorded", + "body":"User recorded outward payment OP12345 of amount 1.00 USD", + "additional":{ + "link":{ + "text":"0d6f5e4038f7eb902bfa651b", + "url":"outward-payment/view/0d6f5e4038f7eb902bfa651b" + } + }, + "createdAt":"2024-05-24T21:15:59.356Z", + "updatedAt":"2024-05-24T21:15:59.356Z", + "__v":0 +} \ No newline at end of file diff --git a/components/upbooks/upbooks.app.mjs b/components/upbooks/upbooks.app.mjs index effabab86ef72..ad657f1048feb 100644 --- a/components/upbooks/upbooks.app.mjs +++ b/components/upbooks/upbooks.app.mjs @@ -1,11 +1,161 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "upbooks", - propDefinitions: {}, + propDefinitions: { + salaryComponentId: { + type: "string", + label: "Salary Component Id", + description: "The identification of the salary component.", + async options({ page }) { + const { data } = await this.listSalaryComponents({ + params: { + page, + }, + }); + + return data.map(({ + _id: value, groupName: label, + }) => ({ + label, + value, + })); + }, + }, + expenseIds: { + type: "string[]", + label: "Expense Ids", + description: "The identification of the expense.", + async options({ page }) { + const { data } = await this.listExpenses({ + params: { + page, + }, + }); + + return data.map(({ + _id: value, title: label, + }) => ({ + label, + value, + })); + }, + }, + accountId: { + type: "string", + label: "Account Id", + description: "The identification of the account.", + async options({ page }) { + const { data } = await this.listAccounts({ + params: { + page, + }, + }); + + return data.map(({ + _id: value, title, category, + }) => ({ + label: `${title} (${category.charAt(0).toUpperCase() + category.slice(1)})`, + value, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.upbooks.io/api/v1"; + }, + _headers() { + return { + "Authorization": `Bearer ${this.$auth.oauth_access_token}`, + "API-KEY": `${this.$auth.api_key}`, + "Organization-ID": `${this.$auth.organization_id}`, + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + return axios($, { + url: this._baseUrl() + path, + headers: this._headers(), + ...opts, + }); + }, + listAccounts(opts = {}) { + return this._makeRequest({ + path: "/account", + ...opts, + }); + }, + listActivities(opts = {}) { + return this._makeRequest({ + path: "/activity-log/all", + ...opts, + }); + }, + listExpenses(opts = {}) { + return this._makeRequest({ + path: "/expense", + ...opts, + }); + }, + listSalaryComponents(opts = {}) { + return this._makeRequest({ + path: "/salary-component", + ...opts, + }); + }, + addNewEmployee(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/employee", + ...opts, + }); + }, + createExpenseCategory(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/expense-category", + ...opts, + }); + }, + recordOutwardPayment(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/outward-payment", + ...opts, + }); + }, + async *paginate({ + fn, params = {}, maxResults = null, ...opts + }) { + let hasMore = false; + let count = 0; + let page = 0; + + do { + params.page = ++page; + const { + data, + meta: { + current_page, last_page, + }, + } = await fn({ + params, + ...opts, + }); + for (const d of data) { + yield d; + + if (maxResults && ++count === maxResults) { + return count; + } + } + + hasMore = !(current_page == last_page); + + } while (hasMore); }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b095c1bbb562a..9e88c98eebf77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9272,7 +9272,10 @@ importers: '@pipedream/platform': 1.6.5 components/upbooks: - specifiers: {} + specifiers: + '@pipedream/platform': ^1.6.5 + dependencies: + '@pipedream/platform': 1.6.5 components/updown_io: specifiers: