Browse Source
Merge pull request #161 from Tecnativa/11.0-mig_account_bank_statement_import_paypal
Merge pull request #161 from Tecnativa/11.0-mig_account_bank_statement_import_paypal
[MIG]account_bank_statement_import_paypal: Migration to 11.0pull/182/merge
Pedro M. Baeza
6 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 432 additions and 0 deletions
-
105account_bank_statement_import_paypal/README.rst
-
1account_bank_statement_import_paypal/__init__.py
-
18account_bank_statement_import_paypal/__manifest__.py
-
1account_bank_statement_import_paypal/models/__init__.py
-
281account_bank_statement_import_paypal/models/account_bank_statement_import_paypal.py
-
12account_bank_statement_import_paypal/readme/CONFIGURE.rst
-
5account_bank_statement_import_paypal/readme/CONTRIBUTORS.rst
-
1account_bank_statement_import_paypal/readme/DESCRIPTION.rst
-
8account_bank_statement_import_paypal/readme/USAGE.rst
-
BINaccount_bank_statement_import_paypal/static/description/icon.png
-
BINaccount_bank_statement_import_paypal/static/description/paypal_backoffice.png
@ -0,0 +1,105 @@ |
|||
============================= |
|||
Import Paypal Bank Statements |
|||
============================= |
|||
|
|||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|||
!! This file is generated by oca-gen-addon-readme !! |
|||
!! changes will be overwritten. !! |
|||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|||
|
|||
.. |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--statement--import-lightgray.png?logo=github |
|||
:target: https://github.com/OCA/bank-statement-import/tree/11.0/account_bank_statement_import_paypal |
|||
:alt: OCA/bank-statement-import |
|||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png |
|||
:target: https://translation.odoo-community.org/projects/bank-statement-import-11-0/bank-statement-import-11-0-account_bank_statement_import_paypal |
|||
:alt: Translate me on Weblate |
|||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png |
|||
:target: https://runbot.odoo-community.org/runbot/174/11.0 |
|||
:alt: Try me on Runbot |
|||
|
|||
|badge1| |badge2| |badge3| |badge4| |badge5| |
|||
|
|||
This module allows you to import the Paypal CSV files in Odoo as bank statements. |
|||
|
|||
**Table of contents** |
|||
|
|||
.. contents:: |
|||
:local: |
|||
|
|||
Configuration |
|||
============= |
|||
|
|||
In the menu Accounting > Configuration > Accounting > Bank Accounts, |
|||
make sure that you have your Paypal bank account with the following parameters: |
|||
* Bank Account Type: Normal Bank Account |
|||
* Account Number: the email address associated with your Paypal account |
|||
* Account Journal: the journal associated to your Paypal account |
|||
|
|||
TIPS |
|||
---- |
|||
For now only French and English report are supported. |
|||
For adding new support you just need to add your header in |
|||
model/account_bank_statement_import_paypal.py in the variables HEADERS. |
|||
Please help us and do a PR for adding new header ! Thanks |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
To use this module, you need to: |
|||
|
|||
#. Go to Paypal and download your Bank Statement |
|||
|
|||
.. image:: account_bank_statement_import_paypal/static/description/paypal_backoffice.png |
|||
:alt: . |
|||
.. image:: static/description/paypal_backoffice.png |
|||
:alt: . |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-statement-import/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/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_paypal%0Aversion:%2011.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 |
|||
------- |
|||
|
|||
* Akretion |
|||
|
|||
Contributors |
|||
~~~~~~~~~~~~ |
|||
|
|||
* Alexis de Lattre <alexis.delattre@akretion.com> |
|||
* Sebastien BEAU <sebastien.beau@akretion.com> |
|||
* Tecnativa (https://www.tecnativa.com) |
|||
|
|||
* Vicent Cubells <vicent.cubells@tecnativa.com> |
|||
|
|||
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-statement-import <https://github.com/OCA/bank-statement-import/tree/11.0/account_bank_statement_import_paypal>`_ project on GitHub. |
|||
|
|||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
@ -0,0 +1 @@ |
|||
from . import models |
@ -0,0 +1,18 @@ |
|||
# Copyright 2014-2017 Akretion (http://www.akretion.com). |
|||
# @author Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# @author Sébastien BEAU <sebastien.beau@akretion.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
{ |
|||
"name": "Import Paypal Bank Statements", |
|||
'summary': 'Import Paypal CSV files as Bank Statements in Odoo', |
|||
"version": "11.0.1.0.0", |
|||
"category": "Accounting", |
|||
"website": "https://github.com/OCA/bank-statement-import", |
|||
"author": " Akretion, Odoo Community Association (OCA)", |
|||
"license": "AGPL-3", |
|||
"application": False, |
|||
"installable": True, |
|||
"depends": [ |
|||
"account_bank_statement_import", |
|||
], |
|||
} |
@ -0,0 +1 @@ |
|||
from . import account_bank_statement_import_paypal |
@ -0,0 +1,281 @@ |
|||
# Copyright 2014-2017 Akretion (http://www.akretion.com). |
|||
# @author Alexis de Lattre <alexis.delattre@akretion.com> |
|||
# @author Sébastien BEAU <sebastien.beau@akretion.com> |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
import logging |
|||
from datetime import datetime |
|||
from odoo import _, api, fields, models |
|||
from odoo.exceptions import UserError |
|||
import re |
|||
from io import StringIO |
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
try: |
|||
import csv |
|||
except (ImportError, IOError) as err: |
|||
_logger.debug(err) |
|||
|
|||
# Paypal header depend of the country the order are the same but the |
|||
# value are translated. You can add you header here |
|||
|
|||
HEADERS = [ |
|||
# French |
|||
'"Date","Heure","Fuseau horaire","Description","Devise","Avant commission"' |
|||
',"Commission","Net","Solde","Numéro de transaction","Adresse email de ' |
|||
'l\'expéditeur","Nom","Nom de la banque","Compte bancaire","Montant des ' |
|||
'frais de livraison et de traitement","TVA","Identifiant de facture",' |
|||
'"Numéro de la transaction de référence"', |
|||
# English |
|||
'"Date","Time","Time Zone","Description","Currency","Gross ","Fee ","Net",' |
|||
'"Balance","Transaction ID","From Email Address","Name","Bank Name",' |
|||
'"Bank Account","Shipping and Handling Amount","Sales Tax","Invoice ID",' |
|||
'"Reference Txn ID"', |
|||
] |
|||
|
|||
|
|||
class AccountBankStatementImport(models.TransientModel): |
|||
_inherit = 'account.bank.statement.import' |
|||
|
|||
@api.model |
|||
def _get_paypal_encoding(self): |
|||
return 'utf-8-sig' |
|||
|
|||
@api.model |
|||
def _get_paypal_str_data(self, data_file): |
|||
if not isinstance(data_file, str): |
|||
data_file = data_file.decode(self._get_paypal_encoding()) |
|||
return data_file.strip() |
|||
|
|||
@api.model |
|||
def _get_paypal_date_format(self): |
|||
""" This method is designed to be inherited """ |
|||
return '%d/%m/%Y' |
|||
|
|||
@api.model |
|||
def _paypal_convert_amount(self, amount_str): |
|||
""" This method is designed to be inherited """ |
|||
valstr = re.sub(r'[^\d,.-]', '', amount_str) |
|||
valstrdot = valstr.replace('.', '') |
|||
valstrdot = valstrdot.replace(',', '.') |
|||
return float(valstrdot) |
|||
|
|||
@api.model |
|||
def _check_paypal(self, data_file): |
|||
data_file = self._get_paypal_str_data(data_file) |
|||
for header in HEADERS: |
|||
if data_file.strip().startswith(header): |
|||
return True |
|||
return False |
|||
|
|||
def _convert_paypal_line_to_dict(self, idx, line): |
|||
date_dt = datetime.strptime(line[0], self._get_paypal_date_format()) |
|||
rline = { |
|||
'date': fields.Date.to_string(date_dt), |
|||
'time': line[1], |
|||
'description': line[3], |
|||
'currency': line[4], |
|||
'amount': line[5], |
|||
'commission': line[6], |
|||
'balance': line[8], |
|||
'transaction_id': line[9], |
|||
'email': line[10], |
|||
'partner_name': line[11], |
|||
# This two field are useful for bank transfer |
|||
'bank_name': line[12], |
|||
'bank_account': line[13], |
|||
'invoice_number': line[16], |
|||
'origin_transaction_id': line[17], |
|||
'idx': idx, |
|||
} |
|||
for field in ['commission', 'amount', 'balance']: |
|||
_logger.debug('Trying to convert %s to float' % rline[field]) |
|||
try: |
|||
rline[field] = self._paypal_convert_amount(rline[field]) |
|||
except Exception: |
|||
raise UserError( |
|||
_("Value '%s' for the field '%s' on line %d, " |
|||
"cannot be converted to float") |
|||
% (rline[field], field, idx)) |
|||
return rline |
|||
|
|||
def _parse_paypal_file(self, data_file): |
|||
data_file = self._get_paypal_str_data(data_file) |
|||
f = StringIO(data_file) |
|||
f.seek(0) |
|||
raw_lines = [] |
|||
reader = csv.reader(f) |
|||
next(reader) # Drop header |
|||
for idx, line in enumerate(reader): |
|||
_logger.debug("Line %d: %s" % (idx, line)) |
|||
raw_lines.append(self._convert_paypal_line_to_dict(idx, line)) |
|||
return raw_lines |
|||
|
|||
def _prepare_paypal_currency_vals(self, cline): |
|||
currencies = self.env['res.currency'].search( |
|||
[('name', '=', cline['currency'])]) |
|||
if not currencies: |
|||
raise UserError( |
|||
_('currency %s on line %d cannot be found in odoo') |
|||
% (cline['currency'], cline['idx'])) |
|||
return { |
|||
'amount_currency': cline['amount'], |
|||
'currency_id': currencies.id, |
|||
'currency': cline['currency'], |
|||
'partner_name': cline['partner_name'], |
|||
'description': cline['description'], |
|||
'email': cline['email'], |
|||
'transaction_id': cline['transaction_id'], |
|||
} |
|||
|
|||
def _post_process_statement_line(self, raw_lines): |
|||
journal_id = self.env.context.get('journal_id') |
|||
if not journal_id: |
|||
raise UserError(_('You must run this wizard from the journal')) |
|||
journal = self.env['account.journal'].browse(journal_id) |
|||
currency = journal.currency_id or journal.company_id.currency_id |
|||
currency_change_lines = {} |
|||
real_transactions = [] |
|||
for line in raw_lines: |
|||
if line['currency'] != currency.name: |
|||
currency_change_lines[line['transaction_id']] = line |
|||
else: |
|||
real_transactions.append(line) |
|||
|
|||
for line in real_transactions: |
|||
# Check if the current transaction is linked with a |
|||
# transaction of currency change if yes merge the transaction |
|||
# as for odoo it's only one line |
|||
cline = currency_change_lines.get(line['origin_transaction_id']) |
|||
if cline: |
|||
# we update the current line with currency information |
|||
vals = self._prepare_paypal_currency_vals(cline) |
|||
line.update(vals) |
|||
return real_transactions |
|||
|
|||
def _prepare_paypal_statement_line(self, fline): |
|||
if fline['bank_name']: |
|||
name = '|'.join([ |
|||
fline['description'], |
|||
fline['bank_name'], |
|||
fline['bank_account'] |
|||
]) |
|||
else: |
|||
name = '|'.join([ |
|||
fline['description'], |
|||
fline['partner_name'], |
|||
fline['email'], |
|||
fline['invoice_number'], |
|||
]) |
|||
return { |
|||
'date': fline['date'], |
|||
'name': name, |
|||
'ref': fline['transaction_id'], |
|||
'unique_import_id': |
|||
fline['transaction_id'] + fline['date'] + fline['time'], |
|||
'amount': fline['amount'], |
|||
'bank_account_id': False, |
|||
'currency_id': fline.get('currency_id'), |
|||
'amount_currency': fline.get('amount_currency'), |
|||
} |
|||
|
|||
def _prepare_paypal_statement(self, lines): |
|||
return { |
|||
'name': |
|||
_('PayPal Import %s > %s') |
|||
% (lines[0]['date'], lines[-1]['date']), |
|||
'date': lines[-1]['date'], |
|||
'balance_start': |
|||
lines[0]['balance'] - |
|||
lines[0]['amount'] - |
|||
lines[0]['commission'], |
|||
'balance_end_real': lines[-1]['balance'], |
|||
} |
|||
|
|||
@api.model |
|||
def _parse_file(self, data_file): |
|||
""" Import a file in Paypal CSV format """ |
|||
paypal = self._check_paypal(data_file) |
|||
if not paypal: |
|||
return super(AccountBankStatementImport, self)._parse_file( |
|||
data_file) |
|||
|
|||
raw_lines = self._parse_paypal_file(data_file) |
|||
final_lines = self._post_process_statement_line(raw_lines) |
|||
|
|||
vals_bank_statement = self._prepare_paypal_statement(final_lines) |
|||
|
|||
transactions = [] |
|||
commission_total = 0 |
|||
for fline in final_lines: |
|||
commission_total += fline['commission'] |
|||
vals_line = self._prepare_paypal_statement_line(fline) |
|||
_logger.debug("vals_line = %s" % vals_line) |
|||
transactions.append(vals_line) |
|||
|
|||
if commission_total: |
|||
commission_line = { |
|||
'date': vals_bank_statement['date'], |
|||
'name': _('Paypal commissions'), |
|||
'ref': _('PAYPAL-COSTS'), |
|||
'amount': commission_total, |
|||
'unique_import_id': False, |
|||
} |
|||
transactions.append(commission_line) |
|||
|
|||
vals_bank_statement['transactions'] = transactions |
|||
return None, None, [vals_bank_statement] |
|||
|
|||
@api.model |
|||
def _get_paypal_partner(self, description, partner_name, |
|||
partner_email, invoice_number): |
|||
if invoice_number: |
|||
# In most case e-commerce case invoice_number |
|||
# will contain the sale order number |
|||
sale = self.env['sale.order'].search([ |
|||
('name', '=', invoice_number)]) |
|||
if sale and len(sale) == 1: |
|||
return sale.partner_id.commercial_partner_id |
|||
|
|||
invoice = self.env['account.invoice'].search([ |
|||
('number', '=', invoice_number)]) |
|||
if invoice and len(invoice) == 1: |
|||
return invoice.partner_id.commercial_partner_id |
|||
|
|||
if partner_email: |
|||
partner = self.env['res.partner'].search([ |
|||
('email', '=', partner_email), |
|||
('parent_id', '=', False)]) |
|||
if partner and len(partner) == 1: |
|||
return partner.commercial_partner_id |
|||
|
|||
if partner_name: |
|||
partner = self.env['res.partner'].search([ |
|||
('name', '=ilike', partner_name)]) |
|||
if partner and len(partner) == 1: |
|||
return partner.commercial_partner_id |
|||
return None |
|||
|
|||
@api.model |
|||
def _complete_paypal_statement_line(self, line): |
|||
_logger.debug('Process line %s', line['name']) |
|||
info = line['name'].split('|') |
|||
if len(info) == 4: |
|||
partner = self._get_paypal_partner(*info) |
|||
if partner: |
|||
return { |
|||
'partner_id': partner.id, |
|||
'account_id': partner.property_account_receivable.id, |
|||
} |
|||
return None |
|||
|
|||
@api.model |
|||
def _complete_statement(self, stmts_vals, journal_id, account_number): |
|||
""" Match the partner from paypal information """ |
|||
stmts_vals = super(AccountBankStatementImport, self).\ |
|||
_complete_statement(stmts_vals, journal_id, account_number) |
|||
for line in stmts_vals['transactions']: |
|||
vals = self._complete_paypal_statement_line(line) |
|||
if vals: |
|||
line.update(vals) |
|||
return stmts_vals |
@ -0,0 +1,12 @@ |
|||
In the menu Accounting > Configuration > Accounting > Bank Accounts, |
|||
make sure that you have your Paypal bank account with the following parameters: |
|||
* Bank Account Type: Normal Bank Account |
|||
* Account Number: the email address associated with your Paypal account |
|||
* Account Journal: the journal associated to your Paypal account |
|||
|
|||
TIPS |
|||
---- |
|||
For now only French and English report are supported. |
|||
For adding new support you just need to add your header in |
|||
model/account_bank_statement_import_paypal.py in the variables HEADERS. |
|||
Please help us and do a PR for adding new header ! Thanks |
@ -0,0 +1,5 @@ |
|||
* Alexis de Lattre <alexis.delattre@akretion.com> |
|||
* Sebastien BEAU <sebastien.beau@akretion.com> |
|||
* Tecnativa (https://www.tecnativa.com) |
|||
|
|||
* Vicent Cubells <vicent.cubells@tecnativa.com> |
@ -0,0 +1 @@ |
|||
This module allows you to import the Paypal CSV files in Odoo as bank statements. |
@ -0,0 +1,8 @@ |
|||
To use this module, you need to: |
|||
|
|||
#. Go to Paypal and download your Bank Statement |
|||
|
|||
.. image:: account_bank_statement_import_paypal/static/description/paypal_backoffice.png |
|||
:alt: . |
|||
.. image:: static/description/paypal_backoffice.png |
|||
:alt: . |
After Width: 180 | Height: 180 | Size: 6.3 KiB |
After Width: 1194 | Height: 932 | Size: 95 KiB |
Write
Preview
Loading…
Cancel
Save
Reference in new issue