-
-
Notifications
You must be signed in to change notification settings - Fork 526
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1d814c3
commit 4b82e99
Showing
41 changed files
with
13,095 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
===================== | ||
Account Payment Plaid | ||
===================== | ||
|
||
.. | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! This file is generated by oca-gen-addon-readme !! | ||
!! changes will be overwritten. !! | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! source digest: sha256:815525549c46556e7fa6a37a49653162624972fbba8a8888ed314f8841007cba | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png | ||
:target: https://odoo-community.org/page/development-status | ||
:alt: Beta | ||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fbank--payment-lightgray.png?logo=github | ||
:target: https://github.com/OCA/bank-payment/tree/14.0/account_payment_plaid | ||
:alt: OCA/bank-payment | ||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png | ||
:target: https://translation.odoo-community.org/projects/bank-payment-14-0/bank-payment-14-0-account_payment_plaid | ||
:alt: Translate me on Weblate | ||
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png | ||
:target: https://runboat.odoo-community.org/builds?repo=OCA/bank-payment&target_branch=14.0 | ||
:alt: Try me on Runboat | ||
|
||
|badge1| |badge2| |badge3| |badge4| |badge5| | ||
|
||
This addon allow pay your bills with plaid platform using the ACH transfer method. | ||
Do you need plaid account for use this module. | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
:local: | ||
|
||
Usage | ||
===== | ||
|
||
Using the Plaid API for bank transfers on production or development environment: | ||
|
||
#. Go to "Settings" > "Plaid". | ||
#. Add your Plaid credentials. | ||
#. Synchronize with Plaid. | ||
#. Select your bank account. | ||
#. Go to "Contacts" and add the plaid client id for the contact. | ||
#. Go to your invoice and click on "Pay with Plaid" button.\nYou can see the button if the bill is confirmed.\nWhen you click on the button, you will see a confirmation window. | ||
#. When you confirm the payment and the confirmation window\nis closed you can see the transfer in "Settings" > "Technical" > "Plaid" > "Transfer". | ||
#. When the transfer is done, you can see the bill as paid and the payment create on odoo. | ||
|
||
If you are using the sandbox environment for testing, | ||
do you need to use the simulation method for simulate the transfer. | ||
This method only works with the sandbox environment. | ||
You can found this method on "Settings" > "Technical" > "Plaid" > "Transfer". | ||
|
||
#. Select the transfer that you want to simulate. | ||
#. Click on "Simulate Transfer" button. | ||
#. Select the command that you want to simulate. | ||
* "Simulate Transfer" : This command create a event on sandbox environment.\nDo you need this event for check the status of the transfer on Odoo. | ||
* "Simulate transfer ledger available" : This command simulate converting pending balance\nto available balance for all originators in the Sandbox environment. | ||
#. Click on "Confirm" button. | ||
|
||
This addon use the cron for check the status of the transfer on Plaid and update the bill and payment. | ||
If you need more information about Plaid, please visit the `Plaid website <https://plaid.com>`_ or `Plaid Docs Transfer <https://plaid.com/docs/transfer/>`_. | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-payment/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us to smash it by providing a detailed and welcomed | ||
`feedback <https://github.com/OCA/bank-payment/issues/new?body=module:%20account_payment_plaid%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
||
Do not contact contributors directly about support or help with technical issues. | ||
|
||
Credits | ||
======= | ||
|
||
Authors | ||
~~~~~~~ | ||
|
||
* Binhex | ||
|
||
Contributors | ||
~~~~~~~~~~~~ | ||
|
||
* `Binhex <https://binhex.cloud>_` | ||
|
||
* Adasat Torres de León <[email protected]> | ||
|
||
Maintainers | ||
~~~~~~~~~~~ | ||
|
||
This module is maintained by the OCA. | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
mission is to support the collaborative development of Odoo features and | ||
promote its widespread use. | ||
|
||
This module is part of the `OCA/bank-payment <https://github.com/OCA/bank-payment/tree/14.0/account_payment_plaid>`_ project on GitHub. | ||
|
||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import wizard | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Copyright 2024 Binhex - Adasat Torres de León. | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
{ | ||
"name": "Account Payment Plaid", | ||
"version": "14.0.1.0.0", | ||
"category": "Connector", | ||
"website": "https://github.com/OCA/bank-payment", | ||
"author": "Binhex, Odoo Community Association (OCA)", | ||
"license": "AGPL-3", | ||
"depends": ["base", "account", "purchase"], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"views/assets.xml", | ||
"views/account_move_views.xml", | ||
"views/res_partner_views.xml", | ||
"views/res_config_settings_views.xml", | ||
"views/plaid_account_views.xml", | ||
"views/plaid_transfer_views.xml", | ||
"wizard/account_payment_plaid_wizard_views.xml", | ||
"wizard/plaid_transfer_sandbox_simulation_wizard_views.xml", | ||
"data/sync_transfer_events_cron.xml", | ||
"data/payment_method_data.xml", | ||
], | ||
"external_dependencies": { | ||
"python": ["plaid-python"], | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<odoo> | ||
<data> | ||
<record id="account_payment_method_plaid_out" model="account.payment.method"> | ||
<field name="name">Plaid</field> | ||
<field name="code">plaid</field> | ||
<field name="payment_type">outbound</field> | ||
</record> | ||
</data> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<odoo> | ||
<data> | ||
<record id="plaid_sync_transfer_cron" model="ir.cron"> | ||
<field name="name">Sync Transfer Events</field> | ||
<field name="model_id" ref="model_plaid_transfer" /> | ||
<field name="interval_number">1</field> | ||
<field name="interval_type">minutes</field> | ||
<field name="numbercall">-1</field> | ||
<field name="state">code</field> | ||
<field name="code"> | ||
model.cron_sync_transfer_events() | ||
</field> | ||
</record> | ||
</data> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from . import plaid_interface | ||
from . import plaid_account | ||
from . import plaid_transfer | ||
from . import res_company | ||
from . import res_config_settings | ||
from . import res_partner | ||
from . import account_move |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from odoo import _, models | ||
|
||
|
||
class AccountMove(models.Model): | ||
|
||
_inherit = "account.move" | ||
|
||
def action_payment_with_plaid_wizard(self): | ||
return { | ||
"type": "ir.actions.act_window", | ||
"name": _("Payment with Plaid"), | ||
"res_model": "account.payment.plaid.wizard", | ||
"view_mode": "form", | ||
"view_type": "form", | ||
"context": { | ||
"default_partner_id": self.partner_id.id, | ||
"default_account_move_id": self.id, | ||
"default_amount": self.amount_total, | ||
"default_currency_id": self.currency_id.id, | ||
"default_description": self.name, | ||
"default_company_id": self.company_id.id, | ||
}, | ||
"target": "new", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from odoo import fields, models | ||
|
||
|
||
class PlaidAccount(models.Model): | ||
_name = "plaid.account" | ||
|
||
name = fields.Char(string="Name", required=True) | ||
account = fields.Char(string="Account ID", required=True) | ||
currency_id = fields.Many2one("res.currency", string="Currency") | ||
official_name = fields.Char(string="Official Name") | ||
type = fields.Char(string="Type") | ||
mask = fields.Char(string="Mask") | ||
subtype = fields.Char(string="Subtype") | ||
company_id = fields.Many2one( | ||
comodel_name="res.company", default=lambda self: self.env.company.id | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
# Copyright 2024 Binhex - Adasat Torres de León. | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
import logging | ||
|
||
from odoo import _, models | ||
from odoo.exceptions import ValidationError | ||
|
||
_logger = logging.getLogger(__name__) | ||
try: | ||
import plaid | ||
from plaid.api import plaid_api | ||
from plaid.model.accounts_get_request import AccountsGetRequest | ||
from plaid.model.ach_class import ACHClass | ||
from plaid.model.country_code import CountryCode | ||
from plaid.model.item_public_token_exchange_request import ( | ||
ItemPublicTokenExchangeRequest, | ||
) | ||
from plaid.model.link_token_create_request import LinkTokenCreateRequest | ||
from plaid.model.link_token_create_request_user import LinkTokenCreateRequestUser | ||
from plaid.model.products import Products | ||
from plaid.model.sandbox_transfer_simulate_request import ( | ||
SandboxTransferSimulateRequest, | ||
) | ||
from plaid.model.transfer_authorization_create_request import ( | ||
TransferAuthorizationCreateRequest, | ||
) | ||
from plaid.model.transfer_authorization_user_in_request import ( | ||
TransferAuthorizationUserInRequest, | ||
) | ||
from plaid.model.transfer_create_request import TransferCreateRequest | ||
from plaid.model.transfer_event_sync_request import TransferEventSyncRequest | ||
from plaid.model.transfer_failure import TransferFailure | ||
from plaid.model.transfer_network import TransferNetwork | ||
from plaid.model.transfer_type import TransferType | ||
except (ImportError, IOError) as err: | ||
_logger.debug(err) | ||
|
||
|
||
class PlaidInterface(models.AbstractModel): | ||
_name = "plaid.interface" | ||
_description = "Plaid Interface" | ||
|
||
def _get_host(self, host): | ||
if host == "devel": | ||
return plaid.Environment.Development | ||
if host == "sand": | ||
return plaid.Environment.Sandbox | ||
if host == "prod": | ||
return plaid.Environment.Production | ||
return False | ||
|
||
def _client(self, client_id, secret, host): | ||
configuration = plaid.Configuration( | ||
host=self._get_host(host), | ||
api_key={ | ||
"clientId": client_id or "", | ||
"secret": secret or "", | ||
}, | ||
) | ||
try: | ||
return plaid_api.PlaidApi(plaid.ApiClient(configuration)) | ||
except plaid.ApiException as e: | ||
raise ValidationError(_("Error getting client api: %s") % e.body) from e | ||
|
||
def _link(self, client, language, country_code, company_name, products): | ||
request = LinkTokenCreateRequest( | ||
products=[Products(product) for product in products], | ||
client_name=company_name, | ||
country_codes=[CountryCode(country_code)], | ||
language=language, | ||
user=LinkTokenCreateRequestUser(client_user_id="client"), | ||
) | ||
try: | ||
response = client.link_token_create(request) | ||
except plaid.ApiException as e: | ||
raise ValidationError(_("Error getting link token: %s") % e.body) from e | ||
return response.to_dict()["link_token"] | ||
|
||
def _login(self, client, public_token): | ||
request = ItemPublicTokenExchangeRequest(public_token=public_token) | ||
try: | ||
response = client.item_public_token_exchange(request) | ||
except plaid.ApiException as e: | ||
raise ValidationError(_("Error getting access token: %s") % e.body) from e | ||
return response["access_token"] | ||
|
||
def _get_accounts(self, client, access_token): | ||
request = AccountsGetRequest(access_token=access_token) | ||
try: | ||
response = client.accounts_get(request) | ||
except plaid.ApiException as e: | ||
raise ValidationError(_("Error getting accounts: %s") % e.body) from e | ||
return response.to_dict()["accounts"] | ||
|
||
def _transfer_auth(self, client, access_token, account_id, partner_id, amount): | ||
request = TransferAuthorizationCreateRequest( | ||
access_token=access_token, | ||
account_id=account_id, | ||
originator_client_id=partner_id.plaid_client_id, | ||
type=TransferType("credit"), | ||
amount=amount, | ||
network=TransferNetwork("ach"), | ||
user=TransferAuthorizationUserInRequest(legal_name=partner_id.name), | ||
ach_class=ACHClass("ppd"), | ||
) | ||
|
||
try: | ||
response = client.transfer_authorization_create(request) | ||
except plaid.ApiException as e: | ||
raise ValidationError(_("Error getting transfer auth: %s") % e.body) from e | ||
response_dict = response.to_dict()["authorization"] | ||
return { | ||
"authorization_id": response_dict["id"], | ||
"decision": response_dict["decision"], | ||
"decision_rationale": response_dict["decision_rationale"], | ||
} | ||
|
||
def _transfer( | ||
self, client, access_token, account_id, authorization_id, description | ||
): | ||
request = TransferCreateRequest( | ||
access_token=access_token, | ||
account_id=account_id, | ||
authorization_id=authorization_id, | ||
description=description, | ||
) | ||
try: | ||
response = client.transfer_create(request) | ||
except plaid.ApiException as e: | ||
raise ValidationError(_("Error creating transfer: %s") % e.body) from e | ||
return response.to_dict()["transfer"] | ||
|
||
def _sync_transfer_events(self, client): | ||
request = TransferEventSyncRequest(after_id=4, count=25) | ||
try: | ||
response = client.transfer_event_sync(request) | ||
except plaid.ApiException as e: | ||
raise ValidationError( | ||
_("Error syncing transfer events: %s") % e.body | ||
) from e | ||
return response.to_dict()["transfer_events"] | ||
|
||
############################ | ||
# Sandbox Transfer Methods # | ||
############################ | ||
|
||
def _sandbox_simulate_transfer(self, client, transfer_id, event_type, failure): | ||
if event_type == "failed": | ||
request = SandboxTransferSimulateRequest( | ||
transfer_id=transfer_id, | ||
event_type=event_type, | ||
failure_reason=TransferFailure( | ||
description=failure, | ||
), | ||
) | ||
else: | ||
request = SandboxTransferSimulateRequest( | ||
transfer_id=transfer_id, | ||
event_type=event_type, | ||
) | ||
|
||
try: | ||
client.sandbox_transfer_simulate(request) | ||
except plaid.ApiException as e: | ||
raise ValidationError(_("Error simulating transfer: %s") % e.body) from e | ||
|
||
def _sandbox_transfer_ledger_simulate_available(self, client): | ||
try: | ||
client.sandbox_transfer_ledger_simulate_available({}) | ||
except plaid.ApiException as e: | ||
raise ValidationError(_("Error simulating transfer: %s") % e.body) from e |
Oops, something went wrong.