Skip to content

Commit 8a61054

Browse files
authored
Merge pull request #308 from plaid/of-investmenttransactions
[LP-458] Add logic for Investment Transactions
2 parents 59b65df + 6fa7456 commit 8a61054

File tree

9 files changed

+191
-20
lines changed

9 files changed

+191
-20
lines changed

.env.example

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ PLAID_ENV=sandbox
1212
# If you don't see the institution you want in Link, remove any products you aren't using.
1313
# Important: When moving to Production, make sure to update this list with only the products
1414
# you plan to use. Otherwise, you may be billed for unneeded products.
15+
# NOTE: Income_verification has to be used seperately from all other products due to the specific
16+
# flow.
1517
PLAID_PRODUCTS=auth,transactions
1618
# PLAID_COUNTRY_CODES is a comma-separated list of countries to use when
1719
# initializing Link, e.g. PLAID_COUNTRY_CODES=US,CA.

frontend/src/Components/ProductTypes/Products.tsx

+37-2
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,23 @@ import {
99
identityCategories,
1010
balanceCategories,
1111
investmentsCategories,
12+
investmentsTransactionsCategories,
13+
liabilitiesCategories,
1214
paymentCategories,
1315
assetsCategories,
16+
incomePaystubsCategories,
1417
transferCategories,
1518
transformAuthData,
1619
transformTransactionsData,
1720
transformBalanceData,
1821
transformInvestmentsData,
22+
transformInvestmentTransactionsData,
23+
transformLiabilitiesData,
1924
transformIdentityData,
2025
transformPaymentData,
2126
transformAssetsData,
2227
transformTransferData,
28+
transformIncomePaystubsData,
2329
} from "../../dataUtilities";
2430

