fix(plaid): cannot reset plaid link for a bank account
This commit is contained in:
		
							parent
							
								
									17736afab5
								
							
						
					
					
						commit
						d24eccd623
					
				| @ -25,6 +25,10 @@ frappe.ui.form.on('Bank', { | |||||||
| 			frm.add_custom_button(__('Refresh Plaid Link'), () => { | 			frm.add_custom_button(__('Refresh Plaid Link'), () => { | ||||||
| 				new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token); | 				new erpnext.integrations.refreshPlaidLink(frm.doc.plaid_access_token); | ||||||
| 			}); | 			}); | ||||||
|  | 
 | ||||||
|  | 			frm.add_custom_button(__('Reset Plaid Link'), () => { | ||||||
|  | 				new erpnext.integrations.plaidLink(frm); | ||||||
|  | 			}); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| @ -121,3 +125,101 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink { | |||||||
| 		frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' }); | 		frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' }); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | erpnext.integrations.plaidLink = class plaidLink { | ||||||
|  | 	constructor(parent) { | ||||||
|  | 		this.frm = parent; | ||||||
|  | 		this.plaidUrl = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js'; | ||||||
|  | 		this.init_config(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	async init_config() { | ||||||
|  | 		this.product = ["auth", "transactions"]; | ||||||
|  | 		this.plaid_env = this.frm.doc.plaid_env; | ||||||
|  | 		this.client_name = frappe.boot.sitename; | ||||||
|  | 		this.token = await this.get_link_token(); | ||||||
|  | 		this.init_plaid(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	async get_link_token() { | ||||||
|  | 		const token = await this.frm.call("get_link_token").then(resp => resp.message); | ||||||
|  | 		if (!token) { | ||||||
|  | 			frappe.throw(__('Cannot retrieve link token. Check Error Log for more information')); | ||||||
|  | 		} | ||||||
|  | 		return token; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	init_plaid() { | ||||||
|  | 		const me = this; | ||||||
|  | 		me.loadScript(me.plaidUrl) | ||||||
|  | 			.then(() => { | ||||||
|  | 				me.onScriptLoaded(me); | ||||||
|  | 			}) | ||||||
|  | 			.then(() => { | ||||||
|  | 				if (me.linkHandler) { | ||||||
|  | 					me.linkHandler.open(); | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 			.catch((error) => { | ||||||
|  | 				me.onScriptError(error); | ||||||
|  | 			}); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	loadScript(src) { | ||||||
|  | 		return new Promise(function (resolve, reject) { | ||||||
|  | 			if (document.querySelector('script[src="' + src + '"]')) { | ||||||
|  | 				resolve(); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 			const el = document.createElement('script'); | ||||||
|  | 			el.type = 'text/javascript'; | ||||||
|  | 			el.async = true; | ||||||
|  | 			el.src = src; | ||||||
|  | 			el.addEventListener('load', resolve); | ||||||
|  | 			el.addEventListener('error', reject); | ||||||
|  | 			el.addEventListener('abort', reject); | ||||||
|  | 			document.head.appendChild(el); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	onScriptLoaded(me) { | ||||||
|  | 		me.linkHandler = Plaid.create({ | ||||||
|  | 			clientName: me.client_name, | ||||||
|  | 			product: me.product, | ||||||
|  | 			env: me.plaid_env, | ||||||
|  | 			token: me.token, | ||||||
|  | 			onSuccess: me.plaid_success | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	onScriptError(error) { | ||||||
|  | 		frappe.msgprint(__("There was an issue connecting to Plaid's authentication server. Check browser console for more information")); | ||||||
|  | 		console.log(error); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	plaid_success(token, response) { | ||||||
|  | 		const me = this; | ||||||
|  | 
 | ||||||
|  | 		frappe.prompt({ | ||||||
|  | 			fieldtype: "Link", | ||||||
|  | 			options: "Company", | ||||||
|  | 			label: __("Company"), | ||||||
|  | 			fieldname: "company", | ||||||
|  | 			reqd: 1 | ||||||
|  | 		}, (data) => { | ||||||
|  | 			me.company = data.company; | ||||||
|  | 			frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_institution', { | ||||||
|  | 				token: token, | ||||||
|  | 				response: response | ||||||
|  | 			}).then((result) => { | ||||||
|  | 				frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.add_bank_accounts', { | ||||||
|  | 					response: response, | ||||||
|  | 					bank: result, | ||||||
|  | 					company: me.company | ||||||
|  | 				}); | ||||||
|  | 			}).then(() => { | ||||||
|  | 				frappe.show_alert({ message: __("Bank accounts added"), indicator: 'green' }); | ||||||
|  | 			}); | ||||||
|  | 		}, __("Select a company"), __("Continue")); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | |||||||
| @ -99,5 +99,7 @@ class PlaidConnector(): | |||||||
| 				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 ItemError as e: | ||||||
|  | 			raise e | ||||||
| 		except Exception: | 		except Exception: | ||||||
| 			frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error")) | 			frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error")) | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ from frappe.desk.doctype.tag.tag import add_tag | |||||||
| from frappe.model.document import Document | from frappe.model.document import Document | ||||||
| from frappe.utils import add_months, formatdate, getdate, today | from frappe.utils import add_months, formatdate, getdate, today | ||||||
| 
 | 
 | ||||||
|  | from plaid.errors import ItemError | ||||||
| 
 | 
 | ||||||
| class PlaidSettings(Document): | class PlaidSettings(Document): | ||||||
| 	@staticmethod | 	@staticmethod | ||||||
| @ -51,7 +52,7 @@ def add_institution(token, response): | |||||||
| 			}) | 			}) | ||||||
| 			bank.insert() | 			bank.insert() | ||||||
| 		except Exception: | 		except Exception: | ||||||
| 			frappe.throw(frappe.get_traceback()) | 			frappe.log_error(frappe.get_traceback(), title=_('Plaid Link Error')) | ||||||
| 	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 | ||||||
| @ -83,7 +84,12 @@ def add_bank_accounts(response, bank, company): | |||||||
| 		if not acc_subtype: | 		if not acc_subtype: | ||||||
| 			add_account_subtype(account["subtype"]) | 			add_account_subtype(account["subtype"]) | ||||||
| 
 | 
 | ||||||
| 		if not frappe.db.exists("Bank Account", dict(integration_id=account["id"])): | 		existing_bank_account = frappe.db.exists("Bank Account", { | ||||||
|  | 			'account_name': account["name"], | ||||||
|  | 			'bank': bank["bank_name"] | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		if not existing_bank_account: | ||||||
| 			try: | 			try: | ||||||
| 				new_account = frappe.get_doc({ | 				new_account = frappe.get_doc({ | ||||||
| 					"doctype": "Bank Account", | 					"doctype": "Bank Account", | ||||||
| @ -103,10 +109,27 @@ def add_bank_accounts(response, bank, company): | |||||||
| 			except frappe.UniqueValidationError: | 			except frappe.UniqueValidationError: | ||||||
| 				frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(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.log_error(frappe.get_traceback(), title=_("Plaid Link Error")) | ||||||
|  | 				frappe.throw(_("There was an error creating Bank Account while linking with Plaid."),  | ||||||
|  | 					title=_("Plaid Link Failed")) | ||||||
| 
 | 
 | ||||||
| 		else: | 		else: | ||||||
| 			result.append(frappe.db.get_value("Bank Account", dict(integration_id=account["id"]), "name")) | 			try: | ||||||
|  | 				existing_account = frappe.get_doc('Bank Account', existing_bank_account) | ||||||
|  | 				existing_account.update({ | ||||||
|  | 					"bank": bank["bank_name"], | ||||||
|  | 					"account_name": account["name"], | ||||||
|  | 					"account_type": account.get("type", ""), | ||||||
|  | 					"account_subtype": account.get("subtype", ""), | ||||||
|  | 					"mask": account.get("mask", ""), | ||||||
|  | 					"integration_id": account["id"] | ||||||
|  | 				}) | ||||||
|  | 				existing_account.save() | ||||||
|  | 				result.append(existing_bank_account) | ||||||
|  | 			except Exception: | ||||||
|  | 				frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error")) | ||||||
|  | 				frappe.throw(_("There was an error updating Bank Account {} while linking with Plaid.").format( | ||||||
|  | 					existing_bank_account), title=_("Plaid Link Failed")) | ||||||
| 
 | 
 | ||||||
| 	return result | 	return result | ||||||
| 
 | 
 | ||||||
| @ -172,9 +195,16 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None): | |||||||
| 		account_id = None | 		account_id = None | ||||||
| 
 | 
 | ||||||
| 	plaid = PlaidConnector(access_token) | 	plaid = PlaidConnector(access_token) | ||||||
| 	transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id) |  | ||||||
| 
 | 
 | ||||||
| 	return transactions | 	try: | ||||||
|  | 		transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id) | ||||||
|  | 	except ItemError as e: | ||||||
|  | 		if e.code == "ITEM_LOGIN_REQUIRED": | ||||||
|  | 			msg = _("There was an error syncing transactions.") + " " | ||||||
|  | 			msg += _("Please refresh or reset the Plaid linking of the Bank {}.").format(bank) + " " | ||||||
|  | 			frappe.log_error(msg, title=_("Plaid Link Refresh Required")) | ||||||
|  | 
 | ||||||
|  | 	return transactions or [] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def new_bank_transaction(transaction): | def new_bank_transaction(transaction): | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user