From a56f9a389451aa2890db10686682a8109e6505be Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 16 Oct 2024 16:52:45 -0300 Subject: [PATCH 1/3] teach_n_go init --- .../create-prospect/create-prospect.mjs | 26 +++ .../actions/create-student/create-student.mjs | 34 ++++ .../invoice-mark-paid/invoice-mark-paid.mjs | 34 ++++ components/teach_n_go/package.json | 2 +- .../sources/new-class/new-class.mjs | 94 +++++++++++ .../sources/new-payment/new-payment.mjs | 109 ++++++++++++ .../sources/new-student/new-student.mjs | 93 +++++++++++ components/teach_n_go/teach_n_go.app.mjs | 157 +++++++++++++++++- 8 files changed, 545 insertions(+), 4 deletions(-) create mode 100644 components/teach_n_go/actions/create-prospect/create-prospect.mjs create mode 100644 components/teach_n_go/actions/create-student/create-student.mjs create mode 100644 components/teach_n_go/actions/invoice-mark-paid/invoice-mark-paid.mjs create mode 100644 components/teach_n_go/sources/new-class/new-class.mjs create mode 100644 components/teach_n_go/sources/new-payment/new-payment.mjs create mode 100644 components/teach_n_go/sources/new-student/new-student.mjs diff --git a/components/teach_n_go/actions/create-prospect/create-prospect.mjs b/components/teach_n_go/actions/create-prospect/create-prospect.mjs new file mode 100644 index 0000000000000..b431a3114e3dc --- /dev/null +++ b/components/teach_n_go/actions/create-prospect/create-prospect.mjs @@ -0,0 +1,26 @@ +import teachNGo from "../../teach_n_go.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "teach_n_go-create-prospect", + name: "Create Prospect", + description: "Creates a new prospect inside Teach 'n Go. [See the documentation](https://intercom.help/teach-n-go/en/articles/5750592-prospect-registration-api)", + version: "0.0.{{ts}}", + type: "action", + props: { + teachNGo, + prospectDetails: { + propDefinition: [ + teachNGo, + "prospectDetails", + ], + }, + }, + async run({ $ }) { + const response = await this.teachNGo.createProspect({ + prospectDetails: this.prospectDetails, + }); + $.export("$summary", `Successfully created prospect with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/teach_n_go/actions/create-student/create-student.mjs b/components/teach_n_go/actions/create-student/create-student.mjs new file mode 100644 index 0000000000000..3d619d3d57c11 --- /dev/null +++ b/components/teach_n_go/actions/create-student/create-student.mjs @@ -0,0 +1,34 @@ +import teachNGo from "../../teach_n_go.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "teach_n_go-create-student", + name: "Create Student", + description: "Registers a new student in Teach 'n Go. [See the documentation](https://intercom.help/teach-n-go/en/articles/6807235-new-student-and-class-registration-api)", + version: "0.0.{{ts}}", + type: "action", + props: { + teachNGo, + personalDetails: { + propDefinition: [ + teachNGo, + "personalDetails", + ], + }, + academicDetails: { + propDefinition: [ + teachNGo, + "academicDetails", + ], + }, + }, + async run({ $ }) { + const response = await this.teachNGo.registerStudent({ + personalDetails: this.personalDetails, + academicDetails: this.academicDetails, + }); + + $.export("$summary", `Successfully registered student with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/teach_n_go/actions/invoice-mark-paid/invoice-mark-paid.mjs b/components/teach_n_go/actions/invoice-mark-paid/invoice-mark-paid.mjs new file mode 100644 index 0000000000000..365543b2ae07c --- /dev/null +++ b/components/teach_n_go/actions/invoice-mark-paid/invoice-mark-paid.mjs @@ -0,0 +1,34 @@ +import teachNGo from "../../teach_n_go.app.mjs"; + +export default { + key: "teach_n_go-invoice-mark-paid", + name: "Mark Invoice as Paid", + description: "Marks an existing invoice as paid within Teach 'n Go. [See the documentation](https://intercom.help/teach-n-go/en/articles/8727904-api-endpoints)", + version: "0.0.{{ts}}", + type: "action", + props: { + teachNGo, + invoiceId: { + propDefinition: [ + teachNGo, + "invoiceId", + ], + }, + paidDate: { + propDefinition: [ + teachNGo, + "paidDate", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.teachNGo.markInvoiceAsPaid({ + invoiceId: this.invoiceId, + paidDate: this.paidDate, + }); + + $.export("$summary", `Successfully marked invoice ${this.invoiceId} as paid.`); + return response; + }, +}; diff --git a/components/teach_n_go/package.json b/components/teach_n_go/package.json index 5a857d1e0c1c2..e1f4eb5a4d309 100644 --- a/components/teach_n_go/package.json +++ b/components/teach_n_go/package.json @@ -12,4 +12,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/components/teach_n_go/sources/new-class/new-class.mjs b/components/teach_n_go/sources/new-class/new-class.mjs new file mode 100644 index 0000000000000..9136417573bf6 --- /dev/null +++ b/components/teach_n_go/sources/new-class/new-class.mjs @@ -0,0 +1,94 @@ +import { axios } from "@pipedream/platform"; +import teachNGo from "../../teach_n_go.app.mjs"; + +export default { + key: "teach_n_go-new-class", + name: "New Class Created", + description: "Emit a new event when a class is created. [See the documentation](https://intercom.help/teach-n-go/en/articles/8727904-api-endpoints)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + teachNGo, + db: "$.service.db", + courseTitle: { + propDefinition: [ + teachNGo, + "courseTitle", + ], + }, + dateAndTime: { + propDefinition: [ + teachNGo, + "dateAndTime", + ], + }, + classDescription: { + propDefinition: [ + teachNGo, + "classDescription", + ], + optional: true, + }, + teacher: { + propDefinition: [ + teachNGo, + "teacher", + ], + optional: true, + }, + }, + hooks: { + async deploy() { + const classes = await this.fetchClasses(); + for (const classData of classes.slice(-50).reverse()) { + this.$emit(classData, { + id: classData.id, + summary: `New Class: ${classData.title}`, + ts: Date.parse(classData.dateAndTime), + }); + } + }, + async activate() { + // Activation logic if any + }, + async deactivate() { + // Deactivation logic if any + }, + }, + methods: { + async fetchClasses() { + return this.teachNGo._makeRequest({ + path: "/classes", + }); + }, + async emitNewClassEvent() { + const courseTitle = this.courseTitle; + const dateAndTime = this.dateAndTime; + const classDescription = this.classDescription || null; + const teacher = this.teacher || null; + + const classData = { + courseTitle, + dateAndTime, + classDescription, + teacher, + }; + + this.$emit(classData, { + summary: `New Class: ${courseTitle}`, + ts: new Date().getTime(), + }); + }, + }, + async run() { + const classes = await this.fetchClasses(); + for (const classData of classes) { + this.$emit(classData, { + id: classData.id, + summary: `New Class: ${classData.title}`, + ts: Date.parse(classData.dateAndTime), + }); + } + }, +}; diff --git a/components/teach_n_go/sources/new-payment/new-payment.mjs b/components/teach_n_go/sources/new-payment/new-payment.mjs new file mode 100644 index 0000000000000..7a18345e179ca --- /dev/null +++ b/components/teach_n_go/sources/new-payment/new-payment.mjs @@ -0,0 +1,109 @@ +import teachNGo from "../../teach_n_go.app.mjs"; +import { + axios, DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, +} from "@pipedream/platform"; + +export default { + key: "teach_n_go-new-payment", + name: "New Payment Made", + description: "Emit new event when a payment is made. [See the documentation](https://intercom.help/teach-n-go/en/articles/8727904-api-endpoints)", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + teachNGo: { + type: "app", + app: "teach_n_go", + }, + studentName: { + propDefinition: [ + teachNGo, + "studentName", + ], + }, + amount: { + propDefinition: [ + teachNGo, + "amount", + ], + }, + paymentMethod: { + propDefinition: [ + teachNGo, + "paymentMethod", + ], + optional: true, + }, + paymentDate: { + propDefinition: [ + teachNGo, + "paymentDate", + ], + optional: true, + }, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastPaymentTimestamp() { + return this.db.get("lastPaymentTimestamp") || 0; + }, + _setLastPaymentTimestamp(timestamp) { + this.db.set("lastPaymentTimestamp", timestamp); + }, + async _fetchPayments(params) { + return await axios(this, { + method: "GET", + url: `${this.teachNGo._baseUrl()}/path-to-payment-endpoint`, // Replace with actual endpoint + headers: { + "X-API-KEY": this.teachNGo.$auth.api_key, + }, + params, + }); + }, + }, + hooks: { + async deploy() { + const lastPaymentTimestamp = this._getLastPaymentTimestamp(); + const payments = await this._fetchPayments({ + lastPaymentTimestamp, + }); + const recentPayments = payments.slice(0, 50); + + for (const payment of recentPayments) { + this.$emit(payment, { + id: payment.id, + summary: `New Payment: ${payment.studentName}`, + ts: Date.parse(payment.paymentDate) || Date.now(), + }); + } + + if (recentPayments.length) { + this._setLastPaymentTimestamp(Date.parse(recentPayments[0].paymentDate)); + } + }, + }, + async run() { + const lastPaymentTimestamp = this._getLastPaymentTimestamp(); + const payments = await this._fetchPayments({ + lastPaymentTimestamp, + }); + + for (const payment of payments) { + this.$emit(payment, { + id: payment.id, + summary: `New Payment: ${payment.studentName}`, + ts: Date.parse(payment.paymentDate) || Date.now(), + }); + } + + if (payments.length) { + this._setLastPaymentTimestamp(Date.parse(payments[0].paymentDate)); + } + }, +}; diff --git a/components/teach_n_go/sources/new-student/new-student.mjs b/components/teach_n_go/sources/new-student/new-student.mjs new file mode 100644 index 0000000000000..85daaf78e969b --- /dev/null +++ b/components/teach_n_go/sources/new-student/new-student.mjs @@ -0,0 +1,93 @@ +import teachNGo from "../../teach_n_go.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "teach_n_go-new-student", + name: "New Student Registration", + description: "Emit an event when a new student is registered. [See the documentation](https://intercom.help/teach-n-go/en/articles/6807235-new-student-and-class-registration-api)", + version: "0.0.{{ts}}", + type: "source", + dedupe: "unique", + props: { + teachNGo, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: 60, + }, + }, + studentName: { + propDefinition: [ + teachNGo, + "studentName", + ], + }, + dateOfBirth: { + propDefinition: [ + teachNGo, + "dateOfBirth", + ], + }, + contactNumber: { + propDefinition: [ + teachNGo, + "contactNumber", + ], + optional: true, + }, + email: { + propDefinition: [ + teachNGo, + "email", + ], + optional: true, + }, + }, + methods: { + async fetchStudents() { + return this.teachNGo._makeRequest({ + method: "GET", + path: "/student", + }); + }, + emitStudentRegistrationEvent(student) { + const { + id, fname, lname, registration_date: registrationDate, date_of_birth: dateOfBirth, email_address: email, mobile_phone: contactNumber, + } = student; + const summary = `New Student: ${fname} ${lname}`; + this.$emit(student, { + id, + summary, + ts: Date.parse(registrationDate), + }); + }, + _getLastTimestamp() { + return this.db.get("lastTimestamp") ?? 0; + }, + _setLastTimestamp(ts) { + this.db.set("lastTimestamp", ts); + }, + }, + hooks: { + async deploy() { + const students = await this.fetchStudents(); + students.slice(-50).forEach(this.emitStudentRegistrationEvent.bind(this)); + }, + }, + async run() { + const lastTimestamp = this._getLastTimestamp(); + const students = await this.fetchStudents(); + let maxTimestamp = lastTimestamp; + + students.forEach((student) => { + const studentTimestamp = new Date(student.registration_date).getTime(); + if (studentTimestamp > lastTimestamp) { + this.emitStudentRegistrationEvent(student); + maxTimestamp = Math.max(maxTimestamp, studentTimestamp); + } + }); + + this._setLastTimestamp(maxTimestamp); + }, +}; diff --git a/components/teach_n_go/teach_n_go.app.mjs b/components/teach_n_go/teach_n_go.app.mjs index 6da5c7afce2ad..0bb54b2b5a843 100644 --- a/components/teach_n_go/teach_n_go.app.mjs +++ b/components/teach_n_go/teach_n_go.app.mjs @@ -1,11 +1,162 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "teach_n_go", - propDefinitions: {}, + propDefinitions: { + courseTitle: { + type: "string", + label: "Course Title", + description: "The title of the course for the class.", + }, + dateAndTime: { + type: "string", + label: "Date and Time", + description: "The date and time when the class is scheduled.", + }, + classDescription: { + type: "string", + label: "Class Description", + description: "The optional description of the class.", + optional: true, + }, + teacher: { + type: "string", + label: "Teacher", + description: "The optional teacher for the class.", + optional: true, + }, + studentName: { + type: "string", + label: "Student Name", + description: "The name of the student involved.", + }, + amount: { + type: "number", + label: "Amount", + description: "The amount of the payment.", + }, + paymentMethod: { + type: "string", + label: "Payment Method", + description: "The optional payment method used.", + optional: true, + }, + paymentDate: { + type: "string", + label: "Payment Date", + description: "The optional payment date.", + optional: true, + }, + dateOfBirth: { + type: "string", + label: "Date of Birth", + description: "The date of birth of the student.", + }, + contactNumber: { + type: "string", + label: "Contact Number", + description: "The optional contact number of the student.", + optional: true, + }, + email: { + type: "string", + label: "Email", + description: "The optional email of the student.", + optional: true, + }, + prospectDetails: { + type: "object", + label: "Prospect Details", + description: "The details of the new prospect.", + }, + invoiceId: { + type: "string", + label: "Invoice ID", + description: "The ID of the invoice to be marked as paid.", + }, + paidDate: { + type: "string", + label: "Paid Date", + description: "The optional date when the invoice was paid.", + optional: true, + }, + personalDetails: { + type: "object", + label: "Personal Details", + description: "The personal details of the new student.", + }, + academicDetails: { + type: "object", + label: "Academic Details", + description: "The academic details of the new student.", + }, + }, methods: { - // this.$auth contains connected account data authKeys() { console.log(Object.keys(this.$auth)); }, + _baseUrl() { + return "https://app.teachngo.com/api"; + }, + async _makeRequest(opts = {}) { + const { + $ = this, method = "GET", path = "/", headers, ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + method, + url: this._baseUrl() + path, + headers: { + ...headers, + "X-API-KEY": this.$auth.api_key, + }, + }); + }, + async emitNewClassEvent({ + courseTitle, dateAndTime, classDescription, teacher, + }) { + // Logic to emit new class created event based on input parameters + }, + async emitNewPaymentEvent({ + studentName, amount, paymentMethod, paymentDate, + }) { + // Logic to emit new payment made event based on input parameters + }, + async emitNewStudentRegistrationEvent({ + studentName, dateOfBirth, contactNumber, email, + }) { + // Logic to emit new student registration event based on input parameters + }, + async createProspect({ prospectDetails }) { + return this._makeRequest({ + method: "POST", + path: "/prospect", + data: prospectDetails, + }); + }, + async markInvoiceAsPaid({ + invoiceId, paidDate, + }) { + return this._makeRequest({ + method: "POST", + path: `/invoice/${invoiceId}/paid`, + data: { + paid_date: paidDate, + }, + }); + }, + async registerStudent({ + personalDetails, academicDetails, + }) { + return this._makeRequest({ + method: "POST", + path: "/student", + data: { + personalDetails, + academicDetails, + }, + }); + }, }, -}; \ No newline at end of file +}; From 412dc1e344af087b46486f2f4f00ba33446277ae Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Fri, 18 Oct 2024 10:00:14 -0300 Subject: [PATCH 2/3] [Components] teach_n_go #14312 Sources - New Class Created - New Student Registration Actions - Create Prospect - Create Student --- .../create-prospect/create-prospect.mjs | 81 ++++++- .../actions/create-student/create-student.mjs | 188 ++++++++++++++-- .../invoice-mark-paid/invoice-mark-paid.mjs | 34 --- components/teach_n_go/common/constants.mjs | 30 +++ components/teach_n_go/common/utils.mjs | 24 +++ components/teach_n_go/package.json | 5 +- components/teach_n_go/sources/common/base.mjs | 59 +++++ .../sources/new-class/new-class.mjs | 94 +------- .../sources/new-class/test-event.mjs | 46 ++++ .../sources/new-payment/new-payment.mjs | 109 ---------- .../sources/new-student/new-student.mjs | 97 ++------- .../sources/new-student/test-event.mjs | 51 +++++ components/teach_n_go/teach_n_go.app.mjs | 204 +++++++----------- 13 files changed, 567 insertions(+), 455 deletions(-) delete mode 100644 components/teach_n_go/actions/invoice-mark-paid/invoice-mark-paid.mjs create mode 100644 components/teach_n_go/common/constants.mjs create mode 100644 components/teach_n_go/common/utils.mjs create mode 100644 components/teach_n_go/sources/common/base.mjs create mode 100644 components/teach_n_go/sources/new-class/test-event.mjs delete mode 100644 components/teach_n_go/sources/new-payment/new-payment.mjs create mode 100644 components/teach_n_go/sources/new-student/test-event.mjs diff --git a/components/teach_n_go/actions/create-prospect/create-prospect.mjs b/components/teach_n_go/actions/create-prospect/create-prospect.mjs index b431a3114e3dc..0a9a288d76ab4 100644 --- a/components/teach_n_go/actions/create-prospect/create-prospect.mjs +++ b/components/teach_n_go/actions/create-prospect/create-prospect.mjs @@ -1,26 +1,87 @@ -import teachNGo from "../../teach_n_go.app.mjs"; -import { axios } from "@pipedream/platform"; +import app from "../../teach_n_go.app.mjs"; export default { key: "teach_n_go-create-prospect", name: "Create Prospect", description: "Creates a new prospect inside Teach 'n Go. [See the documentation](https://intercom.help/teach-n-go/en/articles/5750592-prospect-registration-api)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { - teachNGo, - prospectDetails: { + app, + firstName: { propDefinition: [ - teachNGo, - "prospectDetails", + app, + "firstName", ], }, + lastName: { + propDefinition: [ + app, + "lastName", + ], + }, + mobilePhone: { + type: "integer", + label: "Mobile Phone", + description: "The prospect's contact number.", + optional: true, + }, + emailAddress: { + propDefinition: [ + app, + "emailAddress", + ], + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "General information you wish to capture.", + optional: true, + }, + gender: { + propDefinition: [ + app, + "gender", + ], + optional: true, + }, + dateOfBirth: { + propDefinition: [ + app, + "dateOfBirth", + ], + optional: true, + }, + courseSubject: { + type: "string", + label: "Course Subject", + description: "The students chosen subject.", + optional: true, + }, + courseLevel: { + type: "string", + label: "Course Level", + description: "The students chosen level.", + optional: true, + }, }, async run({ $ }) { - const response = await this.teachNGo.createProspect({ - prospectDetails: this.prospectDetails, + const response = await this.app.createProspect({ + $, + data: { + "fname": this.firstName, + "lname": this.lastName, + "mobile_phone": this.mobilePhone, + "email_address": this.emailAddress, + "description": this.description, + "gender": this.gender, + "date_of_birth": this.dateOfBirth, + "course_subject": this.courseSubject, + "course_level": this.courseLevel, + }, }); - $.export("$summary", `Successfully created prospect with ID: ${response.id}`); + $.export("$summary", `Successfully created prospect with ID: ${response.data.id}`); return response; }, }; diff --git a/components/teach_n_go/actions/create-student/create-student.mjs b/components/teach_n_go/actions/create-student/create-student.mjs index 3d619d3d57c11..c3ce761888919 100644 --- a/components/teach_n_go/actions/create-student/create-student.mjs +++ b/components/teach_n_go/actions/create-student/create-student.mjs @@ -1,34 +1,194 @@ -import teachNGo from "../../teach_n_go.app.mjs"; -import { axios } from "@pipedream/platform"; +import { PAYMENT_METHOD_OPTIONS } from "../../common/constants.mjs"; +import app from "../../teach_n_go.app.mjs"; export default { key: "teach_n_go-create-student", name: "Create Student", description: "Registers a new student in Teach 'n Go. [See the documentation](https://intercom.help/teach-n-go/en/articles/6807235-new-student-and-class-registration-api)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { - teachNGo, - personalDetails: { + app, + firstName: { propDefinition: [ - teachNGo, - "personalDetails", + app, + "firstName", ], + description: "The student's first name.", }, - academicDetails: { + lastName: { propDefinition: [ - teachNGo, - "academicDetails", + app, + "lastName", ], + description: "The student's last name.", + }, + gender: { + propDefinition: [ + app, + "gender", + ], + description: "The student's gender.", + optional: true, + }, + registrationDate: { + type: "string", + label: "Registration Date", + description: "The student's registration date. **Format: YYYY-MM-DD**", + optional: true, + }, + dateOfBirth: { + propDefinition: [ + app, + "dateOfBirth", + ], + description: "The student's date of birth. **Format: YYYY-MM-DD**", + optional: true, + }, + identificationNumber: { + type: "string", + label: "Identification Number", + description: "The external number to identify the student.", + optional: true, + }, + preferredPaymentMethod: { + type: "integer", + label: "Preferred Payment Method", + description: "The payment method the student want to use.", + options: PAYMENT_METHOD_OPTIONS, + optional: true, + }, + discountPercentage: { + type: "string", + label: "Discount Percentage", + description: "The discount percentage on the payment amount.", + optional: true, + }, + mobilePhoneCode: { + type: "integer", + label: "Mobile Phone Code", + description: "The region code of the mobile phone. Min length: 2, Max length: 4", + optional: true, + }, + mobilePhone: { + type: "integer", + label: "Mobile Phone", + description: "The student's mobile phone", + optional: true, + }, + homePhoneCode: { + type: "integer", + label: "Home Phone Code", + description: "The region code of the home phone. Min length: 2, Max length: 4", + optional: true, + }, + homePhone: { + type: "integer", + label: "Home Phone", + description: "The student's home phone", + optional: true, + }, + emailAddress: { + propDefinition: [ + app, + "emailAddress", + ], + description: "The student's email address.", + optional: true, + }, + streetNameAndNumber: { + type: "string", + label: "Street Name And Number", + description: "The student's full address.", + optional: true, + }, + flatFloor: { + type: "string", + label: "Flat Floor", + description: "The student's address flat floor if it exists.", + optional: true, + }, + area: { + type: "string", + label: "Area", + description: "The student's address area.", + optional: true, + }, + city: { + type: "string", + label: "City", + description: "The student's city.", + optional: true, + }, + postcode: { + type: "string", + label: "Postcode", + description: "The student's postcode.", + optional: true, + }, + countryCode: { + type: "string", + label: "Country Code", + description: "The student's ISO 2 letter country code, e.g. (US, UK, IN).", + optional: true, + }, + generalNotes: { + type: "string", + label: "General Notes", + description: "Some student's additional notes.", + optional: true, + }, + medicalNotes: { + type: "string", + label: "Medical Notes", + description: "Some student's additional medical notes.", + optional: true, + }, + courses: { + propDefinition: [ + app, + "courses", + ], + optional: true, + }, + enrolmentDate: { + type: "string", + label: "Enrolment Date", + description: "The date of the student's enrolment.", + optional: true, }, }, async run({ $ }) { - const response = await this.teachNGo.registerStudent({ - personalDetails: this.personalDetails, - academicDetails: this.academicDetails, + const response = await this.app.registerStudent({ + $, + data: { + fname: this.firstName, + lname: this.lastName, + gender: this.gender, + registration_date: this.registrationDate, + date_of_birth: this.dateOfBirth, + identification_number: this.identificationNumber, + preferred_payment_method: this.preferredPaymentMethod, + discount_percentage: this.discountPercentage && parseFloat(this.discountPercentage), + mobile_phone_code: this.mobilePhoneCode, + mobile_phone: this.mobilePhone, + home_phone_code: this.homePhoneCode, + home_phone: this.homePhone, + email_address: this.emailAddress, + street_name_and_number: this.streetNameAndNumber, + flat_floor: this.flatFloor, + area: this.area, + city: this.city, + postcode: this.postcode, + country_code: this.countryCode, + general_notes: this.generalNotes, + medical_notes: this.medicalNotes, + courses: this.courses, + enrolment_date: this.enrolmentDate, + }, }); - $.export("$summary", `Successfully registered student with ID: ${response.id}`); + $.export("$summary", `Successfully registered student with ID: ${response.data.id}`); return response; }, }; diff --git a/components/teach_n_go/actions/invoice-mark-paid/invoice-mark-paid.mjs b/components/teach_n_go/actions/invoice-mark-paid/invoice-mark-paid.mjs deleted file mode 100644 index 365543b2ae07c..0000000000000 --- a/components/teach_n_go/actions/invoice-mark-paid/invoice-mark-paid.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import teachNGo from "../../teach_n_go.app.mjs"; - -export default { - key: "teach_n_go-invoice-mark-paid", - name: "Mark Invoice as Paid", - description: "Marks an existing invoice as paid within Teach 'n Go. [See the documentation](https://intercom.help/teach-n-go/en/articles/8727904-api-endpoints)", - version: "0.0.{{ts}}", - type: "action", - props: { - teachNGo, - invoiceId: { - propDefinition: [ - teachNGo, - "invoiceId", - ], - }, - paidDate: { - propDefinition: [ - teachNGo, - "paidDate", - ], - optional: true, - }, - }, - async run({ $ }) { - const response = await this.teachNGo.markInvoiceAsPaid({ - invoiceId: this.invoiceId, - paidDate: this.paidDate, - }); - - $.export("$summary", `Successfully marked invoice ${this.invoiceId} as paid.`); - return response; - }, -}; diff --git a/components/teach_n_go/common/constants.mjs b/components/teach_n_go/common/constants.mjs new file mode 100644 index 0000000000000..f8b20bd4ccc75 --- /dev/null +++ b/components/teach_n_go/common/constants.mjs @@ -0,0 +1,30 @@ +export const LIMIT = 100; + +export const GENDER_OPTIONS = [ + "Female", + "Male", + "Not Specified", +]; + +export const PAYMENT_METHOD_OPTIONS = [ + { + label: "Cash", + value: 1, + }, + { + label: "Cheque", + value: 2, + }, + { + label: "Credit Card", + value: 3, + }, + { + label: "Bank Transfer", + value: 4, + }, + { + label: "Direct Debit", + value: 5, + }, +]; diff --git a/components/teach_n_go/common/utils.mjs b/components/teach_n_go/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/teach_n_go/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/teach_n_go/package.json b/components/teach_n_go/package.json index e1f4eb5a4d309..4db442120a99c 100644 --- a/components/teach_n_go/package.json +++ b/components/teach_n_go/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/teach_n_go", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Teach 'n Go Components", "main": "teach_n_go.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/teach_n_go/sources/common/base.mjs b/components/teach_n_go/sources/common/base.mjs new file mode 100644 index 0000000000000..6eed1508280e6 --- /dev/null +++ b/components/teach_n_go/sources/common/base.mjs @@ -0,0 +1,59 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import app from "../../teach_n_go.app.mjs"; + +export default { + props: { + app, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastId() { + return this.db.get("lastId") || 0; + }, + _setLastId(lastId) { + this.db.set("lastId", lastId); + }, + async emitEvent(maxResults = false) { + const lastId = this._getLastId(); + + const response = this.app.paginate({ + fn: this.getFunction(), + }); + + let responseArray = []; + for await (const item of response) { + if (item.id <= lastId) break; + responseArray.push(item); + } + + if (responseArray.length) { + if (maxResults && (responseArray.length > maxResults)) { + responseArray.length = maxResults; + } + this._setLastId(responseArray[0].id); + } + + for (const item of responseArray.reverse()) { + this.$emit(item, { + id: item.id, + summary: this.getSummary(item), + ts: Date.parse(item.created || new Date()), + }); + } + }, + }, + hooks: { + async deploy() { + await this.emitEvent(25); + }, + }, + async run() { + await this.emitEvent(); + }, +}; diff --git a/components/teach_n_go/sources/new-class/new-class.mjs b/components/teach_n_go/sources/new-class/new-class.mjs index 9136417573bf6..e3dc8d48985b8 100644 --- a/components/teach_n_go/sources/new-class/new-class.mjs +++ b/components/teach_n_go/sources/new-class/new-class.mjs @@ -1,94 +1,22 @@ -import { axios } from "@pipedream/platform"; -import teachNGo from "../../teach_n_go.app.mjs"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "teach_n_go-new-class", name: "New Class Created", - description: "Emit a new event when a class is created. [See the documentation](https://intercom.help/teach-n-go/en/articles/8727904-api-endpoints)", - version: "0.0.{{ts}}", + description: "Emit new event when a class is created.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - teachNGo, - db: "$.service.db", - courseTitle: { - propDefinition: [ - teachNGo, - "courseTitle", - ], - }, - dateAndTime: { - propDefinition: [ - teachNGo, - "dateAndTime", - ], - }, - classDescription: { - propDefinition: [ - teachNGo, - "classDescription", - ], - optional: true, - }, - teacher: { - propDefinition: [ - teachNGo, - "teacher", - ], - optional: true, - }, - }, - hooks: { - async deploy() { - const classes = await this.fetchClasses(); - for (const classData of classes.slice(-50).reverse()) { - this.$emit(classData, { - id: classData.id, - summary: `New Class: ${classData.title}`, - ts: Date.parse(classData.dateAndTime), - }); - } - }, - async activate() { - // Activation logic if any - }, - async deactivate() { - // Deactivation logic if any - }, - }, methods: { - async fetchClasses() { - return this.teachNGo._makeRequest({ - path: "/classes", - }); + ...common.methods, + getFunction() { + return this.app.listCourses; }, - async emitNewClassEvent() { - const courseTitle = this.courseTitle; - const dateAndTime = this.dateAndTime; - const classDescription = this.classDescription || null; - const teacher = this.teacher || null; - - const classData = { - courseTitle, - dateAndTime, - classDescription, - teacher, - }; - - this.$emit(classData, { - summary: `New Class: ${courseTitle}`, - ts: new Date().getTime(), - }); + getSummary(item) { + return `New Class: ${item.course_full_title}`; }, }, - async run() { - const classes = await this.fetchClasses(); - for (const classData of classes) { - this.$emit(classData, { - id: classData.id, - summary: `New Class: ${classData.title}`, - ts: Date.parse(classData.dateAndTime), - }); - } - }, + sampleEmit, }; diff --git a/components/teach_n_go/sources/new-class/test-event.mjs b/components/teach_n_go/sources/new-class/test-event.mjs new file mode 100644 index 0000000000000..6c4f7457f87bf --- /dev/null +++ b/components/teach_n_go/sources/new-class/test-event.mjs @@ -0,0 +1,46 @@ +export default { + "course_title": "Class title", + "course_subject": "Course subject", + "course_level": "Course level", + "school_id": 16385, + "start_date": "2024-10-21", + "end_date": "2024-10-28", + "recurrence": "weekly", + "payment_frequency": "free", + "id": 153319, + "photo": null, + "payment_fee": "0", + "course_description": "", + "course_full_title": "Class title [Online Lesson]", + "created": "2024-10-17 18:20:13", + "modified": "2024-10-17 18:20:15", + "color": "color1", + "course_started": false, + "course_ended": false, + "course_status": 1, + "num_enrolled_students": 0, + "teachers": "66792", + "classrooms": "39627", + "billing_month_start_date": "2024-10-01", + "billing_month_end_date": "2024-10-01", + "custom_payments": null, + "archived": false, + "awarding_body": "", + "course_code": "", + "book_code": "", + "total_lessons": 2, + "total_lessons_hrs": "02:00", + "skype_meeting_link": "", + "year": null, + "credit_hours": "", + "class_type": "", + "is_ended": null, + "teacher_hourly_fees": null, + "is_booking_class": false, + "subscription_plan_id": null, + "is_stripe_sub_allow": 0, + "created_by": 66114, + "modified_by": 66114, + "exception_dates": null, + "removed_exception_dates": null +} \ No newline at end of file diff --git a/components/teach_n_go/sources/new-payment/new-payment.mjs b/components/teach_n_go/sources/new-payment/new-payment.mjs deleted file mode 100644 index 7a18345e179ca..0000000000000 --- a/components/teach_n_go/sources/new-payment/new-payment.mjs +++ /dev/null @@ -1,109 +0,0 @@ -import teachNGo from "../../teach_n_go.app.mjs"; -import { - axios, DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, -} from "@pipedream/platform"; - -export default { - key: "teach_n_go-new-payment", - name: "New Payment Made", - description: "Emit new event when a payment is made. [See the documentation](https://intercom.help/teach-n-go/en/articles/8727904-api-endpoints)", - version: "0.0.1", - type: "source", - dedupe: "unique", - props: { - teachNGo: { - type: "app", - app: "teach_n_go", - }, - studentName: { - propDefinition: [ - teachNGo, - "studentName", - ], - }, - amount: { - propDefinition: [ - teachNGo, - "amount", - ], - }, - paymentMethod: { - propDefinition: [ - teachNGo, - "paymentMethod", - ], - optional: true, - }, - paymentDate: { - propDefinition: [ - teachNGo, - "paymentDate", - ], - optional: true, - }, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, - }, - }, - }, - methods: { - _getLastPaymentTimestamp() { - return this.db.get("lastPaymentTimestamp") || 0; - }, - _setLastPaymentTimestamp(timestamp) { - this.db.set("lastPaymentTimestamp", timestamp); - }, - async _fetchPayments(params) { - return await axios(this, { - method: "GET", - url: `${this.teachNGo._baseUrl()}/path-to-payment-endpoint`, // Replace with actual endpoint - headers: { - "X-API-KEY": this.teachNGo.$auth.api_key, - }, - params, - }); - }, - }, - hooks: { - async deploy() { - const lastPaymentTimestamp = this._getLastPaymentTimestamp(); - const payments = await this._fetchPayments({ - lastPaymentTimestamp, - }); - const recentPayments = payments.slice(0, 50); - - for (const payment of recentPayments) { - this.$emit(payment, { - id: payment.id, - summary: `New Payment: ${payment.studentName}`, - ts: Date.parse(payment.paymentDate) || Date.now(), - }); - } - - if (recentPayments.length) { - this._setLastPaymentTimestamp(Date.parse(recentPayments[0].paymentDate)); - } - }, - }, - async run() { - const lastPaymentTimestamp = this._getLastPaymentTimestamp(); - const payments = await this._fetchPayments({ - lastPaymentTimestamp, - }); - - for (const payment of payments) { - this.$emit(payment, { - id: payment.id, - summary: `New Payment: ${payment.studentName}`, - ts: Date.parse(payment.paymentDate) || Date.now(), - }); - } - - if (payments.length) { - this._setLastPaymentTimestamp(Date.parse(payments[0].paymentDate)); - } - }, -}; diff --git a/components/teach_n_go/sources/new-student/new-student.mjs b/components/teach_n_go/sources/new-student/new-student.mjs index 85daaf78e969b..5fe9a2abeb76f 100644 --- a/components/teach_n_go/sources/new-student/new-student.mjs +++ b/components/teach_n_go/sources/new-student/new-student.mjs @@ -1,93 +1,26 @@ -import teachNGo from "../../teach_n_go.app.mjs"; -import { axios } from "@pipedream/platform"; +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; export default { + ...common, key: "teach_n_go-new-student", name: "New Student Registration", - description: "Emit an event when a new student is registered. [See the documentation](https://intercom.help/teach-n-go/en/articles/6807235-new-student-and-class-registration-api)", - version: "0.0.{{ts}}", + description: "Emit new event when a new student is registered.", + version: "0.0.1", type: "source", dedupe: "unique", - props: { - teachNGo, - db: "$.service.db", - timer: { - type: "$.interface.timer", - default: { - intervalSeconds: 60, - }, - }, - studentName: { - propDefinition: [ - teachNGo, - "studentName", - ], - }, - dateOfBirth: { - propDefinition: [ - teachNGo, - "dateOfBirth", - ], - }, - contactNumber: { - propDefinition: [ - teachNGo, - "contactNumber", - ], - optional: true, - }, - email: { - propDefinition: [ - teachNGo, - "email", - ], - optional: true, - }, - }, methods: { - async fetchStudents() { - return this.teachNGo._makeRequest({ - method: "GET", - path: "/student", - }); - }, - emitStudentRegistrationEvent(student) { - const { - id, fname, lname, registration_date: registrationDate, date_of_birth: dateOfBirth, email_address: email, mobile_phone: contactNumber, - } = student; - const summary = `New Student: ${fname} ${lname}`; - this.$emit(student, { - id, - summary, - ts: Date.parse(registrationDate), - }); + ...common.methods, + getFunction() { + return this.app.listStudents; }, - _getLastTimestamp() { - return this.db.get("lastTimestamp") ?? 0; + getSummary({ + fname, lname, email_address: email, + }) { + return `New Student: ${fname} ${lname}${email + ? ` - ${email}` + : ""}`; }, - _setLastTimestamp(ts) { - this.db.set("lastTimestamp", ts); - }, - }, - hooks: { - async deploy() { - const students = await this.fetchStudents(); - students.slice(-50).forEach(this.emitStudentRegistrationEvent.bind(this)); - }, - }, - async run() { - const lastTimestamp = this._getLastTimestamp(); - const students = await this.fetchStudents(); - let maxTimestamp = lastTimestamp; - - students.forEach((student) => { - const studentTimestamp = new Date(student.registration_date).getTime(); - if (studentTimestamp > lastTimestamp) { - this.emitStudentRegistrationEvent(student); - maxTimestamp = Math.max(maxTimestamp, studentTimestamp); - } - }); - - this._setLastTimestamp(maxTimestamp); }, + sampleEmit, }; diff --git a/components/teach_n_go/sources/new-student/test-event.mjs b/components/teach_n_go/sources/new-student/test-event.mjs new file mode 100644 index 0000000000000..a8692d2b06884 --- /dev/null +++ b/components/teach_n_go/sources/new-student/test-event.mjs @@ -0,0 +1,51 @@ +export default { + "id": 411081, + "school_id": 16385, + "identification_number": "123", + "fname": "Jhon", + "lname": "Doe", + "gender": "Male", + "registration_date": "2024-10-17", + "date_of_birth": "1991-02-02", + "email_address": "jhon@email.com", + "mobile_phonecode": "", + "mobile_phone": "", + "home_phonecode": "", + "home_phone": "", + "street_name_and_number": "", + "flat_floor": "", + "area": "", + "city": "", + "country_code": "", + "postcode": "", + "whole_address": "", + "general_notes": "", + "medical_notes": "", + "delayed_payments": "", + "num_enrolled_courses": 1, + "discount_percentage": "10", + "discount_type": "percentage", + "custom_fields": [], + "timezone": null, + "course_subject": null, + "course_level": null, + "photo_link": "/img/user-no-img-m.jpg", + "preferred_payment_method": "Credit Card", + "classes": [ + { + "course_title": "class title", + "course_full_title": "class title [Online Lesson]", + "course_subject": "", + "course_level": "", + "course_description": "", + "course_started": true, + "course_ended": false, + "school_id": 16385, + "recurrence": "weekly", + "payment_frequency": "free", + "enrolment_date": "2024-10-20", + "unenrolment_date": null, + "student_id": 411081 + } + ] +} \ No newline at end of file diff --git a/components/teach_n_go/teach_n_go.app.mjs b/components/teach_n_go/teach_n_go.app.mjs index 0bb54b2b5a843..e86422f456a65 100644 --- a/components/teach_n_go/teach_n_go.app.mjs +++ b/components/teach_n_go/teach_n_go.app.mjs @@ -1,162 +1,122 @@ import { axios } from "@pipedream/platform"; +import { GENDER_OPTIONS } from "./common/constants.mjs"; export default { type: "app", app: "teach_n_go", propDefinitions: { - courseTitle: { + firstName: { type: "string", - label: "Course Title", - description: "The title of the course for the class.", + label: "First Name", + description: "The prospect's first name.", }, - dateAndTime: { + lastName: { type: "string", - label: "Date and Time", - description: "The date and time when the class is scheduled.", + label: "Last Name", + description: "The prospect's surname.", }, - classDescription: { + gender: { type: "string", - label: "Class Description", - description: "The optional description of the class.", - optional: true, - }, - teacher: { - type: "string", - label: "Teacher", - description: "The optional teacher for the class.", - optional: true, - }, - studentName: { - type: "string", - label: "Student Name", - description: "The name of the student involved.", - }, - amount: { - type: "number", - label: "Amount", - description: "The amount of the payment.", - }, - paymentMethod: { - type: "string", - label: "Payment Method", - description: "The optional payment method used.", - optional: true, - }, - paymentDate: { - type: "string", - label: "Payment Date", - description: "The optional payment date.", - optional: true, + label: "Gender", + description: "The prospect's gender.", + options: GENDER_OPTIONS, }, dateOfBirth: { type: "string", - label: "Date of Birth", - description: "The date of birth of the student.", + label: "Date Of Birth", + description: "The prospect's date of birth. **Format: YYYY-MM-DD**", }, - contactNumber: { + emailAddress: { type: "string", - label: "Contact Number", - description: "The optional contact number of the student.", - optional: true, - }, - email: { - type: "string", - label: "Email", - description: "The optional email of the student.", - optional: true, - }, - prospectDetails: { - type: "object", - label: "Prospect Details", - description: "The details of the new prospect.", - }, - invoiceId: { - type: "string", - label: "Invoice ID", - description: "The ID of the invoice to be marked as paid.", - }, - paidDate: { - type: "string", - label: "Paid Date", - description: "The optional date when the invoice was paid.", - optional: true, - }, - personalDetails: { - type: "object", - label: "Personal Details", - description: "The personal details of the new student.", - }, - academicDetails: { - type: "object", - label: "Academic Details", - description: "The academic details of the new student.", + label: "Email Address", + description: "The prospect's email address.", + }, + courses: { + type: "integer[]", + label: "Courses", + description: "The student's course Ids.", + async options() { + const { data } = await this.listCourses(); + + return data.map(({ + course_full_title: label, id: value, + }) => ({ + label, + value, + })); + }, }, }, methods: { - authKeys() { - console.log(Object.keys(this.$auth)); - }, _baseUrl() { - return "https://app.teachngo.com/api"; + return "https://app.teachngo.com"; + }, + _headers(headers = {}) { + return { + "X-API-KEY": `${this.$auth.api_key}`, + ...headers, + }; }, - async _makeRequest(opts = {}) { - const { - $ = this, method = "GET", path = "/", headers, ...otherOpts - } = opts; + _makeRequest({ + $ = this, path, headers, ...opts + }) { return axios($, { - ...otherOpts, - method, url: this._baseUrl() + path, - headers: { - ...headers, - "X-API-KEY": this.$auth.api_key, - }, + headers: this._headers(headers), + ...opts, }); }, - async emitNewClassEvent({ - courseTitle, dateAndTime, classDescription, teacher, - }) { - // Logic to emit new class created event based on input parameters - }, - async emitNewPaymentEvent({ - studentName, amount, paymentMethod, paymentDate, - }) { - // Logic to emit new payment made event based on input parameters - }, - async emitNewStudentRegistrationEvent({ - studentName, dateOfBirth, contactNumber, email, - }) { - // Logic to emit new student registration event based on input parameters + createProspect(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/LeadsApi/add", + ...opts, + }); }, - async createProspect({ prospectDetails }) { + registerStudent(opts = {}) { return this._makeRequest({ method: "POST", - path: "/prospect", - data: prospectDetails, + path: "/api/student", + ...opts, }); }, - async markInvoiceAsPaid({ - invoiceId, paidDate, - }) { + listCourses(opts = {}) { return this._makeRequest({ method: "POST", - path: `/invoice/${invoiceId}/paid`, - data: { - paid_date: paidDate, - }, + path: "/globalApis/course_list", + ...opts, }); }, - async registerStudent({ - personalDetails, academicDetails, - }) { + listStudents(opts = {}) { return this._makeRequest({ method: "POST", - path: "/student", - data: { - personalDetails, - academicDetails, - }, + path: "/globalApis/student_list", + ...opts, }); }, + async *paginate({ + fn, params = {}, ...opts + }) { + let hasMore = false; + let page = 0; + + do { + params.page = ++page; + const { + data, + next, + } = await fn({ + params, + ...opts, + }); + + for (const d of data) { + yield d; + } + + hasMore = next; + + } while (hasMore); + }, }, }; From bd8cb974d509259ba240d42d20c5b9f445389df4 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Fri, 18 Oct 2024 10:01:00 -0300 Subject: [PATCH 3/3] pnpm update --- pnpm-lock.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a8b902fe0ad6..797b6e5e50dc3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9918,7 +9918,10 @@ importers: specifiers: {} components/teach_n_go: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/teachable: specifiers: