fix: use Plaid's new API (develop) (#23318)

Co-authored-by: Mangesh-Khairnar <mkhairnar10@gmail.com>
This commit is contained in:
Rohan 2020-09-21 13:14:07 +05:30 committed by GitHub
parent 44c692ed40
commit e42f08085b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 149 additions and 132 deletions

View File

@ -72,7 +72,7 @@ erpnext.accounts.bankReconciliation = class BankReconciliation {
check_plaid_status() { check_plaid_status() {
const me = this; const me = this;
frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => { frappe.db.get_value("Plaid Settings", "Plaid Settings", "enabled", (r) => {
if (r && r.enabled == "1") { if (r && r.enabled === "1") {
me.plaid_status = "active" me.plaid_status = "active"
} else { } else {
me.plaid_status = "inactive" me.plaid_status = "inactive"
@ -139,7 +139,7 @@ erpnext.accounts.bankTransactionUpload = class bankTransactionUpload {
} }
make() { make() {
const me = this; const me = this;
new frappe.ui.FileUploader({ new frappe.ui.FileUploader({
method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement', method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
allow_multiple: 0, allow_multiple: 0,
@ -214,31 +214,35 @@ erpnext.accounts.bankTransactionSync = class bankTransactionSync {
init_config() { init_config() {
const me = this; const me = this;
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.plaid_configuration') frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.get_plaid_configuration')
.then(result => { .then(result => {
me.plaid_env = result.plaid_env; me.plaid_env = result.plaid_env;
me.plaid_public_key = result.plaid_public_key; me.client_name = result.client_name;
me.client_name = result.client_name; me.link_token = result.link_token;
me.sync_transactions() me.sync_transactions();
}) })
} }
sync_transactions() { sync_transactions() {
const me = this; const me = this;
frappe.db.get_value("Bank Account", me.parent.bank_account, "bank", (v) => { frappe.db.get_value("Bank Account", me.parent.bank_account, "bank", (r) => {
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions', { frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions', {
bank: v['bank'], bank: r.bank,
bank_account: me.parent.bank_account, bank_account: me.parent.bank_account,
freeze: true freeze: true
}) })
.then((result) => { .then((result) => {
let result_title = (result.length > 0) ? __("{0} bank transaction(s) created", [result.length]) : __("This bank account is already synchronized") let result_title = (result && result.length > 0)
? __("{0} bank transaction(s) created", [result.length])
: __("This bank account is already synchronized");
let result_msg = ` let result_msg = `
<div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;"> <div class="flex justify-center align-center text-muted" style="height: 50vh; display: flex;">
<h5 class="text-muted">${result_title}</h5> <h5 class="text-muted">${result_title}</h5>
</div>` </div>`
this.parent.$main_section.append(result_msg) this.parent.$main_section.append(result_msg)
frappe.show_alert({message:__("Bank account '{0}' has been synchronized", [me.parent.bank_account]), indicator:'green'}); frappe.show_alert({ message: __("Bank account '{0}' has been synchronized", [me.parent.bank_account]), indicator: 'green' });
}) })
}) })
} }
@ -384,7 +388,7 @@ erpnext.accounts.ReconciliationRow = class ReconciliationRow {
}) })
frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments', frappe.xcall('erpnext.accounts.page.bank_reconciliation.bank_reconciliation.get_linked_payments',
{bank_transaction: data, freeze:true, freeze_message:__("Finding linked payments")} { bank_transaction: data, freeze: true, freeze_message: __("Finding linked payments") }
).then((result) => { ).then((result) => {
me.make_dialog(result) me.make_dialog(result)
}) })

View File

@ -2,81 +2,84 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals import plaid
from frappe import _ import requests
from frappe.utils.password import get_decrypted_password from plaid.errors import APIError, ItemError, InvalidRequestError
from plaid import Client
from plaid.errors import APIError, ItemError
import frappe import frappe
import requests from frappe import _
class PlaidConnector(): class PlaidConnector():
def __init__(self, access_token=None): def __init__(self, access_token=None):
plaid_settings = frappe.get_single("Plaid Settings")
self.config = {
"plaid_client_id": plaid_settings.plaid_client_id,
"plaid_secret": get_decrypted_password("Plaid Settings", "Plaid Settings", 'plaid_secret'),
"plaid_public_key": plaid_settings.plaid_public_key,
"plaid_env": plaid_settings.plaid_env
}
self.client = Client(client_id=self.config.get("plaid_client_id"),
secret=self.config.get("plaid_secret"),
public_key=self.config.get("plaid_public_key"),
environment=self.config.get("plaid_env")
)
self.access_token = access_token self.access_token = access_token
self.settings = frappe.get_single("Plaid Settings")
self.products = ["auth", "transactions"]
self.client_name = frappe.local.site
self.client = plaid.Client(
client_id=self.settings.plaid_client_id,
secret=self.settings.get_password("plaid_secret"),
environment=self.settings.plaid_env,
api_version="2019-05-29"
)
def get_access_token(self, public_token): def get_access_token(self, public_token):
if public_token is None: if public_token is None:
frappe.log_error(_("Public token is missing for this bank"), _("Plaid public token error")) frappe.log_error(_("Public token is missing for this bank"), _("Plaid public token error"))
response = self.client.Item.public_token.exchange(public_token) response = self.client.Item.public_token.exchange(public_token)
access_token = response['access_token'] access_token = response["access_token"]
return access_token return access_token
def get_link_token(self):
token_request = {
"client_name": self.client_name,
"client_id": self.settings.plaid_client_id,
"secret": self.settings.plaid_secret,
"products": self.products,
# only allow Plaid-supported languages and countries (LAST: Sep-19-2020)
"language": frappe.local.lang if frappe.local.lang in ["en", "fr", "es", "nl"] else "en",
"country_codes": ["US", "CA", "FR", "IE", "NL", "ES", "GB"],
"user": {
"client_user_id": frappe.generate_hash(frappe.session.user, length=32)
}
}
try:
response = self.client.LinkToken.create(token_request)
except InvalidRequestError:
frappe.log_error(frappe.get_traceback(), _("Plaid invalid request error"))
frappe.msgprint(_("Please check your Plaid client ID and secret values"))
except APIError as e:
frappe.log_error(frappe.get_traceback(), _("Plaid authentication error"))
frappe.throw(_(str(e)), title=_("Authentication Failed"))
else:
return response["link_token"]
def auth(self): def auth(self):
try: try:
self.client.Auth.get(self.access_token) self.client.Auth.get(self.access_token)
print("Authentication successful.....")
except ItemError as e: except ItemError as e:
if e.code == 'ITEM_LOGIN_REQUIRED': if e.code == "ITEM_LOGIN_REQUIRED":
pass
else:
pass pass
except APIError as e: except APIError as e:
if e.code == 'PLANNED_MAINTENANCE': if e.code == "PLANNED_MAINTENANCE":
pass
else:
pass pass
except requests.Timeout: except requests.Timeout:
pass pass
except Exception as e: except Exception as e:
print(e)
frappe.log_error(frappe.get_traceback(), _("Plaid authentication error")) frappe.log_error(frappe.get_traceback(), _("Plaid authentication error"))
frappe.msgprint({"title": _("Authentication Failed"), "message":e, "raise_exception":1, "indicator":'red'}) frappe.throw(_(str(e)), title=_("Authentication Failed"))
def get_transactions(self, start_date, end_date, account_id=None): def get_transactions(self, start_date, end_date, account_id=None):
self.auth()
account_ids = list(account_id) if account_id else None
try: try:
self.auth() response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, account_ids=account_ids)
if account_id: transactions = response["transactions"]
account_ids = [account_id] while len(transactions) < response["total_transactions"]:
response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, account_ids=account_ids)
else:
response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date)
transactions = response['transactions']
while len(transactions) < response['total_transactions']:
response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, offset=len(transactions)) response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, offset=len(transactions))
transactions.extend(response['transactions']) transactions.extend(response["transactions"])
return transactions return transactions
except Exception: except Exception:
frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error")) frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))

