Skip to content

Commit

Permalink
[IMP] account_banking_ach_base: Improved code.
Browse files Browse the repository at this point in the history
  • Loading branch information
murtuzasaleh committed Jul 5, 2019
1 parent 9f242cf commit d9e5e8b
Show file tree
Hide file tree
Showing 19 changed files with 596 additions and 112 deletions.
84 changes: 65 additions & 19 deletions account_banking_ach_base/README.rst
Original file line number Diff line number Diff line change
@@ -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
=====
Expand All @@ -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
<https://github.com/thinkwelltwd/countinghouse>`_. 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 <https://github.com/OCA/l10n-usa/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 <https://github.com/OCA/l10n-usa/issues/new?body=module:%20account_banking_ach_base%0Aversion:%2012.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
~~~~~~~

* Thinkwell Designs

Contributors
~~~~~~~~~~~~

* Dave Burkholder <[email protected]>
* Maxime Chambreuil <[email protected]>
* Serpent Consulting Services Pvt. Ltd. <[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/l10n-usa <https://github.com/OCA/l10n-usa/tree/12.0/account_banking_ach_base>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions account_banking_ach_base/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import models
11 changes: 8 additions & 3 deletions account_banking_ach_base/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -20,5 +20,10 @@
'views/res_company.xml',
'views/res_partner.xml',
],
"external_dependencies": {
"python": ['stdnum',
'ach',
],
},
'installable': True,
}
2 changes: 2 additions & 0 deletions account_banking_ach_base/models/__init__.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down
25 changes: 13 additions & 12 deletions account_banking_ach_base/models/account_banking_mandate.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,49 @@
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):
"""
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
12 changes: 4 additions & 8 deletions account_banking_ach_base/models/account_invoice.py
Original file line number Diff line number Diff line change
@@ -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


Expand All @@ -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()
76 changes: 34 additions & 42 deletions account_banking_ach_base/models/account_payment_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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"""
Expand All @@ -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' \
Expand All @@ -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),
Expand All @@ -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
Loading

0 comments on commit d9e5e8b

Please sign in to comment.