2531
const Products = () => {
@@ -81,6 +87,7 @@ const Products = () => {
8187
transformData={transformBalanceData}
8288
/>
8389
{products.includes("investments") && (
90+
<>
8491
<Endpoint
8592
endpoint="holdings"
8693
name="Investments"
@@ -89,8 +96,26 @@ const Products = () => {
8996
description="Retrieve investment holdings on file with the bank,
9097
brokerage, or investment institution. Analyze over-exposure
9198
to market segments."
92-
transformData={transformInvestmentsData}
93-
/>
99+
transformData={transformInvestmentsData}
100+
/>
101+
<Endpoint
102+
endpoint="investments_transactions"
103+
name="Investments Transactions"
104+
categories={investmentsTransactionsCategories}
105+
schema="/investments/transactions/get"
106+
description="Retrieve investment transactions on file with the bank,
107+
brokerage, or investments institution."
108+
transformData={transformInvestmentTransactionsData}
109+
/>
110+
<Endpoint
111+
endpoint="liabilities"
112+
name="Liabilities"
113+
categories={liabilitiesCategories}
114+
schema="/liabilities/get"
115+
description="Retrieve liabilities and various details about an Item with loan or credit accounts."
116+
transformData={transformLiabilitiesData}
117+
/>
118+
</>
94119
)}
95120
{products.includes("transfer") && (
96121
<Endpoint
@@ -102,6 +127,16 @@ const Products = () => {
102127
transformData={transformTransferData}
103128
/>
104129
)}
130+
{products.includes("income_verification") && (
131+
<Endpoint
132+
endpoint="/income/verification/paystubs"
133+
name="Income Paystubs"
134+
categories={incomePaystubsCategories}
135+
schema="/income/verification/paystubs"
136+
description="(Deprecated) Retrieve information from the paystubs used for income verification"
137+
transformData={transformIncomePaystubsData}
138+
/>
139+
)}
105140
</ProductTypesContainer>
106141
);
107142
};

frontend/src/dataUtilities.ts

+106-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
TransactionsGetResponse,
44
IdentityGetResponse,
55
InvestmentsHoldingsGetResponse,
6+
InvestmentsTransactionsGetResponse,
67
AccountsGetResponse,
78
ItemGetResponse,
89
InstitutionsGetByIdResponse,
@@ -11,6 +12,9 @@ import {
1112
AssetReportGetResponse,
1213
AssetReport,
1314
TransferGetResponse,
15+
IncomeVerificationPaystubsGetResponse,
16+
Paystub,
17+
Earnings,
1418
} from "plaid/dist/api";
1519

1620
const formatCurrency = (
@@ -63,6 +67,12 @@ interface InvestmentsDataItem {
6367
name: string;
6468
}
6569

70+
interface InvestmentsTransactionItem {
71+
amount: number;
72+
date: string;
73+
name: string;
74+
}
75+
6676
interface LiabilitiessDataItem {
6777
amount: string;
6878
date: string;
@@ -98,6 +108,12 @@ interface TransferDataItem {
98108
network: string;
99109
}
100110

111+
interface IncomePaystubsDataItem {
112+
description: string;
113+
currentAmount: number | null;
114+
currency: number | null;
115+
}
116+
101117
export interface ErrorDataItem {
102118
error_type: string;
103119
error_code: string;
@@ -113,11 +129,13 @@ export type DataItem =
113129
| IdentityDataItem
114130
| BalanceDataItem
115131
| InvestmentsDataItem
132+
| InvestmentsTransactionItem
116133
| LiabilitiessDataItem
117134
| ItemDataItem
118135
| PaymentDataItem
119136
| AssetsDataItem
120-
| TransferDataItem;
137+
| TransferDataItem
138+
| IncomePaystubsDataItem;
121139

122140
export type Data = Array<DataItem>;
123141

@@ -216,6 +234,21 @@ export const investmentsCategories: Array<Categories> = [
216234
},
217235
];
218236

237+
export const investmentsTransactionsCategories: Array<Categories> = [
238+
{
239+
title: "Name",
240+
field: "name",
241+
},
242+
{
243+
title: "Amount",
244+
field: "amount",
245+
},
246+
{
247+
title: "Date",
248+
field: "date",
249+
},
250+
];
251+
219252
export const liabilitiesCategories: Array<Categories> = [
220253
{
221254
title: "Name",
@@ -338,6 +371,21 @@ export const transferCategories: Array<Categories> = [
338371
},
339372
];
340373

374+
export const incomePaystubsCategories: Array<Categories> = [
375+
{
376+
title: "Description",
377+
field: "description",
378+
},
379+
{
380+
title: "Current Amount",
381+
field: "currentAmount",
382+
},
383+
{
384+
title: "Currency",
385+
field: "currency",
386+
}
387+
]
388+
341389
export const transformAuthData = (data: AuthGetResponse) => {
342390
return data.numbers.ach!.map((achNumbers) => {
343391
const account = data.accounts!.filter((a) => {
@@ -458,10 +506,41 @@ export const transformInvestmentsData = (data: InvestmentData) => {
458506
});
459507
};
460508

461-
export const transformLiabilitiesData = (data: LiabilitiesGetResponse) => {
462-
const liabilitiesData = data.liabilities;
509+
interface InvestmentsTransactionData {
510+
error: null;
511+
investments_transactions: InvestmentsTransactionsGetResponse;
512+
}
513+
514+
export const transformInvestmentTransactionsData = (data: InvestmentsTransactionData) => {
515+
const investmentTransactionsData = data.investments_transactions.investment_transactions!.sort(function (a,b) {
516+
if (a.account_id > b.account_id) return 1;
517+
return -1;
518+
});
519+
return investmentTransactionsData.map((investmentTransaction) => {
520+
const security = data.investments_transactions.securities!.filter(
521+
(sec) => sec.security_id === investmentTransaction.security_id
522+
)[0];
523+
524+
const obj: DataItem = {
525+
name: security.name!,
526+
amount: investmentTransaction.amount,
527+
date: investmentTransaction.date,
528+
};
529+
return obj;
530+
});
531+
};
532+
533+
interface LiabilitiesDataResponse {
534+
error: null;
535+
liabilities: LiabilitiesGetResponse;
536+
}
537+
538+
export const transformLiabilitiesData = (data: LiabilitiesDataResponse) => {
539+
const liabilitiesData = data.liabilities.liabilities;
540+
//console.log(liabilitiesData)
541+
//console.log("random")
463542
const credit = liabilitiesData.credit!.map((credit) => {
464-
const account = data.accounts.filter(
543+
const account = data.liabilities.accounts.filter(
465544
(acc) => acc.account_id === credit.account_id
466545
)[0];
467546
const obj: DataItem = {
@@ -477,7 +556,7 @@ export const transformLiabilitiesData = (data: LiabilitiesGetResponse) => {
477556
});
478557

479558
const mortgages = liabilitiesData.mortgage?.map((mortgage) => {
480-
const account = data.accounts.filter(
559+
const account = data.liabilities.accounts.filter(
481560
(acc) => acc.account_id === mortgage.account_id
482561
)[0];
483562
const obj: DataItem = {
@@ -493,7 +572,7 @@ export const transformLiabilitiesData = (data: LiabilitiesGetResponse) => {
493572
});
494573

495574
const student = liabilitiesData.student?.map((student) => {
496-
const account = data.accounts.filter(
575+
const account = data.liabilities.accounts.filter(
497576
(acc) => acc.account_id === student.account_id
498577
)[0];
499578
const obj: DataItem = {
@@ -598,3 +677,24 @@ export const transformAssetsData = (data: AssetResponseData) => {
598677
});
599678
});
600679
};
680+
681+
interface IncomePaystub {
682+
paystubs: IncomeVerificationPaystubsGetResponse,
683+
}
684+
685+
export const transformIncomePaystubsData = (data: IncomePaystub) => {
686+
const paystubsItemsArray: Array<Paystub> = data.paystubs.paystubs
687+
var finalArray: Array<IncomePaystubsDataItem> = []
688+
for (var i = 0; i < paystubsItemsArray.length; i++){
689+
var ActualEarningVariable: any = paystubsItemsArray[i].earnings
690+
for (var j = 0; j < ActualEarningVariable.breakdown.length; j++){
691+
var payStubItem: IncomePaystubsDataItem = {
692+
description: paystubsItemsArray[i].employer.name + '_' + ActualEarningVariable.breakdown[j].description,
693+
currentAmount: ActualEarningVariable.breakdown[j].current_amount,
694+
currency: ActualEarningVariable.breakdown[j].iso_currency_code
695+
}
696+
finalArray.push(payStubItem)
697+
}
698+
}
699+
return finalArray
700+
}

go/server.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func main() {
109109
r.GET("/api/payment", payment)
110110
r.GET("/api/create_public_token", createPublicToken)
111111
r.POST("/api/create_link_token", createLinkToken)
112-
r.GET("/api/investment_transactions", investmentTransactions)
112+
r.GET("/api/investments_transactions", investmentTransactions)
113113
r.GET("/api/holdings", holdings)
114114
r.GET("/api/assets", assets)
115115
r.GET("/api/transfer", transfer)
@@ -395,7 +395,7 @@ func investmentTransactions(c *gin.Context) {
395395
}
396396

397397
c.JSON(http.StatusOK, gin.H{
398-
"investment_transactions": invTxResp,
398+
"investments_transactions": invTxResp,
399399
})
400400
}
401401

java/src/main/java/com/plaid/quickstart/resources/InvestmentTransactionsResource.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import retrofit2.Response;
2020

21-
@Path("/investment_transactions")
21+
@Path("/investments_transactions")
2222
@Produces(MediaType.APPLICATION_JSON)
2323
public class InvestmentTransactionsResource {
2424
private final PlaidApi plaidClient;
@@ -48,10 +48,10 @@ public InvestmentTransactionsResponse getAccounts() throws IOException {
4848

4949
private static class InvestmentTransactionsResponse {
5050
@JsonProperty
51-
private InvestmentsTransactionsGetResponse investmentTransactions;
51+
private InvestmentsTransactionsGetResponse investmentsTransactions;
5252

5353
public InvestmentTransactionsResponse(InvestmentsTransactionsGetResponse investmentTransactions) {
54-
this.investmentTransactions = investmentTransactions;
54+
this.investmentsTransactions = investmentTransactions;
5555
}
5656
}
5757
}

java/src/main/java/com/plaid/quickstart/resources/LinkTokenResource.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import java.util.List;
1515
import java.util.Date;
16+
import java.util.ArrayList;
1617
import java.util.Arrays;
1718

1819
import javax.ws.rs.POST;
@@ -29,13 +30,15 @@ public class LinkTokenResource {
2930
private final List<String> plaidProducts;
3031
private final List<String> countryCodes;
3132
private final String redirectUri;
33+
private final List<Products> correctedPlaidProducts;
3234

3335
public LinkTokenResource(PlaidApi plaidClient, List<String> plaidProducts,
3436
List<String> countryCodes, String redirectUri) {
3537
this.plaidClient = plaidClient;
3638
this.plaidProducts = plaidProducts;
3739
this.countryCodes = countryCodes;
3840
this.redirectUri = redirectUri;
41+
this.correctedPlaidProducts = new ArrayList<>();
3942
}
4043

4144
public static class LinkToken {
@@ -55,10 +58,14 @@ public LinkToken(String linkToken) {
5558
LinkTokenCreateRequestUser user = new LinkTokenCreateRequestUser()
5659
.clientUserId(clientUserId);
5760

61+
for (int i = 0; i < this.plaidProducts.size(); i++){
62+
this.correctedPlaidProducts.add(Products.fromValue(this.plaidProducts.get(i)));
63+
};
64+
5865
LinkTokenCreateRequest request = new LinkTokenCreateRequest()
5966
.user(user)
6067
.clientName("Quickstart Client")
61-
.products(Arrays.asList(Products.AUTH, Products.TRANSACTIONS))
68+
.products(this.correctedPlaidProducts)
6269
.countryCodes(Arrays.asList(CountryCode.US, CountryCode.CA))
6370
.language("en")
6471
.redirectUri(this.redirectUri);

0 commit comments

Comments
 (0)