View File

@ -4,14 +4,14 @@
frappe.provide("erpnext.integrations"); frappe.provide("erpnext.integrations");
frappe.ui.form.on('Plaid Settings', { frappe.ui.form.on('Plaid Settings', {
enabled: function(frm) { enabled: function (frm) {
frm.toggle_reqd('plaid_client_id', frm.doc.enabled); frm.toggle_reqd('plaid_client_id', frm.doc.enabled);
frm.toggle_reqd('plaid_secret', frm.doc.enabled); frm.toggle_reqd('plaid_secret', frm.doc.enabled);
frm.toggle_reqd('plaid_public_key', frm.doc.enabled);
frm.toggle_reqd('plaid_env', frm.doc.enabled); frm.toggle_reqd('plaid_env', frm.doc.enabled);
}, },
refresh: function(frm) {
if(frm.doc.enabled) { refresh: function (frm) {
if (frm.doc.enabled) {
frm.add_custom_button('Link a new bank account', () => { frm.add_custom_button('Link a new bank account', () => {
new erpnext.integrations.plaidLink(frm); new erpnext.integrations.plaidLink(frm);
}); });
@ -22,17 +22,16 @@ frappe.ui.form.on('Plaid Settings', {
erpnext.integrations.plaidLink = class plaidLink { erpnext.integrations.plaidLink = class plaidLink {
constructor(parent) { constructor(parent) {
this.frm = parent; this.frm = parent;
this.product = ["transactions", "auth"];
this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js'; this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js';
this.init_config(); this.init_config();
} }
init_config() { async init_config() {
const me = this; this.product = ["auth", "transactions"];
me.plaid_env = me.frm.doc.plaid_env; this.plaid_env = this.frm.doc.plaid_env;
me.plaid_public_key = me.frm.doc.plaid_public_key; this.client_name = frappe.boot.sitename;
me.client_name = frappe.boot.sitename; this.token = await this.frm.call("get_link_token").then(resp => resp.message);
me.init_plaid(); this.init_plaid();
} }
init_plaid() { init_plaid() {
@ -69,17 +68,17 @@ erpnext.integrations.plaidLink = class plaidLink {
} }
onScriptLoaded(me) { onScriptLoaded(me) {
me.linkHandler = window.Plaid.create({ me.linkHandler = Plaid.create({
clientName: me.client_name, clientName: me.client_name,
product: me.product,
env: me.plaid_env, env: me.plaid_env,
key: me.plaid_public_key, token: me.token,
onSuccess: me.plaid_success, onSuccess: me.plaid_success
product: me.product
}); });
} }
onScriptError(error) { onScriptError(error) {
frappe.msgprint('There was an issue loading the link-initialize.js script'); frappe.msgprint("There was an issue connecting to Plaid's authentication server");
frappe.msgprint(error); frappe.msgprint(error);
} }
@ -87,21 +86,25 @@ erpnext.integrations.plaidLink = class plaidLink {
const me = this; const me = this;
frappe.prompt({ frappe.prompt({
fieldtype:"Link", fieldtype: "Link",
options: "Company", options: "Company",
label:__("Company"), label: __("Company"),
fieldname:"company", fieldname: "company",
reqd:1 reqd: 1
}, (data) => { }, (data) => {
me.company = data.company; me.company = data.company;
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_institution', {token: token, response: response}) frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_institution', {
.then((result) => { token: token,
frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_bank_accounts', {response: response, response: response
bank: result, company: me.company}); }).then((result) => {
}) frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_bank_accounts', {
.then(() => { response: response,
frappe.show_alert({message:__("Bank accounts added"), indicator:'green'}); bank: result,
company: me.company
}); });
}).then(() => {
frappe.show_alert({ message: __("Bank accounts added"), indicator: 'green' });
});
}, __("Select a company"), __("Continue")); }, __("Select a company"), __("Continue"));
} }
}; };

View File

@ -1,5 +1,4 @@
{ {
"actions": [],
"creation": "2018-10-25 10:02:48.656165", "creation": "2018-10-25 10:02:48.656165",
"doctype": "DocType", "doctype": "DocType",
"editable_grid": 1, "editable_grid": 1,
@ -12,7 +11,6 @@
"plaid_client_id", "plaid_client_id",
"plaid_secret", "plaid_secret",
"column_break_7", "column_break_7",
"plaid_public_key",
"plaid_env" "plaid_env"
], ],
"fields": [ "fields": [
@ -41,12 +39,6 @@
"in_list_view": 1, "in_list_view": 1,
"label": "Plaid Secret" "label": "Plaid Secret"
}, },
{
"fieldname": "plaid_public_key",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Plaid Public Key"
},
{ {
"fieldname": "plaid_env", "fieldname": "plaid_env",
"fieldtype": "Select", "fieldtype": "Select",
@ -69,8 +61,7 @@
} }
], ],
"issingle": 1, "issingle": 1,
"links": [], "modified": "2020-09-12 02:31:44.542385",
"modified": "2020-02-07 15:21:11.616231",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "ERPNext Integrations", "module": "ERPNext Integrations",
"name": "Plaid Settings", "name": "Plaid Settings",

View File

@ -2,30 +2,36 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import json import json
from frappe import _
from frappe.model.document import Document import frappe
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_connector import PlaidConnector from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_connector import PlaidConnector
from frappe.utils import getdate, formatdate, today, add_months from frappe import _
from frappe.desk.doctype.tag.tag import add_tag from frappe.desk.doctype.tag.tag import add_tag
from frappe.model.document import Document
from frappe.utils import add_months, formatdate, getdate, today
class PlaidSettings(Document): class PlaidSettings(Document):
pass @staticmethod
def get_link_token():
plaid = PlaidConnector()
return plaid.get_link_token()
@frappe.whitelist() @frappe.whitelist()
def plaid_configuration(): def get_plaid_configuration():
if frappe.db.get_single_value("Plaid Settings", "enabled"): if frappe.db.get_single_value("Plaid Settings", "enabled"):
plaid_settings = frappe.get_single("Plaid Settings") plaid_settings = frappe.get_single("Plaid Settings")
return { return {
"plaid_public_key": plaid_settings.plaid_public_key,
"plaid_env": plaid_settings.plaid_env, "plaid_env": plaid_settings.plaid_env,
"link_token": plaid_settings.get_link_token(),
"client_name": frappe.local.site "client_name": frappe.local.site
} }
else:
return "disabled" return "disabled"
@frappe.whitelist() @frappe.whitelist()
def add_institution(token, response): def add_institution(token, response):
@ -33,6 +39,7 @@ def add_institution(token, response):
plaid = PlaidConnector() plaid = PlaidConnector()
access_token = plaid.get_access_token(token) access_token = plaid.get_access_token(token)
bank = None
if not frappe.db.exists("Bank", response["institution"]["name"]): if not frappe.db.exists("Bank", response["institution"]["name"]):
try: try:
@ -44,7 +51,6 @@ def add_institution(token, response):
bank.insert() bank.insert()
except Exception: except Exception:
frappe.throw(frappe.get_traceback()) frappe.throw(frappe.get_traceback())
else: else:
bank = frappe.get_doc("Bank", response["institution"]["name"]) bank = frappe.get_doc("Bank", response["institution"]["name"])
bank.plaid_access_token = access_token bank.plaid_access_token = access_token
@ -52,6 +58,7 @@ def add_institution(token, response):
return bank return bank
@frappe.whitelist() @frappe.whitelist()
def add_bank_accounts(response, bank, company): def add_bank_accounts(response, bank, company):
try: try:
@ -92,9 +99,8 @@ def add_bank_accounts(response, bank, company):
new_account.insert() new_account.insert()
result.append(new_account.name) result.append(new_account.name)
except frappe.UniqueValidationError: except frappe.UniqueValidationError:
frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(new_account.account_name)) frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(account["name"]))
except Exception: except Exception:
frappe.throw(frappe.get_traceback()) frappe.throw(frappe.get_traceback())
@ -103,6 +109,7 @@ def add_bank_accounts(response, bank, company):
return result return result
def add_account_type(account_type): def add_account_type(account_type):
try: try:
frappe.get_doc({ frappe.get_doc({
@ -122,10 +129,11 @@ def add_account_subtype(account_subtype):
except Exception: except Exception:
frappe.throw(frappe.get_traceback()) frappe.throw(frappe.get_traceback())
@frappe.whitelist() @frappe.whitelist()
def sync_transactions(bank, bank_account): def sync_transactions(bank, bank_account):
'''Sync transactions based on the last integration date as the start date, after the sync is completed """Sync transactions based on the last integration date as the start date, after sync is completed
add the transaction date of the oldest transaction as the last integration date''' add the transaction date of the oldest transaction as the last integration date."""
last_transaction_date = frappe.db.get_value("Bank Account", bank_account, "last_integration_date") last_transaction_date = frappe.db.get_value("Bank Account", bank_account, "last_integration_date")
if last_transaction_date: if last_transaction_date:
start_date = formatdate(last_transaction_date, "YYYY-MM-dd") start_date = formatdate(last_transaction_date, "YYYY-MM-dd")
@ -147,10 +155,10 @@ def sync_transactions(bank, bank_account):
len(result), bank_account, start_date, end_date)) len(result), bank_account, start_date, end_date))
frappe.db.set_value("Bank Account", bank_account, "last_integration_date", last_transaction_date) frappe.db.set_value("Bank Account", bank_account, "last_integration_date", last_transaction_date)
except Exception: except Exception:
frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error")) frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
def get_transactions(bank, bank_account=None, start_date=None, end_date=None): def get_transactions(bank, bank_account=None, start_date=None, end_date=None):
access_token = None access_token = None
@ -168,6 +176,7 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None):
return transactions return transactions
def new_bank_transaction(transaction): def new_bank_transaction(transaction):
result = [] result = []
@ -182,8 +191,8 @@ def new_bank_transaction(transaction):
status = "Pending" if transaction["pending"] == "True" else "Settled" status = "Pending" if transaction["pending"] == "True" else "Settled"
tags = []
try: try:
tags = []
tags += transaction["category"] tags += transaction["category"]
tags += ["Plaid Cat. {}".format(transaction["category_id"])] tags += ["Plaid Cat. {}".format(transaction["category_id"])]
except KeyError: except KeyError:
@ -216,6 +225,7 @@ def new_bank_transaction(transaction):
return result return result
def automatic_synchronization(): def automatic_synchronization():
settings = frappe.get_doc("Plaid Settings", "Plaid Settings") settings = frappe.get_doc("Plaid Settings", "Plaid Settings")
@ -223,4 +233,8 @@ def automatic_synchronization():
plaid_accounts = frappe.get_all("Bank Account", filters={"integration_id": ["!=", ""]}, fields=["name", "bank"]) plaid_accounts = frappe.get_all("Bank Account", filters={"integration_id": ["!=", ""]}, fields=["name", "bank"])
for plaid_account in plaid_accounts: for plaid_account in plaid_accounts:
frappe.enqueue("erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions", bank=plaid_account.bank, bank_account=plaid_account.name) frappe.enqueue(
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.sync_transactions",
bank=plaid_account.bank,
bank_account=plaid_account.name
)

View File

@ -1,14 +1,17 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt # See license.txt
from __future__ import unicode_literals
import unittest
import frappe
from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings import plaid_configuration, add_account_type, add_account_subtype, new_bank_transaction, add_bank_accounts
import json import json
from frappe.utils.response import json_handler import unittest
import frappe
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
from erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings import (
add_account_subtype, add_account_type, add_bank_accounts,
new_bank_transaction, get_plaid_configuration)
from frappe.utils.response import json_handler
class TestPlaidSettings(unittest.TestCase): class TestPlaidSettings(unittest.TestCase):
def setUp(self): def setUp(self):
@ -31,7 +34,7 @@ class TestPlaidSettings(unittest.TestCase):
def test_plaid_disabled(self): def test_plaid_disabled(self):
frappe.db.set_value("Plaid Settings", None, "enabled", 0) frappe.db.set_value("Plaid Settings", None, "enabled", 0)
self.assertTrue(plaid_configuration() == "disabled") self.assertTrue(get_plaid_configuration() == "disabled")
def test_add_account_type(self): def test_add_account_type(self):
add_account_type("brokerage") add_account_type("brokerage")
@ -64,7 +67,7 @@ class TestPlaidSettings(unittest.TestCase):
'mask': '0000', 'mask': '0000',
'id': '6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK', 'id': '6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK',
'name': 'Plaid Checking' 'name': 'Plaid Checking'
}], }],
'institution': { 'institution': {
'institution_id': 'ins_6', 'institution_id': 'ins_6',
'name': 'Citi' 'name': 'Citi'
@ -100,7 +103,7 @@ class TestPlaidSettings(unittest.TestCase):
'mask': '0000', 'mask': '0000',
'id': '6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK', 'id': '6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK',
'name': 'Plaid Checking' 'name': 'Plaid Checking'
}], }],
'institution': { 'institution': {
'institution_id': 'ins_6', 'institution_id': 'ins_6',
'name': 'Citi' 'name': 'Citi'
@ -152,4 +155,4 @@ class TestPlaidSettings(unittest.TestCase):
new_bank_transaction(transactions) new_bank_transaction(transactions)
self.assertTrue(len(frappe.get_all("Bank Transaction")) == 1) self.assertTrue(len(frappe.get_all("Bank Transaction")) == 1)

View File

@ -4,17 +4,16 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
def execute(): def execute():
frappe.reload_doc("erpnext_integrations", "doctype", "plaid_settings") frappe.reload_doc("erpnext_integrations", "doctype", "plaid_settings")
plaid_settings = frappe.get_single("Plaid Settings") plaid_settings = frappe.get_single("Plaid Settings")
if plaid_settings.enabled: if plaid_settings.enabled:
if not (frappe.conf.plaid_client_id and frappe.conf.plaid_env \ if not (frappe.conf.plaid_client_id and frappe.conf.plaid_env and frappe.conf.plaid_secret):
and frappe.conf.plaid_public_key and frappe.conf.plaid_secret):
plaid_settings.enabled = 0 plaid_settings.enabled = 0
else: else:
plaid_settings.update({ plaid_settings.update({
"plaid_client_id": frappe.conf.plaid_client_id, "plaid_client_id": frappe.conf.plaid_client_id,
"plaid_public_key": frappe.conf.plaid_public_key,
"plaid_env": frappe.conf.plaid_env, "plaid_env": frappe.conf.plaid_env,
"plaid_secret": frappe.conf.plaid_secret "plaid_secret": frappe.conf.plaid_secret
}) })

View File

@ -3,7 +3,7 @@ frappe
gocardless-pro==1.11.0 gocardless-pro==1.11.0
googlemaps==3.1.1 googlemaps==3.1.1
pandas==1.0.5 pandas==1.0.5
plaid-python==3.4.0 plaid-python==6.0.0
pycountry==19.8.18 pycountry==19.8.18
PyGithub==1.44.1 PyGithub==1.44.1
python-stdnum==1.12 python-stdnum==1.12