@pipedream/bloomerang 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,77 @@
1
+ import bloomerang from "../../bloomerang.app.mjs";
2
+ import {
3
+ CHANNEL_OPTIONS, PURPOSE_OPTIONS,
4
+ } from "../../common/constants.mjs";
5
+
6
+ export default {
7
+ key: "bloomerang-add-interaction",
8
+ name: "Add Interaction",
9
+ description: "Adds an interaction to an existing constituent in Bloomerang. [See the documentation](https://bloomerang.co/product/integrations-data-management/api/rest-api/#/Interactions/post_interaction)",
10
+ version: "0.0.3",
11
+ annotations: {
12
+ destructiveHint: false,
13
+ openWorldHint: true,
14
+ readOnlyHint: false,
15
+ },
16
+ type: "action",
17
+ props: {
18
+ bloomerang,
19
+ constituentId: {
20
+ propDefinition: [
21
+ bloomerang,
22
+ "constituentId",
23
+ ],
24
+ },
25
+ date: {
26
+ type: "string",
27
+ label: "Date",
28
+ description: "The date of the interaction",
29
+ },
30
+ subject: {
31
+ type: "string",
32
+ label: "Subject",
33
+ description: "The subject of the interaction",
34
+ },
35
+ channel: {
36
+ type: "string",
37
+ label: "Channel",
38
+ description: "The channel of the interaction",
39
+ options: CHANNEL_OPTIONS,
40
+ },
41
+ purpose: {
42
+ type: "string",
43
+ label: "Purpose",
44
+ description: "The purpose of the interaction",
45
+ options: PURPOSE_OPTIONS,
46
+ },
47
+ note: {
48
+ type: "string",
49
+ label: "Note",
50
+ description: "Note for the interaction",
51
+ optional: true,
52
+ },
53
+ isInbound: {
54
+ type: "boolean",
55
+ label: "Is Inbound",
56
+ description: "Was the interaction initiated by constituent?",
57
+ optional: true,
58
+ },
59
+ },
60
+ async run({ $ }) {
61
+ const response = await this.bloomerang.createInteraction({
62
+ $,
63
+ data: {
64
+ AccountId: this.constituentId,
65
+ Date: this.date,
66
+ Subject: this.subject,
67
+ Channel: this.channel,
68
+ Purpose: this.purpose,
69
+ note: this.note,
70
+ IsInbound: this.isInbound,
71
+ },
72
+ });
73
+
74
+ $.export("$summary", `Successfully added interaction with ID ${response.Id}`);
75
+ return response;
76
+ },
77
+ };
@@ -0,0 +1,172 @@
1
+ import bloomerang from "../../bloomerang.app.mjs";
2
+ import {
3
+ COMMUNICATION_CHANNEL_OPTIONS,
4
+ CONSTITUENT_GENDER_OPTIONS,
5
+ CONSTITUENT_PREFIX_OPTIONS,
6
+ CONSTITUENT_STATUS_OPTIONS,
7
+ CONSTITUENT_SUFFIX_OPTIONS,
8
+ CONSTITUENT_TYPE_OPTIONS,
9
+ } from "../../common/constants.mjs";
10
+
11
+ export default {
12
+ key: "bloomerang-create-constituent",
13
+ name: "Create Constituent",
14
+ description: "Creates a new constituent in Bloomerang. [See the documentation](https://bloomerang.co/product/integrations-data-management/api/rest-api/#/Constituents/post_constituent)",
15
+ version: "0.0.2",
16
+ annotations: {
17
+ destructiveHint: false,
18
+ openWorldHint: true,
19
+ readOnlyHint: false,
20
+ },
21
+ type: "action",
22
+ props: {
23
+ bloomerang,
24
+ type: {
25
+ type: "string",
26
+ label: "Constituent Type",
27
+ description: "Filter constituents by type",
28
+ options: CONSTITUENT_TYPE_OPTIONS,
29
+ reloadProps: true,
30
+ },
31
+ status: {
32
+ type: "string",
33
+ label: "Status",
34
+ description: "The status of the constituent",
35
+ options: CONSTITUENT_STATUS_OPTIONS,
36
+ optional: true,
37
+ },
38
+ fullName: {
39
+ type: "string",
40
+ label: "Organization Name",
41
+ description: "The organization's name of the constituent",
42
+ hidden: true,
43
+ },
44
+ firstName: {
45
+ type: "string",
46
+ label: "First Name",
47
+ description: "The first name of the constituent",
48
+ hidden: true,
49
+ },
50
+ lastName: {
51
+ type: "string",
52
+ label: "Last Name",
53
+ description: "The last name of the constituent",
54
+ hidden: true,
55
+ },
56
+ middleName: {
57
+ type: "string",
58
+ label: "Middle Name",
59
+ description: "The middle name of the constituent",
60
+ optional: true,
61
+ },
62
+ prefix: {
63
+ type: "string",
64
+ label: "Title",
65
+ description: "The prefix of the constituent",
66
+ options: CONSTITUENT_PREFIX_OPTIONS,
67
+ optional: true,
68
+ },
69
+ suffix: {
70
+ type: "string",
71
+ label: "Suffix",
72
+ description: "The suffix of the constituent",
73
+ options: CONSTITUENT_SUFFIX_OPTIONS,
74
+ optional: true,
75
+ },
76
+ jobTitle: {
77
+ type: "string",
78
+ label: "Job Title",
79
+ description: "The job title of the constituent",
80
+ optional: true,
81
+ },
82
+ gender: {
83
+ type: "string",
84
+ label: "Gender",
85
+ description: "The gender of the constituent",
86
+ options: CONSTITUENT_GENDER_OPTIONS,
87
+ optional: true,
88
+ },
89
+ birthdate: {
90
+ type: "string",
91
+ label: "Birthdate",
92
+ description: "The birth date of the constituent",
93
+ optional: true,
94
+ },
95
+ employer: {
96
+ type: "string",
97
+ label: "Employer",
98
+ description: "The employer of the constituent",
99
+ optional: true,
100
+ },
101
+ website: {
102
+ type: "string",
103
+ label: "Website",
104
+ description: "An website of the constituent",
105
+ optional: true,
106
+ },
107
+ facebookId: {
108
+ type: "string",
109
+ label: "Facebook",
110
+ description: "The constituent's facebook page",
111
+ optional: true,
112
+ },
113
+ twitterId: {
114
+ type: "string",
115
+ label: "Twitter ID",
116
+ description: "The constituent's twitter ID",
117
+ optional: true,
118
+ },
119
+ linkedInId: {
120
+ type: "string",
121
+ label: "LinkedIn",
122
+ description: "The constituent's linkedIn page",
123
+ optional: true,
124
+ },
125
+ preferredCommunicationChannel: {
126
+ type: "string",
127
+ label: "Preferred Communication Channel",
128
+ description: "The preferred comunication channel of the constituent",
129
+ options: COMMUNICATION_CHANNEL_OPTIONS,
130
+ optional: true,
131
+ },
132
+ },
133
+ async additionalProps(props) {
134
+ const isIndividual = this.type === "Individual";
135
+ props.firstName.hidden = !isIndividual;
136
+ props.lastName.hidden = !isIndividual;
137
+ props.fullName.hidden = isIndividual;
138
+ return {};
139
+ },
140
+ async run({ $ }) {
141
+ const data = {
142
+ Type: this.type,
143
+ Status: this.status,
144
+ Prefix: this.prefix,
145
+ Suffix: this.suffix,
146
+ JobTitle: this.jobTitle,
147
+ Gender: this.gender,
148
+ Birthdate: this.birthdate,
149
+ Employer: this.employer,
150
+ Website: this.website,
151
+ FacebookId: this.facebookId,
152
+ TwitterId: this.twitterId,
153
+ LinkedInId: this.linkedInId,
154
+ PreferredCommunicationChannel: this.preferredCommunicationChannel,
155
+ };
156
+ if (this.type === "Individual") {
157
+ data.FirstName = this.firstName;
158
+ data.LastName = this.lastName;
159
+ data.MiddleName = this.middleName;
160
+ } else {
161
+ data.FullName = this.fullName;
162
+ }
163
+
164
+ const response = await this.bloomerang.createConstituent({
165
+ $,
166
+ data,
167
+ });
168
+
169
+ $.export("$summary", `Successfully created constituent with ID ${response.Id}`);
170
+ return response;
171
+ },
172
+ };
@@ -0,0 +1,90 @@
1
+ import bloomerang from "../../bloomerang.app.mjs";
2
+ import { PAYMENT_METHOD_OPTIONS } from "../../common/constants.mjs";
3
+
4
+ export default {
5
+ key: "bloomerang-create-donation",
6
+ name: "Create Donation",
7
+ description: "Creates a new donation record in Bloomerang. [See the documentation](https://bloomerang.co/product/integrations-data-management/api/rest-api/)",
8
+ version: "0.0.2",
9
+ annotations: {
10
+ destructiveHint: false,
11
+ openWorldHint: true,
12
+ readOnlyHint: false,
13
+ },
14
+ type: "action",
15
+ props: {
16
+ bloomerang,
17
+ constituentId: {
18
+ propDefinition: [
19
+ bloomerang,
20
+ "constituentId",
21
+ ],
22
+ },
23
+ date: {
24
+ type: "string",
25
+ label: "Date",
26
+ description: "The date of the donation",
27
+ },
28
+ amount: {
29
+ type: "string",
30
+ label: "Amount",
31
+ description: "The amount for the donation",
32
+ },
33
+ fundId: {
34
+ propDefinition: [
35
+ bloomerang,
36
+ "fundId",
37
+ ],
38
+ },
39
+ paymentMethod: {
40
+ type: "string",
41
+ label: "Payment Method",
42
+ description: "The method of payment",
43
+ options: PAYMENT_METHOD_OPTIONS,
44
+ },
45
+ campaignId: {
46
+ propDefinition: [
47
+ bloomerang,
48
+ "campaignId",
49
+ ],
50
+ optional: true,
51
+ },
52
+ appealId: {
53
+ propDefinition: [
54
+ bloomerang,
55
+ "appealId",
56
+ ],
57
+ optional: true,
58
+ },
59
+ note: {
60
+ type: "string",
61
+ label: "Note",
62
+ description: "A note for the donation",
63
+ optional: true,
64
+ },
65
+ },
66
+ async run({ $ }) {
67
+ const response = await this.bloomerang.createDonation({
68
+ $,
69
+ data: {
70
+ AccountId: this.constituentId,
71
+ Date: this.date,
72
+ Amount: this.amount,
73
+ Method: this.paymentMethod,
74
+ Designations: [
75
+ {
76
+ FundId: this.fundId,
77
+ Amount: this.amount,
78
+ Type: "Donation",
79
+ CampaignId: this.campaignId,
80
+ AppealId: this.appealId,
81
+ Note: this.note,
82
+ },
83
+ ],
84
+ },
85
+ });
86
+
87
+ $.export("$summary", `Successfully created donation with ID: ${response.Id}`);
88
+ return response;
89
+ },
90
+ };
@@ -1,11 +1,189 @@
1
+ import { axios } from "@pipedream/platform";
2
+ import { LIMIT } from "./common/constants.mjs";
3
+
1
4
  export default {
2
5
  type: "app",
3
6
  app: "bloomerang",
4
- propDefinitions: {},
7
+ propDefinitions: {
8
+ constituentId: {
9
+ type: "string",
10
+ label: "Constituent ID",
11
+ description: "The ID of the constituent",
12
+ async options({ page }) {
13
+ const { Results: response } = await this.listConstituents({
14
+ params: {
15
+ skip: LIMIT * page,
16
+ take: LIMIT,
17
+ },
18
+ });
19
+ return response.map(({
20
+ Id: value, FullName: label,
21
+ }) => ({
22
+ label,
23
+ value,
24
+ }));
25
+ },
26
+ },
27
+ fundId: {
28
+ type: "string",
29
+ label: "Fund",
30
+ description: "Filter donations by fund",
31
+ async options({ page }) {
32
+ const { Results: response } = await this.listFunds({
33
+ params: {
34
+ skip: LIMIT * page,
35
+ take: LIMIT,
36
+ },
37
+ });
38
+ return response.map(({
39
+ Id: value, Name: label,
40
+ }) => ({
41
+ label,
42
+ value,
43
+ }));
44
+ },
45
+ },
46
+ campaignId: {
47
+ type: "string",
48
+ label: "Campaign",
49
+ description: "Filter interactions by campaign",
50
+ async options({ page }) {
51
+ const { Results: response } = await this.listCampaigns({
52
+ params: {
53
+ skip: LIMIT * page,
54
+ take: LIMIT,
55
+ },
56
+ });
57
+ return response.map(({
58
+ Id: value, Name: label,
59
+ }) => ({
60
+ label,
61
+ value,
62
+ }));
63
+ },
64
+ },
65
+ appealId: {
66
+ type: "string",
67
+ label: "Appeal",
68
+ description: "An appeal for the donation",
69
+ async options({ page }) {
70
+ const { Results: response } = await this.listAppeals({
71
+ params: {
72
+ skip: LIMIT * page,
73
+ take: LIMIT,
74
+ },
75
+ });
76
+ return response.map(({
77
+ Id: value, Name: label,
78
+ }) => ({
79
+ label,
80
+ value,
81
+ }));
82
+ },
83
+ },
84
+ },
5
85
  methods: {
6
- // this.$auth contains connected account data
7
- authKeys() {
8
- console.log(Object.keys(this.$auth));
86
+ _baseUrl() {
87
+ return "https://api.bloomerang.co/v2";
88
+ },
89
+ _headers() {
90
+ return {
91
+ "accept": "application/json",
92
+ "x-api-key": `${this.$auth.api_key}`,
93
+ };
94
+ },
95
+ _makeRequest({
96
+ $ = this, path, ...opts
97
+ }) {
98
+ return axios($, {
99
+ url: this._baseUrl() + path,
100
+ headers: this._headers(),
101
+ ...opts,
102
+ });
103
+ },
104
+ listConstituents(opts = {}) {
105
+ return this._makeRequest({
106
+ path: "/constituents",
107
+ ...opts,
108
+ });
109
+ },
110
+ listInteractions(opts = {}) {
111
+ return this._makeRequest({
112
+ path: "/interactions",
113
+ ...opts,
114
+ });
115
+ },
116
+ listTransactions(opts = {}) {
117
+ return this._makeRequest({
118
+ path: "/transactions",
119
+ ...opts,
120
+ });
121
+ },
122
+ listFunds(opts = {}) {
123
+ return this._makeRequest({
124
+ path: "/funds",
125
+ ...opts,
126
+ });
127
+ },
128
+ listCampaigns(opts = {}) {
129
+ return this._makeRequest({
130
+ path: "/campaigns",
131
+ ...opts,
132
+ });
133
+ },
134
+ listAppeals(opts = {}) {
135
+ return this._makeRequest({
136
+ path: "/appeals",
137
+ ...opts,
138
+ });
139
+ },
140
+ createDonation(opts = {}) {
141
+ return this._makeRequest({
142
+ method: "POST",
143
+ path: "/transaction",
144
+ ...opts,
145
+ });
146
+ },
147
+ createConstituent(opts = {}) {
148
+ return this._makeRequest({
149
+ method: "POST",
150
+ path: "/constituent",
151
+ ...opts,
152
+ });
153
+ },
154
+ createInteraction(opts = {}) {
155
+ return this._makeRequest({
156
+ method: "POST",
157
+ path: "/interaction",
158
+ ...opts,
159
+ });
160
+ },
161
+ async *paginate({
162
+ fn, params = {}, maxResults = null, ...opts
163
+ }) {
164
+ let hasMore = false;
165
+ let count = 0;
166
+ let page = 0;
167
+
168
+ do {
169
+ params.skip = LIMIT * page;
170
+ params.take = LIMIT;
171
+ page++;
172
+ const { Results: data } = await fn({
173
+ params,
174
+ ...opts,
175
+ });
176
+ for (const d of data) {
177
+ yield d;
178
+
179
+ if (maxResults && ++count === maxResults) {
180
+ return count;
181
+ }
182
+ }
183
+
184
+ hasMore = data.length;
185
+
186
+ } while (hasMore);
9
187
  },
10
188
  },
11
- };
189
+ };
@@ -0,0 +1,173 @@
1
+ export const LIMIT = 50;
2
+
3
+ export const CHANNEL_OPTIONS = [
4
+ {
5
+ label: "Email",
6
+ value: "Email",
7
+ },
8
+ {
9
+ label: "In Person",
10
+ value: "InPerson",
11
+ },
12
+ {
13
+ label: "Mail",
14
+ value: "Mail",
15
+ },
16
+ {
17
+ label: "Mass Email",
18
+ value: "MassEmail",
19
+ },
20
+ {
21
+ label: "Other",
22
+ value: "Other",
23
+ },
24
+ {
25
+ label: "Phone",
26
+ value: "Phone",
27
+ },
28
+ {
29
+ label: "Social Media",
30
+ value: "SocialMedia",
31
+ },
32
+ {
33
+ label: "Text Message",
34
+ value: "TextMessage",
35
+ },
36
+ {
37
+ label: "Video Call",
38
+ value: "VideoCall",
39
+ },
40
+ {
41
+ label: "Webinar",
42
+ value: "Webinar",
43
+ },
44
+ {
45
+ label: "Website",
46
+ value: "Website",
47
+ },
48
+ ];
49
+
50
+ export const PURPOSE_OPTIONS = [
51
+ {
52
+ label: "Acknowledgement",
53
+ value: "Acknowledgement",
54
+ },
55
+ {
56
+ label: "Impact/Cultivation",
57
+ value: "ImpactCultivation",
58
+ },
59
+ {
60
+ label: "Newsletter",
61
+ value: "Newsletter",
62
+ },
63
+ {
64
+ label: "Receipt",
65
+ value: "Receipt",
66
+ },
67
+ {
68
+ label: "Solicitation",
69
+ value: "Solicitation",
70
+ },
71
+ {
72
+ label: "Special Event",
73
+ value: "SpecialEvent",
74
+ },
75
+ {
76
+ label: "Volunteer Activity",
77
+ value: "VolunteerActivity",
78
+ },
79
+ {
80
+ label: "Pledge Reminder",
81
+ value: "PledgeReminder",
82
+ },
83
+ {
84
+ label: "Welcome",
85
+ value: "Welcome",
86
+ },
87
+ {
88
+ label: "Other",
89
+ value: "Other",
90
+ },
91
+ ];
92
+
93
+ export const CONSTITUENT_TYPE_OPTIONS = [
94
+ "Individual",
95
+ "Organization",
96
+ ];
97
+
98
+ export const CONSTITUENT_STATUS_OPTIONS = [
99
+ "Active",
100
+ "Inactive",
101
+ "Deceased",
102
+ ];
103
+
104
+ export const CONSTITUENT_PREFIX_OPTIONS = [
105
+ "Atty.",
106
+ "Capt",
107
+ "Cmdr",
108
+ "Coach",
109
+ "Col",
110
+ "Dr.",
111
+ "Fr.",
112
+ "Gen",
113
+ "Gov.",
114
+ "Hon.",
115
+ "Lt",
116
+ "Maj",
117
+ "Master",
118
+ "Miss",
119
+ "Mr.",
120
+ "Mrs.",
121
+ "Ms.",
122
+ "Mx.",
123
+ "Pastor",
124
+ "Pres.",
125
+ "Prof.",
126
+ "Pvt",
127
+ "Rabbi",
128
+ "Rep.",
129
+ "Rev.",
130
+ "Sen.",
131
+ "Sgt",
132
+ "Sir",
133
+ "Sr.",
134
+ ];
135
+
136
+ export const CONSTITUENT_SUFFIX_OPTIONS = [
137
+ "DDS",
138
+ "Esq.",
139
+ "II",
140
+ "III",
141
+ "IV",
142
+ "Jr.",
143
+ "M.D.",
144
+ "Ph.D.",
145
+ "Sr.",
146
+ "V",
147
+ ];
148
+
149
+ export const CONSTITUENT_GENDER_OPTIONS = [
150
+ "Male",
151
+ "Female",
152
+ "Other",
153
+ ];
154
+
155
+ export const COMMUNICATION_CHANNEL_OPTIONS = [
156
+ "Email",
157
+ "Phone",
158
+ "Text Message",
159
+ "Mail",
160
+ ];
161
+
162
+ export const PAYMENT_METHOD_OPTIONS = [
163
+ "None",
164
+ "Cash",
165
+ "Check",
166
+ "CreditCard",
167
+ "Eft",
168
+ "InKind",
169
+ "ApplePay",
170
+ "GooglePay",
171
+ "PayPal",
172
+ "Venmo",
173
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/bloomerang",
3
- "version": "0.0.1",
3
+ "version": "0.1.1",
4
4
  "description": "Pipedream Bloomerang Components",
5
5
  "main": "bloomerang.app.mjs",
6
6
  "keywords": [
@@ -11,5 +11,8 @@
11
11
  "author": "Pipedream <support@pipedream.com> (https://pipedream.com/)",
12
12
  "publishConfig": {
13
13
  "access": "public"
14
+ },
15
+ "dependencies": {
16
+ "@pipedream/platform": "^3.1.1"
14
17
  }
15
18
  }