diff --git a/account_banking_ach_base/README.rst b/account_banking_ach_base/README.rst index 49fd5f4b..a639ec3f 100644 --- a/account_banking_ach_base/README.rst +++ b/account_banking_ach_base/README.rst @@ -1,19 +1,36 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :alt: License: AGPL-3 +===================================================== +Localizations for North American Banking & Financials +===================================================== -======================= -Counting House ACH Base -======================= +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -Add fields to Bank, Partner and Company required for ACH transactions in USA. +.. |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%2Fl10n--usa-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-usa/tree/12.0/account_banking_ach_base + :alt: OCA/l10n-usa +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-usa-12-0/l10n-usa-12-0-account_banking_ach_base + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/203/12.0 + :alt: Try me on Runbot -Installation -============ +|badge1| |badge2| |badge3| |badge4| |badge5| -This module depends on : +Add fields to Bank, Partner and Company required for ACH transactions in USA. -* stdnum +**Table of contents** +.. contents:: + :local: Usage ===== @@ -25,15 +42,44 @@ Add Legal ID on Partner and Company records. Add Mandate URL field to Company record. Use in email templates to provide customer with an easy way to access your Mandate Authorization form to streamline ACH authorizations. -Known issues / Roadmap -====================== - - * Add support for EFT 1464 byte payment files required in Canada - Bug Tracker =========== -Bugs are tracked on `GitHub Issues -`_. In case of trouble, please -check there if your issue has already been reported. If you spotted it first, -help us smashing it by providing a detailed and welcomed feedback. +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Thinkwell Designs + +Contributors +~~~~~~~~~~~~ + +* Dave Burkholder +* Maxime Chambreuil +* Serpent Consulting Services Pvt. Ltd. + +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/l10n-usa `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_banking_ach_base/__init__.py b/account_banking_ach_base/__init__.py index 0650744f..83e553ac 100644 --- a/account_banking_ach_base/__init__.py +++ b/account_banking_ach_base/__init__.py @@ -1 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + from . import models diff --git a/account_banking_ach_base/__manifest__.py b/account_banking_ach_base/__manifest__.py index 178a8505..f88672c3 100644 --- a/account_banking_ach_base/__manifest__.py +++ b/account_banking_ach_base/__manifest__.py @@ -4,10 +4,10 @@ { 'name': 'Localizations for North American Banking & Financials', 'summary': 'Add fields required for North American Banking & Financials', - 'version': '11.0.1.0.0', + 'version': '12.0.1.0.0', 'license': 'AGPL-3', - 'author': 'Thinkwell Designs', - 'website': 'https://github.com/thinkwelltwd/countinghouse', + 'author': 'Thinkwell Designs, Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/l10n-usa', 'category': 'Banking addons', 'depends': [ 'account_payment_order', @@ -20,5 +20,10 @@ 'views/res_company.xml', 'views/res_partner.xml', ], + "external_dependencies": { + "python": ['stdnum', + 'ach', + ], + }, 'installable': True, } diff --git a/account_banking_ach_base/models/__init__.py b/account_banking_ach_base/models/__init__.py index 736d9c5a..03d74879 100644 --- a/account_banking_ach_base/models/__init__.py +++ b/account_banking_ach_base/models/__init__.py @@ -1,3 +1,5 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + from . import account_banking_mandate from . import account_invoice from . import account_payment_order diff --git a/account_banking_ach_base/models/account_banking_mandate.py b/account_banking_ach_base/models/account_banking_mandate.py index 183d40e9..48203cbe 100644 --- a/account_banking_ach_base/models/account_banking_mandate.py +++ b/account_banking_ach_base/models/account_banking_mandate.py @@ -1,20 +1,21 @@ -from odoo import api, fields, models +from odoo import api, fields, models, _ from odoo.exceptions import UserError class AccountBankingMandate(models.Model): _inherit = 'account.banking.mandate' - delay_days = fields.Integer(string='Delay Days', required=True, default=10, - help='Number of days to wait after invoice date before ' - 'including an invoice in Payment Order for processing.', - ) + delay_days = fields.Integer(string='Delay Days', required=True, + default=10, + help='''Number of days to wait after invoice + date before including an invoice in Payment + Order for processing.''') def validate(self): for mandate in self: if not mandate.delay_days: - raise UserError('Delay days must be specified, and greater than 0.') - + raise UserError(_('''Delay days must be specified, and + greater than 0.''')) super(AccountBankingMandate, self).validate() def set_payment_modes_on_partner(self): @@ -22,27 +23,27 @@ def set_payment_modes_on_partner(self): Set the payment modes on the Partner if they don't already exist. """ payment_modes = {} - - if self.partner_id.customer and not self.partner_id.customer_payment_mode_id: + if self.partner_id.customer and not \ + self.partner_id.customer_payment_mode_id: customer_mode = self.env['account.payment.mode'].search([ ('payment_type', '=', 'inbound'), ('company_id', '=', self.company_id.id), ], limit=1) if customer_mode: payment_modes['customer_payment_mode_id'] = customer_mode.id - if self.partner_id.supplier and not self.partner_id.supplier_payment_mode_id: + if self.partner_id.supplier and not \ + self.partner_id.supplier_payment_mode_id: supplier_mode = self.env['account.payment.mode'].search([ ('payment_type', '=', 'outbound'), ('company_id', '=', self.company_id.id), ], limit=1) if supplier_mode: payment_modes['supplier_payment_mode_id'] = supplier_mode.id - if payment_modes: self.partner_id.write(payment_modes) @api.model def create(self, vals): mandate = super(AccountBankingMandate, self).create(vals) - self.set_payment_modes_on_partner() + mandate.set_payment_modes_on_partner() return mandate diff --git a/account_banking_ach_base/models/account_invoice.py b/account_banking_ach_base/models/account_invoice.py index e95473a3..3ef29f90 100644 --- a/account_banking_ach_base/models/account_invoice.py +++ b/account_banking_ach_base/models/account_invoice.py @@ -1,5 +1,5 @@ from datetime import date, timedelta -from odoo import api, fields, models +from odoo import api, fields, models, _ from odoo.exceptions import UserError @@ -9,19 +9,15 @@ class AccountInvoice(models.Model): @api.multi def create_account_payment_line(self): today = date.today() - for invoice in self: mandate = invoice.mandate_id if not mandate: continue - invoice_date = fields.Date.from_string(invoice.date_invoice) delay_expired = invoice_date + timedelta(days=mandate.delay_days) - if today < delay_expired: raise UserError( - 'To satisfy payment mandate, cannot add invoice %s to Debit Order until %s!' % - (invoice.number, delay_expired.strftime('%Y-%m-%d')) - ) - + _('To satisfy payment mandate, cannot add invoice %s to ' + 'Debit Order until %s!' % + (invoice.number, delay_expired.strftime('%Y-%m-%d')))) return super(AccountInvoice, self).create_account_payment_line() diff --git a/account_banking_ach_base/models/account_payment_order.py b/account_banking_ach_base/models/account_payment_order.py index 847c6bc2..58667902 100644 --- a/account_banking_ach_base/models/account_payment_order.py +++ b/account_banking_ach_base/models/account_payment_order.py @@ -23,30 +23,29 @@ def get_file_id_mod(self): ACH file_id_mod should be 'A' for the first of the day, 'B' for the second and so on. """ - ach_transactions_today = self.env['account.payment.order'].search_count([ - ('create_date', '>=', fields.Date.today()), - ('company_partner_bank_id', '=', self.company_partner_bank_id.id), - ('state', 'in', ['generated', 'uploaded']), - ('payment_mode_id.payment_method_id.code', 'in', ['ACH-In', 'ACH-Out']), - ]) - + ach_transactions_today =\ + self.env['account.payment.order'].search_count([ + ('create_date', '>=', fields.Date.today()), + ('company_partner_bank_id', '=', + self.company_partner_bank_id.id), + ('state', 'in', ['generated', 'uploaded']), + ('payment_mode_id.payment_method_id.code', 'in', + ['ACH-In', 'ACH-Out']) + ]) return ascii_uppercase[ach_transactions_today] def ach_settings(self): bank = self.company_partner_bank_id.bank_id routing_number = bank.routing_number legal_id_number = self.company_id.legal_id_number - if not legal_id_number: raise UserError( - '%s does not have an EIN / SSN / BN assigned!' % self.company_id.name - ) + _('%s does not have an EIN / SSN / BN ' + 'assigned!' % self.company_id.name)) if not routing_number: raise UserError( - '%s does not have a Routing Number assigned!' % bank.name - ) - + _('%s does not have a Routing Number assigned!' % bank.name)) return { 'immediate_dest': self.company_partner_bank_id.acc_number, 'immediate_org': routing_number, @@ -58,13 +57,13 @@ def ach_settings(self): def validate_banking(self, line): if not line.partner_bank_id.bank_id: raise UserError( - _('%s account number has no Bank assigned' % line.partner_bank_id.acc_number) - ) + _('%s account number has no Bank ' + 'assigned' % line.partner_bank_id.acc_number)) if not line.partner_bank_id.bank_id.routing_number: raise UserError( - _('%s has no routing number specified' % line.partner_bank_id.bank_id.name) - ) + _('%s has no routing number ' + 'specified' % line.partner_bank_id.bank_id.name)) def validate_mandates(self, line): """Ensure that mandates are correctly set""" @@ -80,20 +79,20 @@ def validate_mandates(self, line): "for partner '%s' has expired.") % (line.mandate_id.unique_mandate_reference, line.mandate_id.partner_id.name)) - if line.mandate_id.type == 'oneoff': - if line.mandate_id.last_debit_date: - raise Warning( - _("The mandate with reference '%s' for partner " - "'%s' has type set to 'One-Off' and it has a " - "last debit date set to '%s', so we can't use " - "it.") - % (line.mandate_id.unique_mandate_reference, - line.mandate_id.partner_id.name, - line.mandate_id.last_debit_date)) + if line.mandate_id.type == 'oneoff' and \ + line.mandate_id.last_debit_date: + raise Warning( + _("The mandate with reference '%s' for partner " + "'%s' has type set to 'One-Off' and it has a " + "last debit date set to '%s', so we can't use " + "it.") % (line.mandate_id.unique_mandate_reference, + line.mandate_id.partner_id.name, + line.mandate_id.last_debit_date)) def get_transaction_type(self, amount): if not amount: - return DEBIT_ZERO_DOLLAR_ENTRY_WITH_ADDENDA if self.payment_type == 'inbound' \ + return DEBIT_ZERO_DOLLAR_ENTRY_WITH_ADDENDA if \ + self.payment_type == 'inbound' \ else CREDIT_ZERO_DOLLAR_ENTRY_WITH_ADDENDA return DEBIT_AUTOMATED_PAYMENT if self.payment_type == 'inbound' \ @@ -102,24 +101,18 @@ def get_transaction_type(self, amount): @api.multi def generate_ach_file(self): self.ensure_one() - inbound_payment = self.payment_type == 'inbound' - file_mod = self.get_file_id_mod() - ach_file = AchFile(file_id_mod=file_mod, settings=self.ach_settings()) + ach_file = AchFile(file_id_mod=file_mod, + settings=self.ach_settings()) filename = '{today}_{bank}_{file_mod}.txt'.format( - today=fields.Date.today(), bank=self.company_partner_bank_id.id, file_mod=file_mod, - ) - + today=fields.Date.today(), + bank=self.company_partner_bank_id.id, file_mod=file_mod) entries = [] - for line in self.bank_line_ids: - if inbound_payment: self.validate_mandates(line) - self.validate_banking(line) - amount = line.amount_currency entries.append({ 'type': self.get_transaction_type(amount=amount), @@ -131,8 +124,7 @@ def generate_ach_file(self): 'payment_related_info': line.communication, }], }) - - credits = self.payment_type == 'outbound' - ach_file.add_batch('PPD', entries, credits=credits, debits=inbound_payment) - + outbound_payment = self.payment_type == 'outbound' + ach_file.add_batch('PPD', entries, credits=outbound_payment, + debits=inbound_payment) return ach_file.render_to_string(), filename diff --git a/account_banking_ach_base/models/base.py b/account_banking_ach_base/models/base.py index 44a94d66..0490c4cc 100644 --- a/account_banking_ach_base/models/base.py +++ b/account_banking_ach_base/models/base.py @@ -1,4 +1,4 @@ -from odoo import api, models, fields +from odoo import api, fields, models, _ from odoo.exceptions import UserError from stdnum.us import ssn, ein from stdnum.ca import bn @@ -12,22 +12,20 @@ class LegalIDNumber(models.AbstractModel): Use generic ID and apply validation depending on the Country field. """ _name = 'countinghouse.legal_id_number' + _description = 'Countinghouse Legal Id Number' legal_id_number = fields.Char( string='Legal ID', required=False, - help='''For US entities, enter valid EIN or Social Security Number. + help='''For US entities, enter valid EIN or Social Security Number. Canadian entities, enter Canadian Business Number. - ''' - ) + ''') @api.constrains('legal_id_number') def validate_legal_id_number(self): if not self.legal_id_number: return - valid = False - for v in (ssn, ein, bn): try: v.validate(self.legal_id_number) @@ -35,8 +33,7 @@ def validate_legal_id_number(self): break except Exception: continue - if not valid: raise UserError( - '%s is not a valid EIN / SSN / Canadian Business Number' % self.legal_id_number - ) + _('%s is not a valid EIN / SSN / Canadian Business ' + 'Number' % self.legal_id_number)) diff --git a/account_banking_ach_base/models/res_bank.py b/account_banking_ach_base/models/res_bank.py index d22951cd..03198325 100644 --- a/account_banking_ach_base/models/res_bank.py +++ b/account_banking_ach_base/models/res_bank.py @@ -1,4 +1,4 @@ -from odoo import api, models, fields +from odoo import api, fields, models, _ from odoo.exceptions import ValidationError from stdnum.us import rtn @@ -6,25 +6,23 @@ class ResBank(models.Model): _inherit = 'res.bank' - routing_number = fields.Char(string='Routing Number', required=False) + routing_number = fields.Char(string='Routing Number') @api.constrains('routing_number') def validate_routing_number(self): if not self.routing_number or not self.country: return - country_code = self.country.code - if country_code == 'US': try: rtn.validate(self.routing_number) except Exception: raise ValidationError( - '%s is not a valid US routing number!' % self.routing_number - ) - + _('%s is not a valid US routing ' + 'number!' % self.routing_number)) elif country_code == 'CA': - if len(self.routing_number) != 8 or not not self.routing_number.is_digit(): + if len(self.routing_number) != 8 or not \ + self.routing_number.is_digit(): raise ValidationError( - '%s is not a valid Canadian routing number!' % self.routing_number - ) + _('%s is not a valid Canadian routing ' + 'number!' % self.routing_number)) diff --git a/account_banking_ach_base/models/res_company.py b/account_banking_ach_base/models/res_company.py index 33b73e36..03954b4a 100644 --- a/account_banking_ach_base/models/res_company.py +++ b/account_banking_ach_base/models/res_company.py @@ -6,7 +6,7 @@ class ResCompany(models.Model): _inherit = ['countinghouse.legal_id_number', 'res.company'] mandate_url = fields.Char(string='Mandate URL', required=False, - help='Full URL to download ACH Mandate / Authorization form. Useful ' - 'to include in email templates for customer to access and ' - 'complete the Mandate form.' - ) + help='''Full URL to download ACH Mandate / + Authorization form. Useful to include in email + templates for customer to access and + complete the Mandate form.''') diff --git a/account_banking_ach_base/readme/CONTRIBUTORS.rst b/account_banking_ach_base/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..5a46796e --- /dev/null +++ b/account_banking_ach_base/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Dave Burkholder +* Maxime Chambreuil +* Serpent Consulting Services Pvt. Ltd. diff --git a/account_banking_ach_base/readme/DESCRIPTION.rst b/account_banking_ach_base/readme/DESCRIPTION.rst new file mode 100644 index 00000000..f67cdafa --- /dev/null +++ b/account_banking_ach_base/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Add fields to Bank, Partner and Company required for ACH transactions in USA. diff --git a/account_banking_ach_base/readme/USAGE.rst b/account_banking_ach_base/readme/USAGE.rst new file mode 100644 index 00000000..381ada16 --- /dev/null +++ b/account_banking_ach_base/readme/USAGE.rst @@ -0,0 +1,6 @@ +Add `routing_number` on Bank records. + +Add Legal ID on Partner and Company records. + +Add Mandate URL field to Company record. Use in email templates to provide customer with an easy +way to access your Mandate Authorization form to streamline ACH authorizations. diff --git a/account_banking_ach_base/requirements.txt b/account_banking_ach_base/requirements.txt deleted file mode 100644 index 2695d2b9..00000000 --- a/account_banking_ach_base/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -stdnum -python-ach \ No newline at end of file diff --git a/account_banking_ach_base/static/description/index.html b/account_banking_ach_base/static/description/index.html new file mode 100644 index 00000000..aa11efe8 --- /dev/null +++ b/account_banking_ach_base/static/description/index.html @@ -0,0 +1,429 @@ + + + + + + +Localizations for North American Banking & Financials + + + +
+

Localizations for North American Banking & Financials

+ + +

Beta License: AGPL-3 OCA/l10n-usa Translate me on Weblate Try me on Runbot

+

Add fields to Bank, Partner and Company required for ACH transactions in USA.

+

Table of contents

+ +
+

Usage

+

Add routing_number on Bank records.

+

Add Legal ID on Partner and Company records.

+

Add Mandate URL field to Company record. Use in email templates to provide customer with an easy +way to access your Mandate Authorization form to streamline ACH authorizations.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Thinkwell Designs
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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/l10n-usa project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/account_banking_ach_base/views/account_banking_mandate.xml b/account_banking_ach_base/views/account_banking_mandate.xml index 1749a2bc..142238a1 100644 --- a/account_banking_ach_base/views/account_banking_mandate.xml +++ b/account_banking_ach_base/views/account_banking_mandate.xml @@ -4,10 +4,14 @@ account.invoice.days.delay account.banking.mandate - + - + + + + 1 diff --git a/account_banking_ach_base/views/account_invoice.xml b/account_banking_ach_base/views/account_invoice.xml index 2158a184..27e4044b 100644 --- a/account_banking_ach_base/views/account_invoice.xml +++ b/account_banking_ach_base/views/account_invoice.xml @@ -1,7 +1,8 @@ - + account.invoice.valid.mandate account.invoice diff --git a/oca_dependencies.txt b/oca_dependencies.txt new file mode 100644 index 00000000..34f82ae9 --- /dev/null +++ b/oca_dependencies.txt @@ -0,0 +1 @@ +bank-payment diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..bcff9f62 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +ach +python-stdnum