From aa54c740ca8f5f8e4747b89295a3a4f7e2d4e20a Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Wed, 10 Sep 2014 12:48:09 +0200 Subject: [PATCH] [MIG] Migration and enhancement of all modules involved in SEPA --- .../__init__.py | 1 - __unported__/account_direct_debit/__init__.py | 1 - .../account_direct_debit/model/__init__.py | 5 - .../account_payment_shortcut/__init__.py | 2 - .../account_payment_shortcut/__openerp__.py | 34 -- .../account_payment_shortcut/payment_order.py | 54 --- account_banking_pain_base/__init__.py | 23 + .../__openerp__.py | 19 +- .../banking_export_pain.py | 0 .../company.py | 0 .../company_view.xml | 0 .../i18n/account_banking_pain_base.pot | 0 .../i18n/fr.po | 0 .../i18n/nl.po | 0 .../models}/__init__.py | 2 +- .../models/banking_export_pain.py | 440 ++++++++++++++++++ .../models}/payment_line.py | 0 .../models}/payment_mode.py | 0 .../models/res_company.py | 82 ++++ account_banking_pain_base/payment_line.py | 52 +++ .../payment_line_view.xml | 0 account_banking_pain_base/payment_mode.py | 39 ++ .../payment_mode_view.xml | 0 .../views/payment_line_view.xml | 41 ++ .../views/payment_mode_view.xml | 22 + .../views/res_company_view.xml | 24 + account_banking_payment_export/__init__.py | 3 + .../__openerp__.py | 56 ++- .../data/payment_mode_type.xml | 0 .../demo/banking_demo.xml | 4 + .../i18n/account_banking_payment_export.pot | 0 .../i18n/nl.po | 0 .../migrations/7.0.0.1.165/pre-migration.py | 0 .../model/__init__.py | 0 .../model/account_move_line.py | 0 .../model/account_payment.py | 0 .../model/bank_payment_manual.py | 0 .../model/payment_mode.py | 0 .../model/payment_mode_type.py | 0 .../model/payment_order_create.py | 0 .../models/__init__.py | 5 + .../models/account_move_line.py | 98 ++++ .../models/account_payment.py | 77 +++ .../models/payment_mode.py | 54 +++ .../models/payment_mode_type.py | 62 +++ .../security/ir.model.access.csv | 0 .../view/account_payment.xml | 0 .../view/bank_payment_manual.xml | 0 .../view/payment_mode.xml | 2 +- .../view/payment_mode_type.xml | 19 +- .../view/payment_order_create_view.xml | 0 .../wizard/__init__.py | 3 + .../wizard/bank_payment_manual.py | 54 +++ .../wizard/bank_payment_manual.xml | 18 + .../wizard/payment_order_create.py | 175 +++++++ .../wizard/payment_order_create_view.xml | 34 ++ .../__init__.py | 24 + .../__openerp__.py | 33 +- .../account_banking_sepa.py | 0 .../account_banking_sepa_view.xml | 0 .../data/pain.001.001.02.xsd | 0 .../data/pain.001.001.03.xsd | 0 .../data/pain.001.001.04.xsd | 0 .../data/pain.001.001.05.xsd | 0 .../data/payment_type_sepa_sct.xml | 4 + .../demo}/sepa_credit_transfer_demo.xml | 0 .../account_banking_sepa_credit_transfer.pot | 0 .../i18n/fr.po | 0 .../i18n/nl.po | 0 .../models}/__init__.py | 1 - .../models/account_banking_sepa.py | 76 +++ .../security/ir.model.access.csv | 0 .../sepa_credit_transfer_demo.xml | 15 + .../static/description/icon.svg | 92 ++++ .../static/src/img/icon.png | Bin .../views/account_banking_sepa_view.xml | 77 +++ .../wizard/__init__.py | 0 .../wizard/export_sepa.py | 40 +- .../wizard/export_sepa_view.xml | 0 .../__init__.py | 3 +- .../__openerp__.py | 41 +- .../account_banking_sdd.py | 0 .../account_banking_sdd_view.xml | 0 .../account_invoice_view.xml | 0 .../account_payment_view.xml | 0 .../company.py | 0 .../company_view.xml | 0 .../data}/mandate_expire_cron.xml | 0 .../data/mandate_reference_sequence.xml | 0 .../data/pain.008.001.02.xsd | 0 .../data/pain.008.001.03.xsd | 0 .../data/pain.008.001.04.xsd | 0 .../data/payment_type_sdd.xml | 0 .../demo}/sepa_direct_debit_demo.xml | 0 .../account_banking_sepa_direct_debit.pot | 0 .../i18n/fr.po | 0 .../i18n/nl.po | 0 .../mandate_expire_cron.xml | 26 ++ .../models/__init__.py | 28 ++ .../models/account_invoice.py | 32 ++ .../models/banking_export_sdd.py | 78 ++++ .../models/payment_line.py | 74 +++ .../models/res_company.py | 80 ++++ .../models/res_partner_bank.py | 30 ++ .../models/sdd_mandate.py | 291 ++++++++++++ .../res_partner_bank_view.xml | 0 .../sdd_mandate_view.xml | 0 .../security/ir.model.access.csv | 0 .../original_mandate_required_security.xml | 0 .../sepa_direct_debit_demo.xml | 27 ++ .../static/description/icon.svg | 92 ++++ .../static/src/img/icon.png | Bin .../views/account_banking_sdd_view.xml | 77 +++ .../views/account_invoice_view.xml | 22 + .../views/account_payment_view.xml | 26 ++ .../views/res_company_view.xml | 23 + .../views/res_partner_bank_view.xml | 48 ++ .../views/sdd_mandate_view.xml | 153 ++++++ .../wizard/__init__.py | 0 .../wizard/export_sdd.py | 8 +- .../wizard/export_sdd_view.xml | 0 account_direct_debit/__init__.py | 1 + .../__openerp__.py | 15 +- .../data/account_payment_term.xml | 0 .../i18n/account_direct_debit.pot | 0 .../i18n/nl.po | 0 .../migrations/7.0.2/post-migration.py | 0 .../migrations/7.0.2/pre-migration.py | 0 account_direct_debit/models/__init__.py | 4 + .../models}/account_invoice.py | 14 +- .../models}/account_move_line.py | 26 +- .../models}/account_payment.py | 7 +- .../models}/payment_line.py | 63 ++- .../views}/account_invoice.xml | 0 .../views}/account_payment.xml | 35 +- .../views}/payment_mode.xml | 0 .../views}/payment_mode_type.xml | 15 +- account_direct_debit/wizard/__init__.py | 1 + .../wizard}/payment_order_create.py | 12 +- .../workflow/account_invoice.xml | 0 account_payment_partner/__init__.py | 24 + .../__openerp__.py | 11 +- .../demo/partner_demo.xml | 0 .../i18n/account_payment_partner.pot | 0 .../i18n/nl.po | 0 .../models}/__init__.py | 3 +- .../models}/account_invoice.py | 29 +- .../models}/partner.py | 0 .../models}/payment_order_create.py | 0 account_payment_partner/models/res_partner.py | 42 ++ .../views}/account_invoice.xml | 0 .../views/account_invoice_view.xml | 40 ++ .../views}/partner.xml | 0 .../views/res_partner_view.xml | 27 ++ .../wizard}/__init__.py | 2 +- .../wizard/payment_order_create.py | 37 ++ .../__init__.py | 2 +- .../__openerp__.py | 19 +- .../i18n/account_payment_purchase.pot | 0 .../i18n/fr.po | 0 .../i18n/nl.po | 0 .../model/__init__.py | 0 .../model/purchase.py | 0 .../model/stock.py | 0 account_payment_purchase/models/__init__.py | 24 + .../models/purchase_order.py | 63 +++ .../models/stock_picking.py | 38 ++ .../view/purchase.xml | 0 .../views/purchase_order_view.xml | 25 + .../__init__.py | 2 +- .../__openerp__.py | 18 +- .../i18n/account_payment_sale.pot | 0 .../i18n/nl.po | 0 .../model/__init__.py | 0 .../model/sale.py | 0 account_payment_sale/models/__init__.py | 24 + account_payment_sale/models/sale_order.py | 50 ++ account_payment_sale/models/stock_picking.py | 40 ++ .../view/sale.xml | 0 .../views/sale_order_view.xml | 24 + 180 files changed, 3395 insertions(+), 368 deletions(-) delete mode 100644 __unported__/account_banking_payment_export/__init__.py delete mode 100644 __unported__/account_direct_debit/__init__.py delete mode 100644 __unported__/account_direct_debit/model/__init__.py delete mode 100644 __unported__/account_payment_shortcut/__init__.py delete mode 100644 __unported__/account_payment_shortcut/__openerp__.py delete mode 100644 __unported__/account_payment_shortcut/payment_order.py create mode 100644 account_banking_pain_base/__init__.py rename {__unported__/account_banking_pain_base => account_banking_pain_base}/__openerp__.py (85%) rename {__unported__/account_banking_pain_base => account_banking_pain_base}/banking_export_pain.py (100%) rename {__unported__/account_banking_pain_base => account_banking_pain_base}/company.py (100%) rename {__unported__/account_banking_pain_base => account_banking_pain_base}/company_view.xml (100%) rename {__unported__/account_banking_pain_base => account_banking_pain_base}/i18n/account_banking_pain_base.pot (100%) rename {__unported__/account_banking_pain_base => account_banking_pain_base}/i18n/fr.po (100%) rename {__unported__/account_banking_pain_base => account_banking_pain_base}/i18n/nl.po (100%) rename {__unported__/account_banking_pain_base => account_banking_pain_base/models}/__init__.py (97%) create mode 100644 account_banking_pain_base/models/banking_export_pain.py rename {__unported__/account_banking_pain_base => account_banking_pain_base/models}/payment_line.py (100%) rename {__unported__/account_banking_pain_base => account_banking_pain_base/models}/payment_mode.py (100%) create mode 100644 account_banking_pain_base/models/res_company.py create mode 100644 account_banking_pain_base/payment_line.py rename {__unported__/account_banking_pain_base => account_banking_pain_base}/payment_line_view.xml (100%) create mode 100644 account_banking_pain_base/payment_mode.py rename {__unported__/account_banking_pain_base => account_banking_pain_base}/payment_mode_view.xml (100%) create mode 100644 account_banking_pain_base/views/payment_line_view.xml create mode 100644 account_banking_pain_base/views/payment_mode_view.xml create mode 100644 account_banking_pain_base/views/res_company_view.xml create mode 100644 account_banking_payment_export/__init__.py rename {__unported__/account_banking_payment_export => account_banking_payment_export}/__openerp__.py (59%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/data/payment_mode_type.xml (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/demo/banking_demo.xml (94%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/i18n/account_banking_payment_export.pot (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/i18n/nl.po (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/migrations/7.0.0.1.165/pre-migration.py (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/model/__init__.py (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/model/account_move_line.py (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/model/account_payment.py (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/model/bank_payment_manual.py (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/model/payment_mode.py (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/model/payment_mode_type.py (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/model/payment_order_create.py (100%) create mode 100644 account_banking_payment_export/models/__init__.py create mode 100644 account_banking_payment_export/models/account_move_line.py create mode 100644 account_banking_payment_export/models/account_payment.py create mode 100644 account_banking_payment_export/models/payment_mode.py create mode 100644 account_banking_payment_export/models/payment_mode_type.py rename {__unported__/account_banking_payment_export => account_banking_payment_export}/security/ir.model.access.csv (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/view/account_payment.xml (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/view/bank_payment_manual.xml (100%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/view/payment_mode.xml (97%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/view/payment_mode_type.xml (77%) rename {__unported__/account_banking_payment_export => account_banking_payment_export}/view/payment_order_create_view.xml (100%) create mode 100644 account_banking_payment_export/wizard/__init__.py create mode 100644 account_banking_payment_export/wizard/bank_payment_manual.py create mode 100644 account_banking_payment_export/wizard/bank_payment_manual.xml create mode 100644 account_banking_payment_export/wizard/payment_order_create.py create mode 100644 account_banking_payment_export/wizard/payment_order_create_view.xml create mode 100644 account_banking_sepa_credit_transfer/__init__.py rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/__openerp__.py (71%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/account_banking_sepa.py (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/account_banking_sepa_view.xml (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/data/pain.001.001.02.xsd (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/data/pain.001.001.03.xsd (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/data/pain.001.001.04.xsd (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/data/pain.001.001.05.xsd (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/data/payment_type_sepa_sct.xml (88%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer/demo}/sepa_credit_transfer_demo.xml (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/i18n/account_banking_sepa_credit_transfer.pot (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/i18n/fr.po (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/i18n/nl.po (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer/models}/__init__.py (98%) create mode 100644 account_banking_sepa_credit_transfer/models/account_banking_sepa.py rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/security/ir.model.access.csv (100%) create mode 100644 account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml create mode 100644 account_banking_sepa_credit_transfer/static/description/icon.svg rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/static/src/img/icon.png (100%) create mode 100644 account_banking_sepa_credit_transfer/views/account_banking_sepa_view.xml rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/wizard/__init__.py (100%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/wizard/export_sepa.py (95%) rename {__unported__/account_banking_sepa_credit_transfer => account_banking_sepa_credit_transfer}/wizard/export_sepa_view.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/__init__.py (94%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/__openerp__.py (70%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/account_banking_sdd.py (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/account_banking_sdd_view.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/account_invoice_view.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/account_payment_view.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/company.py (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/company_view.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit/data}/mandate_expire_cron.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/data/mandate_reference_sequence.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/data/pain.008.001.02.xsd (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/data/pain.008.001.03.xsd (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/data/pain.008.001.04.xsd (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/data/payment_type_sdd.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit/demo}/sepa_direct_debit_demo.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/i18n/account_banking_sepa_direct_debit.pot (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/i18n/fr.po (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/i18n/nl.po (100%) create mode 100644 account_banking_sepa_direct_debit/mandate_expire_cron.xml create mode 100644 account_banking_sepa_direct_debit/models/__init__.py create mode 100644 account_banking_sepa_direct_debit/models/account_invoice.py create mode 100644 account_banking_sepa_direct_debit/models/banking_export_sdd.py create mode 100644 account_banking_sepa_direct_debit/models/payment_line.py create mode 100644 account_banking_sepa_direct_debit/models/res_company.py create mode 100644 account_banking_sepa_direct_debit/models/res_partner_bank.py create mode 100644 account_banking_sepa_direct_debit/models/sdd_mandate.py rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/res_partner_bank_view.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/sdd_mandate_view.xml (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/security/ir.model.access.csv (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/security/original_mandate_required_security.xml (100%) create mode 100644 account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml create mode 100644 account_banking_sepa_direct_debit/static/description/icon.svg rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/static/src/img/icon.png (100%) create mode 100644 account_banking_sepa_direct_debit/views/account_banking_sdd_view.xml create mode 100644 account_banking_sepa_direct_debit/views/account_invoice_view.xml create mode 100644 account_banking_sepa_direct_debit/views/account_payment_view.xml create mode 100644 account_banking_sepa_direct_debit/views/res_company_view.xml create mode 100644 account_banking_sepa_direct_debit/views/res_partner_bank_view.xml create mode 100644 account_banking_sepa_direct_debit/views/sdd_mandate_view.xml rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/wizard/__init__.py (100%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/wizard/export_sdd.py (98%) rename {__unported__/account_banking_sepa_direct_debit => account_banking_sepa_direct_debit}/wizard/export_sdd_view.xml (100%) create mode 100644 account_direct_debit/__init__.py rename {__unported__/account_direct_debit => account_direct_debit}/__openerp__.py (80%) rename {__unported__/account_direct_debit => account_direct_debit}/data/account_payment_term.xml (100%) rename {__unported__/account_direct_debit => account_direct_debit}/i18n/account_direct_debit.pot (100%) rename {__unported__/account_direct_debit => account_direct_debit}/i18n/nl.po (100%) rename {__unported__/account_direct_debit => account_direct_debit}/migrations/7.0.2/post-migration.py (100%) rename {__unported__/account_direct_debit => account_direct_debit}/migrations/7.0.2/pre-migration.py (100%) create mode 100644 account_direct_debit/models/__init__.py rename {__unported__/account_direct_debit/model => account_direct_debit/models}/account_invoice.py (95%) rename {__unported__/account_direct_debit/model => account_direct_debit/models}/account_move_line.py (86%) rename {__unported__/account_direct_debit/model => account_direct_debit/models}/account_payment.py (76%) rename {__unported__/account_direct_debit/model => account_direct_debit/models}/payment_line.py (76%) rename {__unported__/account_direct_debit/view => account_direct_debit/views}/account_invoice.xml (100%) rename {__unported__/account_direct_debit/view => account_direct_debit/views}/account_payment.xml (71%) rename {__unported__/account_direct_debit/view => account_direct_debit/views}/payment_mode.xml (100%) rename {__unported__/account_direct_debit/view => account_direct_debit/views}/payment_mode_type.xml (52%) create mode 100644 account_direct_debit/wizard/__init__.py rename {__unported__/account_direct_debit/model => account_direct_debit/wizard}/payment_order_create.py (80%) rename {__unported__/account_direct_debit => account_direct_debit}/workflow/account_invoice.xml (100%) create mode 100644 account_payment_partner/__init__.py rename {__unported__/account_payment_partner => account_payment_partner}/__openerp__.py (88%) rename {__unported__/account_payment_partner => account_payment_partner}/demo/partner_demo.xml (100%) rename {__unported__/account_payment_partner => account_payment_partner}/i18n/account_payment_partner.pot (100%) rename {__unported__/account_payment_partner => account_payment_partner}/i18n/nl.po (100%) rename {__unported__/account_payment_partner/model => account_payment_partner/models}/__init__.py (94%) rename {__unported__/account_payment_partner/model => account_payment_partner/models}/account_invoice.py (65%) rename {__unported__/account_payment_partner/model => account_payment_partner/models}/partner.py (100%) rename {__unported__/account_payment_partner/model => account_payment_partner/models}/payment_order_create.py (100%) create mode 100644 account_payment_partner/models/res_partner.py rename {__unported__/account_payment_partner/view => account_payment_partner/views}/account_invoice.xml (100%) create mode 100644 account_payment_partner/views/account_invoice_view.xml rename {__unported__/account_payment_partner/view => account_payment_partner/views}/partner.xml (100%) create mode 100644 account_payment_partner/views/res_partner_view.xml rename {__unported__/account_payment_partner => account_payment_partner/wizard}/__init__.py (96%) create mode 100644 account_payment_partner/wizard/payment_order_create.py rename {__unported__/account_payment_purchase => account_payment_purchase}/__init__.py (98%) rename {__unported__/account_payment_purchase => account_payment_purchase}/__openerp__.py (82%) rename {__unported__/account_payment_purchase => account_payment_purchase}/i18n/account_payment_purchase.pot (100%) rename {__unported__/account_payment_purchase => account_payment_purchase}/i18n/fr.po (100%) rename {__unported__/account_payment_purchase => account_payment_purchase}/i18n/nl.po (100%) rename {__unported__/account_payment_purchase => account_payment_purchase}/model/__init__.py (100%) rename {__unported__/account_payment_purchase => account_payment_purchase}/model/purchase.py (100%) rename {__unported__/account_payment_purchase => account_payment_purchase}/model/stock.py (100%) create mode 100644 account_payment_purchase/models/__init__.py create mode 100644 account_payment_purchase/models/purchase_order.py create mode 100644 account_payment_purchase/models/stock_picking.py rename {__unported__/account_payment_purchase => account_payment_purchase}/view/purchase.xml (100%) create mode 100644 account_payment_purchase/views/purchase_order_view.xml rename {__unported__/account_payment_sale => account_payment_sale}/__init__.py (98%) rename {__unported__/account_payment_sale => account_payment_sale}/__openerp__.py (85%) rename {__unported__/account_payment_sale => account_payment_sale}/i18n/account_payment_sale.pot (100%) rename {__unported__/account_payment_sale => account_payment_sale}/i18n/nl.po (100%) rename {__unported__/account_payment_sale => account_payment_sale}/model/__init__.py (100%) rename {__unported__/account_payment_sale => account_payment_sale}/model/sale.py (100%) create mode 100644 account_payment_sale/models/__init__.py create mode 100644 account_payment_sale/models/sale_order.py create mode 100644 account_payment_sale/models/stock_picking.py rename {__unported__/account_payment_sale => account_payment_sale}/view/sale.xml (100%) create mode 100644 account_payment_sale/views/sale_order_view.xml diff --git a/__unported__/account_banking_payment_export/__init__.py b/__unported__/account_banking_payment_export/__init__.py deleted file mode 100644 index 9186ee3ad..000000000 --- a/__unported__/account_banking_payment_export/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import model diff --git a/__unported__/account_direct_debit/__init__.py b/__unported__/account_direct_debit/__init__.py deleted file mode 100644 index 16e8b082f..000000000 --- a/__unported__/account_direct_debit/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import model diff --git a/__unported__/account_direct_debit/model/__init__.py b/__unported__/account_direct_debit/model/__init__.py deleted file mode 100644 index b3558c40e..000000000 --- a/__unported__/account_direct_debit/model/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -import account_payment -import payment_line -import account_move_line -import account_invoice -import payment_order_create diff --git a/__unported__/account_payment_shortcut/__init__.py b/__unported__/account_payment_shortcut/__init__.py deleted file mode 100644 index c9dbb3cf6..000000000 --- a/__unported__/account_payment_shortcut/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -from . import payment_order diff --git a/__unported__/account_payment_shortcut/__openerp__.py b/__unported__/account_payment_shortcut/__openerp__.py deleted file mode 100644 index 7f35ab096..000000000 --- a/__unported__/account_payment_shortcut/__openerp__.py +++ /dev/null @@ -1,34 +0,0 @@ -############################################################################## -# -# Copyright (C) 2011 Therp BV (). -# 2011 Smile BV (). -# All Rights Reserved -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -{ - 'name': 'Account Payment Invoice Selection Shortcut', - 'version': '1.134', - 'license': 'AGPL-3', - 'author': 'Smile / Therp BV', - 'website': 'https://launchpad.net/banking-addons', - 'category': 'Banking addons', - 'depends': ['account_payment'], - 'description': ''' -When composing a payment order, select all candidates by default -(in the second step of the "Select invoices to pay" wizard). - ''', - 'installable': False, -} diff --git a/__unported__/account_payment_shortcut/payment_order.py b/__unported__/account_payment_shortcut/payment_order.py deleted file mode 100644 index b44c6b8da..000000000 --- a/__unported__/account_payment_shortcut/payment_order.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2011 - 2013 Therp BV (). -# -# All other contributions are (C) by their respective contributors -# -# All Rights Reserved -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import orm - - -class payment_order_create(orm.TransientModel): - _inherit = 'payment.order.create' - - def default_get(self, cr, uid, fields_list, context=None): - """ - Automatically add the candidate move lines to - the payment order, instead of only applying them - to the domain. - - We make use of the fact that the search_entries - method passes an action without a res_id so that a - new instance is created. Inject the line_ids, which have - been placed in the context at object - creation time. - """ - if context is None: - context = {} - res = super(payment_order_create, self).default_get( - cr, uid, fields_list, context=context) - - if (fields_list - and 'entries' in fields_list - and 'entries' not in res - and context.get('line_ids', False)): - res['entries'] = context['line_ids'] - - return res diff --git a/account_banking_pain_base/__init__.py b/account_banking_pain_base/__init__.py new file mode 100644 index 000000000..b69a01a1b --- /dev/null +++ b/account_banking_pain_base/__init__.py @@ -0,0 +1,23 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# PAIN Base module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import models diff --git a/__unported__/account_banking_pain_base/__openerp__.py b/account_banking_pain_base/__openerp__.py similarity index 85% rename from __unported__/account_banking_pain_base/__openerp__.py rename to account_banking_pain_base/__openerp__.py index 23e345e85..e7b199213 100644 --- a/__unported__/account_banking_pain_base/__openerp__.py +++ b/account_banking_pain_base/__openerp__.py @@ -26,15 +26,16 @@ 'license': 'AGPL-3', 'author': 'Akretion, Noviat', 'website': 'http://openerp-community-association.org/', + 'contributors': ['Pedro M. Baeza '], 'category': 'Hidden', 'depends': ['account_banking_payment_export'], 'external_dependencies': { 'python': ['unidecode', 'lxml'], }, 'data': [ - 'payment_line_view.xml', - 'payment_mode_view.xml', - 'company_view.xml', + 'views/payment_line_view.xml', + 'views/payment_mode_view.xml', + 'views/res_company_view.xml', ], 'description': ''' Base module for PAIN file generation @@ -43,14 +44,10 @@ Base module for PAIN file generation This module contains fields and functions that are used by the module for SEPA Credit Transfer (account_banking_sepa_credit_transfer) and SEPA Direct Debit (account_banking_sepa_direct_debit). This module doesn't provide any -functionnality by itself. +functionality by itself. -This module is part of the banking addons: - https://www.github.com/OCA/banking-addons - -This module was started during the Akretion-Noviat code sprint of -November 21st 2013 in Epiais les Louvres (France). +This module was started during the Akretion-Noviat code sprint of November +21st 2013 in Epiais les Louvres (France). ''', - 'active': False, - 'installable': False, + 'installable': True, } diff --git a/__unported__/account_banking_pain_base/banking_export_pain.py b/account_banking_pain_base/banking_export_pain.py similarity index 100% rename from __unported__/account_banking_pain_base/banking_export_pain.py rename to account_banking_pain_base/banking_export_pain.py diff --git a/__unported__/account_banking_pain_base/company.py b/account_banking_pain_base/company.py similarity index 100% rename from __unported__/account_banking_pain_base/company.py rename to account_banking_pain_base/company.py diff --git a/__unported__/account_banking_pain_base/company_view.xml b/account_banking_pain_base/company_view.xml similarity index 100% rename from __unported__/account_banking_pain_base/company_view.xml rename to account_banking_pain_base/company_view.xml diff --git a/__unported__/account_banking_pain_base/i18n/account_banking_pain_base.pot b/account_banking_pain_base/i18n/account_banking_pain_base.pot similarity index 100% rename from __unported__/account_banking_pain_base/i18n/account_banking_pain_base.pot rename to account_banking_pain_base/i18n/account_banking_pain_base.pot diff --git a/__unported__/account_banking_pain_base/i18n/fr.po b/account_banking_pain_base/i18n/fr.po similarity index 100% rename from __unported__/account_banking_pain_base/i18n/fr.po rename to account_banking_pain_base/i18n/fr.po diff --git a/__unported__/account_banking_pain_base/i18n/nl.po b/account_banking_pain_base/i18n/nl.po similarity index 100% rename from __unported__/account_banking_pain_base/i18n/nl.po rename to account_banking_pain_base/i18n/nl.po diff --git a/__unported__/account_banking_pain_base/__init__.py b/account_banking_pain_base/models/__init__.py similarity index 97% rename from __unported__/account_banking_pain_base/__init__.py rename to account_banking_pain_base/models/__init__.py index 6662843e6..f1e6551bf 100644 --- a/__unported__/account_banking_pain_base/__init__.py +++ b/account_banking_pain_base/models/__init__.py @@ -22,5 +22,5 @@ from . import payment_line from . import payment_mode -from . import company +from . import res_company from . import banking_export_pain diff --git a/account_banking_pain_base/models/banking_export_pain.py b/account_banking_pain_base/models/banking_export_pain.py new file mode 100644 index 000000000..17961a29a --- /dev/null +++ b/account_banking_pain_base/models/banking_export_pain.py @@ -0,0 +1,440 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# PAIN Base module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm +from openerp.tools.translate import _ +from openerp.tools.safe_eval import safe_eval +from datetime import datetime +from unidecode import unidecode +from lxml import etree +from openerp import tools +import logging +import base64 + +logger = logging.getLogger(__name__) + + +class BankingExportPain(orm.AbstractModel): + _name = 'banking.export.pain' + + def _validate_iban(self, cr, uid, iban, context=None): + '''if IBAN is valid, returns IBAN + if IBAN is NOT valid, raises an error message''' + partner_bank_obj = self.pool.get('res.partner.bank') + if partner_bank_obj.is_iban_valid(cr, uid, iban, context=context): + return iban.replace(' ', '') + else: + raise orm.except_orm( + _('Error:'), _("This IBAN is not valid : %s") % iban) + + def _prepare_field(self, cr, uid, field_name, field_value, eval_ctx, + max_size=0, gen_args=None, context=None): + """This function is designed to be inherited !""" + if gen_args is None: + gen_args = {} + assert isinstance(eval_ctx, dict), 'eval_ctx must contain a dict' + try: + value = safe_eval(field_value, eval_ctx) + # SEPA uses XML ; XML = UTF-8 ; UTF-8 = support for all characters + # But we are dealing with banks... + # and many banks don't want non-ASCCI characters ! + # cf section 1.4 "Character set" of the SEPA Credit Transfer + # Scheme Customer-to-bank guidelines + if gen_args.get('convert_to_ascii'): + value = unidecode(value) + unallowed_ascii_chars = [ + '"', '#', '$', '%', '&', '*', ';', '<', '>', '=', '@', + '[', ']', '^', '_', '`', '{', '}', '|', '~', '\\', '!'] + for unallowed_ascii_char in unallowed_ascii_chars: + value = value.replace(unallowed_ascii_char, '-') + except: + line = eval_ctx.get('line') + if line: + raise orm.except_orm( + _('Error:'), + _("Cannot compute the '%s' of the Payment Line with " + "reference '%s'.") + % (field_name, line.name)) + else: + raise orm.except_orm( + _('Error:'), + _("Cannot compute the '%s'.") % field_name) + if not isinstance(value, (str, unicode)): + raise orm.except_orm( + _('Field type error:'), + _("The type of the field '%s' is %s. It should be a string " + "or unicode.") + % (field_name, type(value))) + if not value: + raise orm.except_orm( + _('Error:'), + _("The '%s' is empty or 0. It should have a non-null value.") + % field_name) + if max_size and len(value) > max_size: + value = value[0:max_size] + return value + + def _prepare_export_sepa( + self, cr, uid, total_amount, transactions_count, xml_string, + gen_args, context=None): + return { + 'batch_booking': gen_args['sepa_export'].batch_booking, + 'charge_bearer': gen_args['sepa_export'].charge_bearer, + 'total_amount': total_amount, + 'nb_transactions': transactions_count, + 'file': base64.encodestring(xml_string), + 'payment_order_ids': [( + 6, 0, [x.id for x in gen_args['sepa_export'].payment_order_ids] + )], + } + + def _validate_xml(self, cr, uid, xml_string, gen_args, context=None): + xsd_etree_obj = etree.parse( + tools.file_open(gen_args['pain_xsd_file'])) + official_pain_schema = etree.XMLSchema(xsd_etree_obj) + + try: + root_to_validate = etree.fromstring(xml_string) + official_pain_schema.assertValid(root_to_validate) + except Exception, e: + logger.warning( + "The XML file is invalid against the XML Schema Definition") + logger.warning(xml_string) + logger.warning(e) + raise orm.except_orm( + _('Error:'), + _("The generated XML file is not valid against the official " + "XML Schema Definition. The generated XML file and the " + "full error have been written in the server logs. Here " + "is the error, which may give you an idea on the cause " + "of the problem : %s") + % str(e)) + return True + + def finalize_sepa_file_creation( + self, cr, uid, ids, xml_root, total_amount, transactions_count, + gen_args, context=None): + xml_string = etree.tostring( + xml_root, pretty_print=True, encoding='UTF-8', + xml_declaration=True) + logger.debug( + "Generated SEPA XML file in format %s below" + % gen_args['pain_flavor']) + logger.debug(xml_string) + self._validate_xml(cr, uid, xml_string, gen_args, context=context) + + file_id = gen_args['file_obj'].create( + cr, uid, self._prepare_export_sepa( + cr, uid, total_amount, transactions_count, + xml_string, gen_args, context=context), + context=context) + + self.write( + cr, uid, ids, { + 'file_id': file_id, + 'state': 'finish', + }, context=context) + + action = { + 'name': 'SEPA File', + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': self._name, + 'res_id': ids[0], + 'target': 'new', + } + return action + + def generate_group_header_block( + self, cr, uid, parent_node, gen_args, context=None): + group_header_1_0 = etree.SubElement(parent_node, 'GrpHdr') + message_identification_1_1 = etree.SubElement( + group_header_1_0, 'MsgId') + message_identification_1_1.text = self._prepare_field( + cr, uid, 'Message Identification', + 'sepa_export.payment_order_ids[0].reference', + {'sepa_export': gen_args['sepa_export']}, 35, + gen_args=gen_args, context=context) + creation_date_time_1_2 = etree.SubElement(group_header_1_0, 'CreDtTm') + creation_date_time_1_2.text = datetime.strftime( + datetime.today(), '%Y-%m-%dT%H:%M:%S') + if gen_args.get('pain_flavor') == 'pain.001.001.02': + # batch_booking is in "Group header" with pain.001.001.02 + # and in "Payment info" in pain.001.001.03/04 + batch_booking = etree.SubElement(group_header_1_0, 'BtchBookg') + batch_booking.text = \ + str(gen_args['sepa_export'].batch_booking).lower() + nb_of_transactions_1_6 = etree.SubElement( + group_header_1_0, 'NbOfTxs') + control_sum_1_7 = etree.SubElement(group_header_1_0, 'CtrlSum') + # Grpg removed in pain.001.001.03 + if gen_args.get('pain_flavor') == 'pain.001.001.02': + grouping = etree.SubElement(group_header_1_0, 'Grpg') + grouping.text = 'GRPD' + self.generate_initiating_party_block( + cr, uid, group_header_1_0, gen_args, + context=context) + return group_header_1_0, nb_of_transactions_1_6, control_sum_1_7 + + def generate_start_payment_info_block( + self, cr, uid, parent_node, payment_info_ident, + priority, local_instrument, sequence_type, requested_date, + eval_ctx, gen_args, context=None): + payment_info_2_0 = etree.SubElement(parent_node, 'PmtInf') + payment_info_identification_2_1 = etree.SubElement( + payment_info_2_0, 'PmtInfId') + payment_info_identification_2_1.text = self._prepare_field( + cr, uid, 'Payment Information Identification', + payment_info_ident, eval_ctx, 35, + gen_args=gen_args, context=context) + payment_method_2_2 = etree.SubElement(payment_info_2_0, 'PmtMtd') + payment_method_2_2.text = gen_args['payment_method'] + nb_of_transactions_2_4 = False + control_sum_2_5 = False + if gen_args.get('pain_flavor') != 'pain.001.001.02': + batch_booking_2_3 = etree.SubElement(payment_info_2_0, 'BtchBookg') + batch_booking_2_3.text = \ + str(gen_args['sepa_export'].batch_booking).lower() + # The "SEPA Customer-to-bank + # Implementation guidelines" for SCT and SDD says that control sum + # and nb_of_transactions should be present + # at both "group header" level and "payment info" level + nb_of_transactions_2_4 = etree.SubElement( + payment_info_2_0, 'NbOfTxs') + control_sum_2_5 = etree.SubElement(payment_info_2_0, 'CtrlSum') + payment_type_info_2_6 = etree.SubElement( + payment_info_2_0, 'PmtTpInf') + if priority: + instruction_priority_2_7 = etree.SubElement( + payment_type_info_2_6, 'InstrPrty') + instruction_priority_2_7.text = priority + service_level_2_8 = etree.SubElement( + payment_type_info_2_6, 'SvcLvl') + service_level_code_2_9 = etree.SubElement(service_level_2_8, 'Cd') + service_level_code_2_9.text = 'SEPA' + if local_instrument: + local_instrument_2_11 = etree.SubElement( + payment_type_info_2_6, 'LclInstrm') + local_instr_code_2_12 = etree.SubElement( + local_instrument_2_11, 'Cd') + local_instr_code_2_12.text = local_instrument + if sequence_type: + sequence_type_2_14 = etree.SubElement( + payment_type_info_2_6, 'SeqTp') + sequence_type_2_14.text = sequence_type + + if gen_args['payment_method'] == 'DD': + request_date_tag = 'ReqdColltnDt' + else: + request_date_tag = 'ReqdExctnDt' + requested_date_2_17 = etree.SubElement( + payment_info_2_0, request_date_tag) + requested_date_2_17.text = requested_date + return payment_info_2_0, nb_of_transactions_2_4, control_sum_2_5 + + def generate_initiating_party_block( + self, cr, uid, parent_node, gen_args, context=None): + my_company_name = self._prepare_field( + cr, uid, 'Company Name', + 'sepa_export.payment_order_ids[0].mode.bank_id.partner_id.name', + {'sepa_export': gen_args['sepa_export']}, + gen_args.get('name_maxsize'), gen_args=gen_args, context=context) + initiating_party_1_8 = etree.SubElement(parent_node, 'InitgPty') + initiating_party_name = etree.SubElement(initiating_party_1_8, 'Nm') + initiating_party_name.text = my_company_name + initiating_party_identifier = self.pool['res.company'].\ + _get_initiating_party_identifier( + cr, uid, + gen_args['sepa_export'].payment_order_ids[0].company_id.id, + context=context) + initiating_party_issuer = gen_args['sepa_export'].\ + payment_order_ids[0].company_id.initiating_party_issuer + if initiating_party_identifier and initiating_party_issuer: + iniparty_id = etree.SubElement(initiating_party_1_8, 'Id') + iniparty_org_id = etree.SubElement(iniparty_id, 'OrgId') + iniparty_org_other = etree.SubElement(iniparty_org_id, 'Othr') + iniparty_org_other_id = etree.SubElement(iniparty_org_other, 'Id') + iniparty_org_other_id.text = initiating_party_identifier + iniparty_org_other_issuer = etree.SubElement( + iniparty_org_other, 'Issr') + iniparty_org_other_issuer.text = initiating_party_issuer + return True + + def generate_party_agent( + self, cr, uid, parent_node, party_type, party_type_label, + order, party_name, iban, bic, eval_ctx, gen_args, context=None): + '''Generate the piece of the XML file corresponding to BIC + This code is mutualized between TRF and DD''' + assert order in ('B', 'C'), "Order can be 'B' or 'C'" + try: + bic = self._prepare_field( + cr, uid, '%s BIC' % party_type_label, bic, eval_ctx, + gen_args=gen_args, context=context) + party_agent = etree.SubElement(parent_node, '%sAgt' % party_type) + party_agent_institution = etree.SubElement( + party_agent, 'FinInstnId') + party_agent_bic = etree.SubElement( + party_agent_institution, gen_args.get('bic_xml_tag')) + party_agent_bic.text = bic + except orm.except_orm: + if order == 'C': + if iban[0:2] != gen_args['initiating_party_country_code']: + raise orm.except_orm( + _('Error:'), + _("The bank account with IBAN '%s' of partner '%s' " + "must have an associated BIC because it is a " + "cross-border SEPA operation.") + % (iban, party_name)) + if order == 'B' or ( + order == 'C' and gen_args['payment_method'] == 'DD'): + party_agent = etree.SubElement( + parent_node, '%sAgt' % party_type) + party_agent_institution = etree.SubElement( + party_agent, 'FinInstnId') + party_agent_other = etree.SubElement( + party_agent_institution, 'Othr') + party_agent_other_identification = etree.SubElement( + party_agent_other, 'Id') + party_agent_other_identification.text = 'NOTPROVIDED' + # for Credit Transfers, in the 'C' block, if BIC is not provided, + # we should not put the 'Creditor Agent' block at all, + # as per the guidelines of the EPC + return True + + def generate_party_block( + self, cr, uid, parent_node, party_type, order, name, iban, bic, + eval_ctx, gen_args, context=None): + '''Generate the piece of the XML file corresponding to Name+IBAN+BIC + This code is mutualized between TRF and DD''' + assert order in ('B', 'C'), "Order can be 'B' or 'C'" + if party_type == 'Cdtr': + party_type_label = 'Creditor' + elif party_type == 'Dbtr': + party_type_label = 'Debtor' + party_name = self._prepare_field( + cr, uid, '%s Name' % party_type_label, name, eval_ctx, + gen_args.get('name_maxsize'), + gen_args=gen_args, context=context) + piban = self._prepare_field( + cr, uid, '%s IBAN' % party_type_label, iban, eval_ctx, + gen_args=gen_args, + context=context) + viban = self._validate_iban(cr, uid, piban, context=context) + # At C level, the order is : BIC, Name, IBAN + # At B level, the order is : Name, IBAN, BIC + if order == 'B': + gen_args['initiating_party_country_code'] = viban[0:2] + elif order == 'C': + self.generate_party_agent( + cr, uid, parent_node, party_type, party_type_label, + order, party_name, viban, bic, + eval_ctx, gen_args, context=context) + party = etree.SubElement(parent_node, party_type) + party_nm = etree.SubElement(party, 'Nm') + party_nm.text = party_name + party_account = etree.SubElement( + parent_node, '%sAcct' % party_type) + party_account_id = etree.SubElement(party_account, 'Id') + party_account_iban = etree.SubElement( + party_account_id, 'IBAN') + party_account_iban.text = viban + if order == 'B': + self.generate_party_agent( + cr, uid, parent_node, party_type, party_type_label, + order, party_name, viban, bic, + eval_ctx, gen_args, context=context) + return True + + def generate_remittance_info_block( + self, cr, uid, parent_node, line, gen_args, context=None): + + remittance_info_2_91 = etree.SubElement( + parent_node, 'RmtInf') + if line.state == 'normal': + remittance_info_unstructured_2_99 = etree.SubElement( + remittance_info_2_91, 'Ustrd') + remittance_info_unstructured_2_99.text = \ + self._prepare_field( + cr, uid, 'Remittance Unstructured Information', + 'line.communication', {'line': line}, 140, + gen_args=gen_args, + context=context) + else: + if not line.struct_communication_type: + raise orm.except_orm( + _('Error:'), + _("Missing 'Structured Communication Type' on payment " + "line with reference '%s'.") + % (line.name)) + remittance_info_structured_2_100 = etree.SubElement( + remittance_info_2_91, 'Strd') + creditor_ref_information_2_120 = etree.SubElement( + remittance_info_structured_2_100, 'CdtrRefInf') + if gen_args.get('pain_flavor') == 'pain.001.001.02': + creditor_ref_info_type_2_121 = etree.SubElement( + creditor_ref_information_2_120, 'CdtrRefTp') + creditor_ref_info_type_code_2_123 = etree.SubElement( + creditor_ref_info_type_2_121, 'Cd') + creditor_ref_info_type_issuer_2_125 = etree.SubElement( + creditor_ref_info_type_2_121, 'Issr') + creditor_reference_2_126 = etree.SubElement( + creditor_ref_information_2_120, 'CdtrRef') + else: + creditor_ref_info_type_2_121 = etree.SubElement( + creditor_ref_information_2_120, 'Tp') + creditor_ref_info_type_or_2_122 = etree.SubElement( + creditor_ref_info_type_2_121, 'CdOrPrtry') + creditor_ref_info_type_code_2_123 = etree.SubElement( + creditor_ref_info_type_or_2_122, 'Cd') + creditor_ref_info_type_issuer_2_125 = etree.SubElement( + creditor_ref_info_type_2_121, 'Issr') + creditor_reference_2_126 = etree.SubElement( + creditor_ref_information_2_120, 'Ref') + + creditor_ref_info_type_code_2_123.text = 'SCOR' + creditor_ref_info_type_issuer_2_125.text = \ + line.struct_communication_type + creditor_reference_2_126.text = \ + self._prepare_field( + cr, uid, 'Creditor Structured Reference', + 'line.communication', {'line': line}, 35, + gen_args=gen_args, + context=context) + return True + + def generate_creditor_scheme_identification( + self, cr, uid, parent_node, identification, identification_label, + eval_ctx, scheme_name_proprietary, gen_args, context=None): + csi_id = etree.SubElement( + parent_node, 'Id') + csi_privateid = csi_id = etree.SubElement(csi_id, 'PrvtId') + csi_other = etree.SubElement(csi_privateid, 'Othr') + csi_other_id = etree.SubElement(csi_other, 'Id') + csi_other_id.text = self._prepare_field( + cr, uid, identification_label, identification, eval_ctx, + gen_args=gen_args, context=context) + csi_scheme_name = etree.SubElement(csi_other, 'SchmeNm') + csi_scheme_name_proprietary = etree.SubElement( + csi_scheme_name, 'Prtry') + csi_scheme_name_proprietary.text = scheme_name_proprietary + return True diff --git a/__unported__/account_banking_pain_base/payment_line.py b/account_banking_pain_base/models/payment_line.py similarity index 100% rename from __unported__/account_banking_pain_base/payment_line.py rename to account_banking_pain_base/models/payment_line.py diff --git a/__unported__/account_banking_pain_base/payment_mode.py b/account_banking_pain_base/models/payment_mode.py similarity index 100% rename from __unported__/account_banking_pain_base/payment_mode.py rename to account_banking_pain_base/models/payment_mode.py diff --git a/account_banking_pain_base/models/res_company.py b/account_banking_pain_base/models/res_company.py new file mode 100644 index 000000000..f63efc29e --- /dev/null +++ b/account_banking_pain_base/models/res_company.py @@ -0,0 +1,82 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# PAIN Base module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# Copyright (C) 2013 Noviat (http://www.noviat.com) +# @author: Alexis de Lattre +# @author: Luc de Meyer (Noviat) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm, fields + + +class ResCompany(orm.Model): + _inherit = 'res.company' + + _columns = { + 'initiating_party_issuer': fields.char( + 'Initiating Party Issuer', size=35, + help="This will be used as the 'Initiating Party Issuer' in the " + "PAIN files generated by OpenERP."), + } + + def _get_initiating_party_identifier( + self, cr, uid, company_id, context=None): + """The code here may be different from one country to another. + If you need to add support for an additionnal country, you can + contribute your code here or inherit this function in the + localization modules for your country""" + assert isinstance(company_id, int), 'Only one company ID' + company = self.browse(cr, uid, company_id, context=context) + company_vat = company.vat + party_identifier = False + if company_vat: + country_code = company_vat[0:2].upper() + if country_code == 'BE': + party_identifier = company_vat[2:].replace(' ', '') + elif country_code == 'ES': + party_identifier = company.sepa_creditor_identifier + return party_identifier + + def _initiating_party_issuer_default(self, cr, uid, context=None): + """If you need to add support for an additionnal country, you can + add an entry in the dict "party_issuer_per_country" here + or inherit this function in the localization modules for + your country""" + initiating_party_issuer = '' + # If your country require the 'Initiating Party Issuer', you should + # contribute the entry for your country in the dict below + party_issuer_per_country = { + 'BE': 'KBO-BCE', # KBO-BCE = the registry of companies in Belgium + } + company_id = self._company_default_get( + cr, uid, 'res.company', context=context) + if company_id: + company = self.browse(cr, uid, company_id, context=context) + country_code = company.country_id.code + initiating_party_issuer = party_issuer_per_country.get( + country_code, '') + return initiating_party_issuer + + def _initiating_party_issuer_def(self, cr, uid, context=None): + return self._initiating_party_issuer_default( + cr, uid, context=context) + + _defaults = { + 'initiating_party_issuer': _initiating_party_issuer_def, + } diff --git a/account_banking_pain_base/payment_line.py b/account_banking_pain_base/payment_line.py new file mode 100644 index 000000000..0dffbcf42 --- /dev/null +++ b/account_banking_pain_base/payment_line.py @@ -0,0 +1,52 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# PAIN Base module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm, fields + + +class payment_line(orm.Model): + _inherit = 'payment.line' + + def _get_struct_communication_types(self, cr, uid, context=None): + return [('ISO', 'ISO')] + + _columns = { + 'priority': fields.selection([ + ('NORM', 'Normal'), + ('HIGH', 'High'), + ], 'Priority', + help="This field will be used as the 'Instruction Priority' in " + "the generated PAIN file."), + # Update size from 64 to 140, because PAIN allows 140 caracters + 'communication': fields.char( + 'Communication', size=140, required=True, + help="Used as the message between ordering customer and current " + "company. Depicts 'What do you want to say to the recipient " + "about this order ?'"), + 'struct_communication_type': fields.selection( + _get_struct_communication_types, 'Structured Communication Type'), + } + + _defaults = { + 'priority': 'NORM', + 'struct_communication_type': 'ISO', + } diff --git a/__unported__/account_banking_pain_base/payment_line_view.xml b/account_banking_pain_base/payment_line_view.xml similarity index 100% rename from __unported__/account_banking_pain_base/payment_line_view.xml rename to account_banking_pain_base/payment_line_view.xml diff --git a/account_banking_pain_base/payment_mode.py b/account_banking_pain_base/payment_mode.py new file mode 100644 index 000000000..540d01b67 --- /dev/null +++ b/account_banking_pain_base/payment_mode.py @@ -0,0 +1,39 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# PAIN Base module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm, fields + + +class payment_mode(orm.Model): + _inherit = 'payment.mode' + + _columns = { + 'convert_to_ascii': fields.boolean( + 'Convert to ASCII', + help="If active, OpenERP will convert each accented caracter to " + "the corresponding unaccented caracter, so that only ASCII " + "caracters are used in the generated PAIN file."), + } + + _defaults = { + 'convert_to_ascii': True, + } diff --git a/__unported__/account_banking_pain_base/payment_mode_view.xml b/account_banking_pain_base/payment_mode_view.xml similarity index 100% rename from __unported__/account_banking_pain_base/payment_mode_view.xml rename to account_banking_pain_base/payment_mode_view.xml diff --git a/account_banking_pain_base/views/payment_line_view.xml b/account_banking_pain_base/views/payment_line_view.xml new file mode 100644 index 000000000..f92b1bbf5 --- /dev/null +++ b/account_banking_pain_base/views/payment_line_view.xml @@ -0,0 +1,41 @@ + + + + + + + pain.base.payment.line.form + payment.line + + + + + + + + + + + + + + pain.base.payment.line.inside.order.form + payment.order + + + + + + + + + + + + + + diff --git a/account_banking_pain_base/views/payment_mode_view.xml b/account_banking_pain_base/views/payment_mode_view.xml new file mode 100644 index 000000000..2deb24999 --- /dev/null +++ b/account_banking_pain_base/views/payment_mode_view.xml @@ -0,0 +1,22 @@ + + + + + + + add.convert_to_ascii.in.payment.mode.form + payment.mode + + + + + + + + + + diff --git a/account_banking_pain_base/views/res_company_view.xml b/account_banking_pain_base/views/res_company_view.xml new file mode 100644 index 000000000..a98d9b641 --- /dev/null +++ b/account_banking_pain_base/views/res_company_view.xml @@ -0,0 +1,24 @@ + + + + + + + pain.group.on.res.company.form + res.company + + + + + + + + + + + + diff --git a/account_banking_payment_export/__init__.py b/account_banking_payment_export/__init__.py new file mode 100644 index 000000000..408a6001b --- /dev/null +++ b/account_banking_payment_export/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import models +from . import wizard diff --git a/__unported__/account_banking_payment_export/__openerp__.py b/account_banking_payment_export/__openerp__.py similarity index 59% rename from __unported__/account_banking_payment_export/__openerp__.py rename to account_banking_payment_export/__openerp__.py index 9a4317b59..bde925e2c 100644 --- a/__unported__/account_banking_payment_export/__openerp__.py +++ b/account_banking_payment_export/__openerp__.py @@ -47,43 +47,41 @@ ], 'data': [ 'view/account_payment.xml', - 'view/bank_payment_manual.xml', 'view/payment_mode.xml', 'view/payment_mode_type.xml', - 'view/payment_order_create_view.xml', + 'wizard/bank_payment_manual.xml', + 'wizard/payment_order_create_view.xml', 'data/payment_mode_type.xml', 'security/ir.model.access.csv', ], 'demo': ['demo/banking_demo.xml'], 'description': ''' - Infrastructure to export payment orders - plus some bug fixes and obvious enhancements to payment orders - that will hopefully land in offical addons one day. +Infrastructure to export payment orders plus some bug fixes and obvious +enhancements to payment orders that will hopefully land in offical addons one +day. - This technical module provides the base infrastructure to export - payment orders for electronic banking. It provides the following - technical features: - * a new payment.mode.type model - * payment.mode now has a mandatory type - * a better implementation of payment_mode.suitable_bank_types() based - on payment.mode.type - * the "make payment" button launches a wizard depending on the - payment.mode.type - * a manual payment mode type is provided as an example, with a default - "do nothing" wizard +This technical module provides the base infrastructure to export payment orders +for electronic banking. It provides the following technical features: - To enable the use of payment order to collect money for customers, - it adds a payment_order_type (payment|debit) as a basis of direct debit - support (this field becomes visible when account_direct_debit is - installed). - Refactoring note: this field should ideally go in account_direct_debit, - but account_banking_payment currently depends on it. +* a new payment.mode.type model +* payment.mode now has a mandatory type +* a better implementation of payment_mode.suitable_bank_types() based on + payment.mode.type +* the "make payment" button launches a wizard depending on the + payment.mode.type +* a manual payment mode type is provided as an example, with a default "do + nothing" wizard - Bug fixes and enhancement that should land in official addons: - * make the search function of the payment export wizard extensible - * fix lp:1275478: allow payment of customer refunds - * display the maturity date of the move lines when you are in - the wizard to select the lines to pay -''', - 'installable': False, +To enable the use of payment order to collect money for customers, +it adds a payment_order_type (payment|debit) as a basis of direct debit support +(this field becomes visible when account_direct_debit is installed). +Refactoring note: this field should ideally go in account_direct_debit, +but account_banking_payment currently depends on it. + +Bug fixes and enhancement that should land in official addons: + +* make the search function of the payment export wizard extensible +* fix lp:1275478: allow payment of customer refunds + ''', + 'installable': True, } diff --git a/__unported__/account_banking_payment_export/data/payment_mode_type.xml b/account_banking_payment_export/data/payment_mode_type.xml similarity index 100% rename from __unported__/account_banking_payment_export/data/payment_mode_type.xml rename to account_banking_payment_export/data/payment_mode_type.xml diff --git a/__unported__/account_banking_payment_export/demo/banking_demo.xml b/account_banking_payment_export/demo/banking_demo.xml similarity index 94% rename from __unported__/account_banking_payment_export/demo/banking_demo.xml rename to account_banking_payment_export/demo/banking_demo.xml index fd29e4c51..b11367bb8 100644 --- a/__unported__/account_banking_payment_export/demo/banking_demo.xml +++ b/account_banking_payment_export/demo/banking_demo.xml @@ -57,6 +57,10 @@ FTNOFRP1XXX + + + + Credit Trf Banque Postale diff --git a/__unported__/account_banking_payment_export/i18n/account_banking_payment_export.pot b/account_banking_payment_export/i18n/account_banking_payment_export.pot similarity index 100% rename from __unported__/account_banking_payment_export/i18n/account_banking_payment_export.pot rename to account_banking_payment_export/i18n/account_banking_payment_export.pot diff --git a/__unported__/account_banking_payment_export/i18n/nl.po b/account_banking_payment_export/i18n/nl.po similarity index 100% rename from __unported__/account_banking_payment_export/i18n/nl.po rename to account_banking_payment_export/i18n/nl.po diff --git a/__unported__/account_banking_payment_export/migrations/7.0.0.1.165/pre-migration.py b/account_banking_payment_export/migrations/7.0.0.1.165/pre-migration.py similarity index 100% rename from __unported__/account_banking_payment_export/migrations/7.0.0.1.165/pre-migration.py rename to account_banking_payment_export/migrations/7.0.0.1.165/pre-migration.py diff --git a/__unported__/account_banking_payment_export/model/__init__.py b/account_banking_payment_export/model/__init__.py similarity index 100% rename from __unported__/account_banking_payment_export/model/__init__.py rename to account_banking_payment_export/model/__init__.py diff --git a/__unported__/account_banking_payment_export/model/account_move_line.py b/account_banking_payment_export/model/account_move_line.py similarity index 100% rename from __unported__/account_banking_payment_export/model/account_move_line.py rename to account_banking_payment_export/model/account_move_line.py diff --git a/__unported__/account_banking_payment_export/model/account_payment.py b/account_banking_payment_export/model/account_payment.py similarity index 100% rename from __unported__/account_banking_payment_export/model/account_payment.py rename to account_banking_payment_export/model/account_payment.py diff --git a/__unported__/account_banking_payment_export/model/bank_payment_manual.py b/account_banking_payment_export/model/bank_payment_manual.py similarity index 100% rename from __unported__/account_banking_payment_export/model/bank_payment_manual.py rename to account_banking_payment_export/model/bank_payment_manual.py diff --git a/__unported__/account_banking_payment_export/model/payment_mode.py b/account_banking_payment_export/model/payment_mode.py similarity index 100% rename from __unported__/account_banking_payment_export/model/payment_mode.py rename to account_banking_payment_export/model/payment_mode.py diff --git a/__unported__/account_banking_payment_export/model/payment_mode_type.py b/account_banking_payment_export/model/payment_mode_type.py similarity index 100% rename from __unported__/account_banking_payment_export/model/payment_mode_type.py rename to account_banking_payment_export/model/payment_mode_type.py diff --git a/__unported__/account_banking_payment_export/model/payment_order_create.py b/account_banking_payment_export/model/payment_order_create.py similarity index 100% rename from __unported__/account_banking_payment_export/model/payment_order_create.py rename to account_banking_payment_export/model/payment_order_create.py diff --git a/account_banking_payment_export/models/__init__.py b/account_banking_payment_export/models/__init__.py new file mode 100644 index 000000000..2f044680a --- /dev/null +++ b/account_banking_payment_export/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +from . import account_payment +from . import payment_mode +from . import payment_mode_type +from . import account_move_line diff --git a/account_banking_payment_export/models/account_move_line.py b/account_banking_payment_export/models/account_move_line.py new file mode 100644 index 000000000..74bb47f81 --- /dev/null +++ b/account_banking_payment_export/models/account_move_line.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2004-2014 OpenERP S.A. (http://www.openerp.com/) +# (C) 2014 Akretion (http://www.akretion.com/) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm, fields +from operator import itemgetter + + +# All the code below aims at fixing one small issue in _to_pay_search() +# But _to_pay_search() is the search function of the field 'amount_to_pay' +# which is a field.function and these functions are not inheritable in OpenERP. +# So we have to inherit the field 'amount_to_pay' and duplicate the related +# functions +# If the patch that I proposed in this bug report +# https://bugs.launchpad.net/openobject-addons/+bug/1275478 +# is integrated in addons/account_payment, then we will be able to remove this +# file. -- Alexis de Lattre +class AccountMoveLine(orm.Model): + _inherit = 'account.move.line' + + def _amount_to_pay(self, cr, uid, ids, name, arg=None, context=None): + """ Return the amount still to pay regarding all the payemnt orders + (excepting cancelled orders)""" + if not ids: + return {} + cr.execute("""SELECT ml.id, + CASE WHEN ml.amount_currency < 0 + THEN - ml.amount_currency + ELSE ml.credit + END - + (SELECT coalesce(sum(amount_currency),0) + FROM payment_line pl + INNER JOIN payment_order po + ON (pl.order_id = po.id) + WHERE move_line_id = ml.id + AND po.state != 'cancel') AS amount + FROM account_move_line ml + WHERE id IN %s""", (tuple(ids),)) + r = dict(cr.fetchall()) + return r + + def _to_pay_search(self, cr, uid, obj, name, args, context=None): + if not args: + return [] + line_obj = self.pool.get('account.move.line') + query = line_obj._query_get(cr, uid, context={}) + where = ' and '.join(map(lambda x: '''(SELECT + CASE WHEN l.amount_currency < 0 + THEN - l.amount_currency + ELSE l.credit + END - coalesce(sum(pl.amount_currency), 0) + FROM payment_line pl + INNER JOIN payment_order po ON (pl.order_id = po.id) + WHERE move_line_id = l.id + AND po.state != 'cancel' + ) %(operator)s %%s ''' % {'operator': x[1]}, args)) + sql_args = tuple(map(itemgetter(2), args)) + cr.execute( + '''SELECT id + FROM account_move_line l + WHERE account_id IN (select id + FROM account_account + WHERE type in %s AND active) + AND reconcile_id IS null + AND credit > 0 + AND ''' + where + ' and ' + query, + (('payable', 'receivable'),) + sql_args) + # The patch we have compared to the original function in + # addons/account_payment is just above : + # original code : type = 'payable' + # fixed code : type in ('payable', 'receivable') + res = cr.fetchall() + if not res: + return [('id', '=', '0')] + return [('id', 'in', map(lambda x:x[0], res))] + + _columns = { + 'amount_to_pay': fields.function( + _amount_to_pay, type='float', string='Amount to pay', + fnct_search=_to_pay_search), + } diff --git a/account_banking_payment_export/models/account_payment.py b/account_banking_payment_export/models/account_payment.py new file mode 100644 index 000000000..069d9b427 --- /dev/null +++ b/account_banking_payment_export/models/account_payment.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2009 EduSense BV (). +# (C) 2011 - 2013 Therp BV (). +# +# All other contributions are (C) by their respective contributors +# +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, exceptions, _ +from openerp import netsvc + + +class PaymentOrder(models.Model): + _inherit = 'payment.order' + + payment_order_type = fields.Selection( + [('payment', 'Payment'), ('debit', 'Direct debit')], + 'Payment order type', required=True, default='payment', + readonly=True, states={'draft': [('readonly', False)]}) + mode_type = fields.Many2one('payment.mode.type', related='mode.type', + string='Payment Type') + + @api.multi + def launch_wizard(self): + """Search for a wizard to launch according to the type. + If type is manual. just confirm the order. + Previously (pre-v6) in account_payment/wizard/wizard_pay.py + """ + context = self.env.context.copy() + order = self[0] + # check if a wizard is defined for the first order + if order.mode.type and order.mode.type.ir_model_id: + context['active_ids'] = self.ids + wizard_model = order.mode.type.ir_model_id.model + wizard_obj = self.env[wizard_model] + return { + 'name': wizard_obj._description or _('Payment Order Export'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': wizard_model, + 'domain': [], + 'context': context, + 'type': 'ir.actions.act_window', + 'target': 'new', + 'nodestroy': True, + } + else: + # should all be manual orders without type or wizard model + for order in self[1:]: + if order.mode.type and order.mode.type.ir_model_id: + raise exceptions.Warning( + _('Error'), + _('You can only combine payment orders of the same ' + 'type')) + # process manual payments + wf_service = netsvc.LocalService('workflow') + for order_id in self.ids: + wf_service.trg_validate(self.env.uid, 'payment.order', + order_id, 'done', self.env.cr) + return {} diff --git a/account_banking_payment_export/models/payment_mode.py b/account_banking_payment_export/models/payment_mode.py new file mode 100644 index 000000000..b35a150ba --- /dev/null +++ b/account_banking_payment_export/models/payment_mode.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2009 EduSense BV (). +# (C) 2011 - 2013 Therp BV (). +# +# All other contributions are (C) by their respective contributors +# +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields + + +class PaymentMode(models.Model): + """Restoring the payment type from version 5, + used to select the export wizard (if any) + """ + _inherit = "payment.mode" + + def suitable_bank_types(self, cr, uid, payment_mode_id=None, context=None): + """ Reinstates functional code for suitable bank type filtering. + Current code in account_payment is disfunctional. + """ + res = [] + payment_mode = self.browse(cr, uid, payment_mode_id, context=context) + if (payment_mode and payment_mode.type and + payment_mode.type.suitable_bank_types): + res = [t.code for t in payment_mode.type.suitable_bank_types] + return res + + type = fields.Many2one( + 'payment.mode.type', string='Export type', required=True, + help='Select the Export Payment Type for the Payment Mode.') + payment_order_type = fields.Selection( + related='type.payment_order_type', readonly=True, string="Order Type", + selection=[('payment', 'Payment'), ('debit', 'Debit')], + help="This field, that comes from export type, determines if this " + "mode can be selected for customers or suppliers.") + active = fields.Boolean(string='Active', default=True) diff --git a/account_banking_payment_export/models/payment_mode_type.py b/account_banking_payment_export/models/payment_mode_type.py new file mode 100644 index 000000000..4093da765 --- /dev/null +++ b/account_banking_payment_export/models/payment_mode_type.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2009 EduSense BV (). +# (C) 2011 - 2013 Therp BV (). +# +# All other contributions are (C) by their respective contributors +# +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields + + +class PaymentModeType(models.Model): + _name = 'payment.mode.type' + _description = 'Payment Mode Type' + + name = fields.Char('Name', size=64, required=True, help='Payment Type') + code = fields.Char('Code', size=64, required=True, + help='Specify the Code for Payment Type') + suitable_bank_types = fields.Many2many( + comodel_name='res.partner.bank.type', + relation='bank_type_payment_type_rel', column1='pay_type_id', + column2='bank_type_id', string='Suitable bank types', required=True) + ir_model_id = fields.Many2one( + 'ir.model', string='Payment wizard', + help='Select the Payment Wizard for payments of this type. Leave ' + 'empty for manual processing', + domain=[('osv_memory', '=', True)]) + payment_order_type = fields.Selection( + [('payment', 'Payment'), ('debit', 'Debit')], + string='Order type', required=True, default='payment', + help="This field determines if this type applies to customers " + "(Debit) or suppliers (Payment)") + active = fields.Boolean(string='Active', default=True) + + def _auto_init(self, cr, context=None): + res = super(PaymentModeType, self)._auto_init(cr, context=context) + # migrate xmlid from manual_bank_transfer to avoid dependency on + # account_banking + cr.execute( + """UPDATE ir_model_data + SET module='account_banking_payment_export' + WHERE module='account_banking' AND + name='manual_bank_tranfer' AND + model='payment.mode.type'""") + return res diff --git a/__unported__/account_banking_payment_export/security/ir.model.access.csv b/account_banking_payment_export/security/ir.model.access.csv similarity index 100% rename from __unported__/account_banking_payment_export/security/ir.model.access.csv rename to account_banking_payment_export/security/ir.model.access.csv diff --git a/__unported__/account_banking_payment_export/view/account_payment.xml b/account_banking_payment_export/view/account_payment.xml similarity index 100% rename from __unported__/account_banking_payment_export/view/account_payment.xml rename to account_banking_payment_export/view/account_payment.xml diff --git a/__unported__/account_banking_payment_export/view/bank_payment_manual.xml b/account_banking_payment_export/view/bank_payment_manual.xml similarity index 100% rename from __unported__/account_banking_payment_export/view/bank_payment_manual.xml rename to account_banking_payment_export/view/bank_payment_manual.xml diff --git a/__unported__/account_banking_payment_export/view/payment_mode.xml b/account_banking_payment_export/view/payment_mode.xml similarity index 97% rename from __unported__/account_banking_payment_export/view/payment_mode.xml rename to account_banking_payment_export/view/payment_mode.xml index 611b233e8..42b19ca2d 100644 --- a/__unported__/account_banking_payment_export/view/payment_mode.xml +++ b/account_banking_payment_export/view/payment_mode.xml @@ -2,7 +2,7 @@ - diff --git a/__unported__/account_banking_payment_export/view/payment_mode_type.xml b/account_banking_payment_export/view/payment_mode_type.xml similarity index 77% rename from __unported__/account_banking_payment_export/view/payment_mode_type.xml rename to account_banking_payment_export/view/payment_mode_type.xml index a3bd21c25..4ca3acac7 100644 --- a/__unported__/account_banking_payment_export/view/payment_mode_type.xml +++ b/account_banking_payment_export/view/payment_mode_type.xml @@ -20,11 +20,18 @@
- - - - - + + + + + + + + + + +
@@ -44,7 +51,7 @@
- Payment Type + Payment Export Types payment.mode.type form tree,form diff --git a/__unported__/account_banking_payment_export/view/payment_order_create_view.xml b/account_banking_payment_export/view/payment_order_create_view.xml similarity index 100% rename from __unported__/account_banking_payment_export/view/payment_order_create_view.xml rename to account_banking_payment_export/view/payment_order_create_view.xml diff --git a/account_banking_payment_export/wizard/__init__.py b/account_banking_payment_export/wizard/__init__.py new file mode 100644 index 000000000..f30ac09dd --- /dev/null +++ b/account_banking_payment_export/wizard/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import payment_order_create +from . import bank_payment_manual diff --git a/account_banking_payment_export/wizard/bank_payment_manual.py b/account_banking_payment_export/wizard/bank_payment_manual.py new file mode 100644 index 000000000..dd7beee10 --- /dev/null +++ b/account_banking_payment_export/wizard/bank_payment_manual.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2009 EduSense BV (). +# (C) 2011 - 2013 Therp BV (). +# +# All other contributions are (C) by their respective contributors +# +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +"""This module contains a single "wizard" for confirming manual +bank transfers. +""" + +from openerp import models, fields, api +from openerp import netsvc + + +class PaymentManual(models.TransientModel): + _name = 'payment.manual' + _description = 'Send payment order(s) manually' + + payment_order_ids = fields.Many2many( + comodel_name='payment.order', relation='wiz_manual_payorders_rel', + column1='wizard_id', column2='payment_order_id', + string='Payment orders', readonly=True), + + def create(self, vals): + payment_order_ids = self.env.context.get('active_ids', []) + vals['payment_order_ids'] = [[6, 0, payment_order_ids]] + return super(PaymentManual, self).create(vals) + + @api.one + def button_ok(self): + wf_service = netsvc.LocalService('workflow') + for order_id in self.payment_order_ids: + wf_service.trg_validate(self.env.uid, 'payment.order', order_id.id, + 'done', self.env.cr) + return {'type': 'ir.actions.act_window_close'} diff --git a/account_banking_payment_export/wizard/bank_payment_manual.xml b/account_banking_payment_export/wizard/bank_payment_manual.xml new file mode 100644 index 000000000..e350c9b6f --- /dev/null +++ b/account_banking_payment_export/wizard/bank_payment_manual.xml @@ -0,0 +1,18 @@ + + + + + Form for manual payment wizard + payment.manual + +
+
+
+
+
diff --git a/account_banking_payment_export/wizard/payment_order_create.py b/account_banking_payment_export/wizard/payment_order_create.py new file mode 100644 index 000000000..0a34c021f --- /dev/null +++ b/account_banking_payment_export/wizard/payment_order_create.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2009 EduSense BV (). +# (C) 2011 - 2013 Therp BV (). +# +# All other contributions are (C) by their respective contributors +# +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, _ + + +class PaymentOrderCreate(models.TransientModel): + _inherit = 'payment.order.create' + + populate_results = fields.Boolean(string="Populate results directly", + default=True) + + @api.model + def default_get(self, fields): + res = super(PaymentOrderCreate, self).default_get(fields) + context = self.env.context + if ('entries' in fields and context.get('line_ids') and + context.get('populate_results')): + res.update({'entries': context['line_ids']}) + return res + + @api.model + def extend_payment_order_domain(self, payment_order, domain): + if payment_order.payment_order_type == 'payment': + domain += [('account_id.type', 'in', ('payable', 'receivable')), + ('amount_to_pay', '>', 0)] + return True + + @api.multi + def search_entries(self): + """This method taken from account_payment module. + We adapt the domain based on the payment_order_type + """ + line_obj = self.env['account.move.line'] + model_data_obj = self.env['ir.model.data'] + # -- start account_banking_payment -- + payment = self.env['payment.order'].browse( + self.env.context['active_id']) + # Search for move line to pay: + domain = [('move_id.state', '=', 'posted'), + ('reconcile_id', '=', False), + ('company_id', '=', payment.mode.company_id.id)] + self.extend_payment_order_domain(payment, domain) + # -- end account_direct_debit -- + domain += ['|', + ('date_maturity', '<=', self.duedate), + ('date_maturity', '=', False)] + lines = line_obj.search(domain) + context = self.env.context.copy() + context['line_ids'] = lines.ids + context['populate_results'] = self.populate_results + model_datas = model_data_obj.search( + [('model', '=', 'ir.ui.view'), + ('name', '=', 'view_create_payment_order_lines')]) + return {'name': _('Entry Lines'), + 'context': context, + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'payment.order.create', + 'views': [(model_datas[0].res_id, 'form')], + 'type': 'ir.actions.act_window', + 'target': 'new', + } + + @api.model + def _prepare_payment_line(self, payment, line): + """This function is designed to be inherited + The resulting dict is passed to the create method of payment.line""" + _today = fields.Date.context_today(self) + date_to_pay = False # no payment date => immediate payment + if payment.date_prefered == 'due': + # -- account_banking + # date_to_pay = line.date_maturity + date_to_pay = ( + line.date_maturity + if line.date_maturity and line.date_maturity > _today + else False) + # -- end account banking + elif payment.date_prefered == 'fixed': + # -- account_banking + # date_to_pay = payment.date_scheduled + date_to_pay = ( + payment.date_scheduled + if payment.date_scheduled and payment.date_scheduled > _today + else False) + # -- end account banking + # -- account_banking + state = 'normal' + communication = line.ref or '-' + if line.invoice: + if line.invoice.type in ('in_invoice', 'in_refund'): + if line.invoice.reference_type == 'structured': + state = 'structured' + communication = line.invoice.reference + else: + if line.invoice.reference: + communication = line.invoice.reference + elif line.invoice.supplier_invoice_number: + communication = line.invoice.supplier_invoice_number + else: + # Make sure that the communication includes the + # customer invoice number (in the case of debit order) + communication = line.invoice.number.replace('/', '') + state = 'structured' + # support debit orders when enabled + if (payment.payment_order_type == 'debit' and + 'amount_to_receive' in line): + amount_currency = line.amount_to_receive + else: + amount_currency = line.amount_to_pay + line2bank = line.line2bank(payment.mode.id) + # -- end account banking + res = {'move_line_id': line.id, + 'amount_currency': amount_currency, + 'bank_id': line2bank.get(line.id), + 'order_id': payment.id, + 'partner_id': line.partner_id and line.partner_id.id or False, + # account banking + 'communication': communication, + 'state': state, + # end account banking + 'date': date_to_pay, + 'currency': (line.invoice and line.invoice.currency_id.id + or line.journal_id.currency.id + or line.journal_id.company_id.currency_id.id)} + return res + + @api.multi + def create_payment(self): + """This method is a slightly modified version of the existing method on + this model in account_payment. + - pass the payment mode to line2bank() + - allow invoices to create influence on the payment process: not only + 'Free' references are allowed, but others as well + - check date_to_pay is not in the past. + """ + if not self.entries: + return {'type': 'ir.actions.act_window_close'} + context = self.env.context + payment_line_obj = self.env['payment.line'] + payment = self.env['payment.order'].browse(context['active_id']) + # Populate the current payment with new lines: + for line in self.entries: + vals = self._prepare_payment_line(payment, line) + payment_line_obj.create(vals) + # Force reload of payment order view as a workaround for lp:1155525 + return {'name': _('Payment Orders'), + 'context': context, + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': 'payment.order', + 'res_id': context['active_id'], + 'type': 'ir.actions.act_window'} diff --git a/account_banking_payment_export/wizard/payment_order_create_view.xml b/account_banking_payment_export/wizard/payment_order_create_view.xml new file mode 100644 index 000000000..d70135343 --- /dev/null +++ b/account_banking_payment_export/wizard/payment_order_create_view.xml @@ -0,0 +1,34 @@ + + + + + + + payment.order.create.form.export + payment.order.create + + + + + + + + + + add.context.to.display.maturity.date + payment.order.create + + + + {'journal_type': 'sale'} + 1 + + + + + + diff --git a/account_banking_sepa_credit_transfer/__init__.py b/account_banking_sepa_credit_transfer/__init__.py new file mode 100644 index 000000000..c30bd487e --- /dev/null +++ b/account_banking_sepa_credit_transfer/__init__.py @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Credit Transfer module for OpenERP +# Copyright (C) 2010-2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import wizard +from . import models diff --git a/__unported__/account_banking_sepa_credit_transfer/__openerp__.py b/account_banking_sepa_credit_transfer/__openerp__.py similarity index 71% rename from __unported__/account_banking_sepa_credit_transfer/__openerp__.py rename to account_banking_sepa_credit_transfer/__openerp__.py index 230e10e2d..89b56c189 100644 --- a/__unported__/account_banking_sepa_credit_transfer/__openerp__.py +++ b/account_banking_sepa_credit_transfer/__openerp__.py @@ -26,39 +26,34 @@ 'license': 'AGPL-3', 'author': 'Akretion', 'website': 'http://www.akretion.com', + 'contributors': ['Pedro M. Baeza '], 'category': 'Banking addons', 'depends': ['account_banking_pain_base'], 'external_dependencies': { 'python': ['unidecode', 'lxml'], - }, + }, 'data': [ - 'account_banking_sepa_view.xml', + 'views/account_banking_sepa_view.xml', 'wizard/export_sepa_view.xml', 'data/payment_type_sepa_sct.xml', 'security/ir.model.access.csv', ], - 'demo': ['sepa_credit_transfer_demo.xml'], + 'demo': [ + 'demo/sepa_credit_transfer_demo.xml' + ], 'description': ''' Module to export payment orders in SEPA XML file format. SEPA PAIN (PAyment INitiation) is the new european standard for -Customer-to-Bank payment instructions. - -This module implements SEPA Credit Transfer (SCT), more specifically PAIN -versions 001.001.02, 001.001.03, 001.001.04 and 001.001.05. -It is part of the ISO 20022 standard, available on http://www.iso20022.org. +Customer-to-Bank payment instructions. This module implements SEPA Credit +Transfer (SCT), more specifically PAIN versions 001.001.02, 001.001.03, +001.001.04 and 001.001.05. It is part of the ISO 20022 standard, available on +http://www.iso20022.org. The Implementation Guidelines for SEPA Credit Transfer published by the -European Payments Council (http://http://www.europeanpaymentscouncil.eu) -use PAIN version 001.001.03, so it's probably the version of PAIN that you -should try first. - -This module uses the framework provided by the banking addons, -cf https://www.github.com/OCA/banking-addons - -Please contact Alexis de Lattre from Akretion -for any help or question about this module. +European Payments Council (http://http://www.europeanpaymentscouncil.eu) use +PAIN version 001.001.03, so it's probably the version of PAIN that you should +try first. ''', - 'active': False, - 'installable': False, + 'installable': True, } diff --git a/__unported__/account_banking_sepa_credit_transfer/account_banking_sepa.py b/account_banking_sepa_credit_transfer/account_banking_sepa.py similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/account_banking_sepa.py rename to account_banking_sepa_credit_transfer/account_banking_sepa.py diff --git a/__unported__/account_banking_sepa_credit_transfer/account_banking_sepa_view.xml b/account_banking_sepa_credit_transfer/account_banking_sepa_view.xml similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/account_banking_sepa_view.xml rename to account_banking_sepa_credit_transfer/account_banking_sepa_view.xml diff --git a/__unported__/account_banking_sepa_credit_transfer/data/pain.001.001.02.xsd b/account_banking_sepa_credit_transfer/data/pain.001.001.02.xsd similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/data/pain.001.001.02.xsd rename to account_banking_sepa_credit_transfer/data/pain.001.001.02.xsd diff --git a/__unported__/account_banking_sepa_credit_transfer/data/pain.001.001.03.xsd b/account_banking_sepa_credit_transfer/data/pain.001.001.03.xsd similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/data/pain.001.001.03.xsd rename to account_banking_sepa_credit_transfer/data/pain.001.001.03.xsd diff --git a/__unported__/account_banking_sepa_credit_transfer/data/pain.001.001.04.xsd b/account_banking_sepa_credit_transfer/data/pain.001.001.04.xsd similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/data/pain.001.001.04.xsd rename to account_banking_sepa_credit_transfer/data/pain.001.001.04.xsd diff --git a/__unported__/account_banking_sepa_credit_transfer/data/pain.001.001.05.xsd b/account_banking_sepa_credit_transfer/data/pain.001.001.05.xsd similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/data/pain.001.001.05.xsd rename to account_banking_sepa_credit_transfer/data/pain.001.001.05.xsd diff --git a/__unported__/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml b/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml similarity index 88% rename from __unported__/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml rename to account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml index f07ece146..31d851edb 100644 --- a/__unported__/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml +++ b/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml @@ -7,6 +7,7 @@ SEPA Credit Transfer v05 pain.001.001.05 + payment @@ -15,6 +16,7 @@ SEPA Credit Transfer v04 pain.001.001.04 + payment @@ -23,6 +25,7 @@ SEPA Credit Transfer v03 (recommended) pain.001.001.03 + payment @@ -31,6 +34,7 @@ SEPA Credit Transfer v02 pain.001.001.02 + payment diff --git a/__unported__/account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml b/account_banking_sepa_credit_transfer/demo/sepa_credit_transfer_demo.xml similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml rename to account_banking_sepa_credit_transfer/demo/sepa_credit_transfer_demo.xml diff --git a/__unported__/account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot b/account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot rename to account_banking_sepa_credit_transfer/i18n/account_banking_sepa_credit_transfer.pot diff --git a/__unported__/account_banking_sepa_credit_transfer/i18n/fr.po b/account_banking_sepa_credit_transfer/i18n/fr.po similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/i18n/fr.po rename to account_banking_sepa_credit_transfer/i18n/fr.po diff --git a/__unported__/account_banking_sepa_credit_transfer/i18n/nl.po b/account_banking_sepa_credit_transfer/i18n/nl.po similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/i18n/nl.po rename to account_banking_sepa_credit_transfer/i18n/nl.po diff --git a/__unported__/account_banking_sepa_credit_transfer/__init__.py b/account_banking_sepa_credit_transfer/models/__init__.py similarity index 98% rename from __unported__/account_banking_sepa_credit_transfer/__init__.py rename to account_banking_sepa_credit_transfer/models/__init__.py index 207f87a21..90e481210 100644 --- a/__unported__/account_banking_sepa_credit_transfer/__init__.py +++ b/account_banking_sepa_credit_transfer/models/__init__.py @@ -20,5 +20,4 @@ # ############################################################################## -from . import wizard from . import account_banking_sepa diff --git a/account_banking_sepa_credit_transfer/models/account_banking_sepa.py b/account_banking_sepa_credit_transfer/models/account_banking_sepa.py new file mode 100644 index 000000000..69b7d20ae --- /dev/null +++ b/account_banking_sepa_credit_transfer/models/account_banking_sepa.py @@ -0,0 +1,76 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Credit Transfer module for OpenERP +# Copyright (C) 2010-2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api +from openerp.addons.decimal_precision import decimal_precision as dp +from unidecode import unidecode + + +class BankingExportSepa(models.Model): + """SEPA export""" + _name = 'banking.export.sepa' + _description = __doc__ + _rec_name = 'filename' + + @api.one + def _generate_filename(self): + ref = self.payment_order_ids[0].reference + if ref: + label = unidecode(ref.replace('/', '-')) + else: + label = 'error' + self.filename = 'sct_%s.xml' % label + + payment_order_ids = fields.Many2many( + comodel_name='payment.order', column1='banking_export_sepa_id', + column2='account_order_id', relation='account_payment_order_sepa_rel', + string='Payment Orders', readonly=True) + nb_transactions = fields.Integer(string='Number of Transactions', + readonly=True) + total_amount = fields.Float(string='Total Amount', + digits_compute=dp.get_precision('Account'), + readonly=True) + batch_booking = fields.Boolean( + 'Batch Booking', readonly=True, + help="If true, the bank statement will display only one debit line " + "for all the wire transfers of the SEPA XML file ; if false, " + "the bank statement will display one debit line per wire " + "transfer of the SEPA XML file.") + charge_bearer = fields.Selection( + [('SLEV', 'Following Service Level'), + ('SHAR', 'Shared'), + ('CRED', 'Borne by Creditor'), + ('DEBT', 'Borne by Debtor')], string='Charge Bearer', readonly=True, + help="Following service level : transaction charges are to be applied " + "following the rules agreed in the service level and/or scheme " + "(SEPA Core messages must use this). Shared : transaction " + "charges on the creditor side are to be borne by the creditor, " + "transaction charges on the debtor side are to be borne by the " + "debtor. Borne by creditor : all transaction charges are to be " + "borne by the creditor. Borne by debtor : all transaction " + "charges are to be borne by the debtor.") + create_date = fields.Datetime('Generation Date', readonly=True) + file = fields.Binary('SEPA XML File', readonly=True) + filename = fields.Char(string='Filename', size=256, readonly=True, + compute=_generate_filename) + state = fields.Selection([('draft', 'Draft'), ('sent', 'Sent')], + string='State', readonly=True, default='draft') diff --git a/__unported__/account_banking_sepa_credit_transfer/security/ir.model.access.csv b/account_banking_sepa_credit_transfer/security/ir.model.access.csv similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/security/ir.model.access.csv rename to account_banking_sepa_credit_transfer/security/ir.model.access.csv diff --git a/account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml b/account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml new file mode 100644 index 000000000..77abf1b34 --- /dev/null +++ b/account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml @@ -0,0 +1,15 @@ + + + + + + + SEPA Credit Transfer La Banque Postale + + + + + + + + diff --git a/account_banking_sepa_credit_transfer/static/description/icon.svg b/account_banking_sepa_credit_transfer/static/description/icon.svg new file mode 100644 index 000000000..266ef8442 --- /dev/null +++ b/account_banking_sepa_credit_transfer/static/description/icon.svg @@ -0,0 +1,92 @@ + + + +image/svg+xmlCREDITTRANSFER + \ No newline at end of file diff --git a/__unported__/account_banking_sepa_credit_transfer/static/src/img/icon.png b/account_banking_sepa_credit_transfer/static/src/img/icon.png similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/static/src/img/icon.png rename to account_banking_sepa_credit_transfer/static/src/img/icon.png diff --git a/account_banking_sepa_credit_transfer/views/account_banking_sepa_view.xml b/account_banking_sepa_credit_transfer/views/account_banking_sepa_view.xml new file mode 100644 index 000000000..a5896c757 --- /dev/null +++ b/account_banking_sepa_credit_transfer/views/account_banking_sepa_view.xml @@ -0,0 +1,77 @@ + + + + + + + account.banking.export.sepa.form + banking.export.sepa + +
+
+ +
+ + + + + + + + + + + + + + + + +
+
+
+ + + + account.banking.export.sepa.tree + banking.export.sepa + + + + + + + + + + + + + SEPA Credit Transfer Files + banking.export.sepa + form + tree,form + + + + + + + +
+
diff --git a/__unported__/account_banking_sepa_credit_transfer/wizard/__init__.py b/account_banking_sepa_credit_transfer/wizard/__init__.py similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/wizard/__init__.py rename to account_banking_sepa_credit_transfer/wizard/__init__.py diff --git a/__unported__/account_banking_sepa_credit_transfer/wizard/export_sepa.py b/account_banking_sepa_credit_transfer/wizard/export_sepa.py similarity index 95% rename from __unported__/account_banking_sepa_credit_transfer/wizard/export_sepa.py rename to account_banking_sepa_credit_transfer/wizard/export_sepa.py index eb2461ad8..7b2c94ef9 100644 --- a/__unported__/account_banking_sepa_credit_transfer/wizard/export_sepa.py +++ b/account_banking_sepa_credit_transfer/wizard/export_sepa.py @@ -89,9 +89,7 @@ class banking_export_sepa_wizard(orm.TransientModel): cr, uid, vals, context=context) def create_sepa(self, cr, uid, ids, context=None): - ''' - Creates the SEPA Credit Transfer file. That's the important code ! - ''' + """Creates the SEPA Credit Transfer file. That's the important code!""" if context is None: context = {} sepa_export = self.browse(cr, uid, ids[0], context=context) @@ -122,16 +120,14 @@ class banking_export_sepa_wizard(orm.TransientModel): bic_xml_tag = 'BICFI' name_maxsize = 140 root_xml_tag = 'CstmrCdtTrfInitn' - else: raise orm.except_orm( _('Error:'), _("Payment Type Code '%s' is not supported. The only " - "Payment Type Codes supported for SEPA Credit Transfers " - "are 'pain.001.001.02', 'pain.001.001.03', " - "'pain.001.001.04' and 'pain.001.001.05'.") - % pain_flavor) - + "Payment Type Codes supported for SEPA Credit Transfers " + "are 'pain.001.001.02', 'pain.001.001.03', " + "'pain.001.001.04' and 'pain.001.001.05'.") % + pain_flavor) gen_args = { 'bic_xml_tag': bic_xml_tag, 'name_maxsize': name_maxsize, @@ -144,22 +140,18 @@ class banking_export_sepa_wizard(orm.TransientModel): 'account_banking_sepa_credit_transfer/data/%s.xsd' % pain_flavor, } - pain_ns = { 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', None: 'urn:iso:std:iso:20022:tech:xsd:%s' % pain_flavor, } - xml_root = etree.Element('Document', nsmap=pain_ns) pain_root = etree.SubElement(xml_root, root_xml_tag) pain_03_to_05 = \ ['pain.001.001.03', 'pain.001.001.04', 'pain.001.001.05'] - # A. Group header group_header_1_0, nb_of_transactions_1_6, control_sum_1_7 = \ self.generate_group_header_block( cr, uid, pain_root, gen_args, context=context) - transactions_count_1_6 = 0 total_amount = 0.0 amount_control_sum_1_7 = 0.0 @@ -187,7 +179,6 @@ class banking_export_sepa_wizard(orm.TransientModel): self.pool['payment.line'].write( cr, uid, line.id, {'date': requested_date}, context=context) - for (requested_date, priority), lines in lines_per_group.items(): # B. Payment info payment_info_2_0, nb_of_transactions_2_4, control_sum_2_5 = \ @@ -200,7 +191,6 @@ class banking_export_sepa_wizard(orm.TransientModel): 'priority': priority, 'requested_date': requested_date, }, gen_args, context=context) - self.generate_party_block( cr, uid, payment_info_2_0, 'Dbtr', 'B', 'sepa_export.payment_order_ids[0].mode.bank_id.partner_id.' @@ -209,10 +199,8 @@ class banking_export_sepa_wizard(orm.TransientModel): 'sepa_export.payment_order_ids[0].mode.bank_id.bank.bic', {'sepa_export': sepa_export}, gen_args, context=context) - charge_bearer_2_24 = etree.SubElement(payment_info_2_0, 'ChrgBr') charge_bearer_2_24.text = sepa_export.charge_bearer - transactions_count_2_4 = 0 amount_control_sum_2_5 = 0.0 for line in lines: @@ -240,7 +228,6 @@ class banking_export_sepa_wizard(orm.TransientModel): instructed_amount_2_43.text = '%.2f' % line.amount_currency amount_control_sum_1_7 += line.amount_currency amount_control_sum_2_5 += line.amount_currency - if not line.bank_id: raise orm.except_orm( _('Error:'), @@ -252,45 +239,38 @@ class banking_export_sepa_wizard(orm.TransientModel): 'C', 'line.partner_id.name', 'line.bank_id.acc_number', 'line.bank_id.bank.bic', {'line': line}, gen_args, context=context) - self.generate_remittance_info_block( cr, uid, credit_transfer_transaction_info_2_27, line, gen_args, context=context) - if pain_flavor in pain_03_to_05: nb_of_transactions_2_4.text = str(transactions_count_2_4) control_sum_2_5.text = '%.2f' % amount_control_sum_2_5 - if pain_flavor in pain_03_to_05: nb_of_transactions_1_6.text = str(transactions_count_1_6) control_sum_1_7.text = '%.2f' % amount_control_sum_1_7 else: nb_of_transactions_1_6.text = str(transactions_count_1_6) control_sum_1_7.text = '%.2f' % amount_control_sum_1_7 - return self.finalize_sepa_file_creation( cr, uid, ids, xml_root, total_amount, transactions_count_1_6, gen_args, context=context) def cancel_sepa(self, cr, uid, ids, context=None): - ''' - Cancel the SEPA file: just drop the file - ''' + """Cancel the SEPA file: just drop the file""" sepa_export = self.browse(cr, uid, ids[0], context=context) - self.pool.get('banking.export.sepa').unlink( + self.pool['banking.export.sepa'].unlink( cr, uid, sepa_export.file_id.id, context=context) return {'type': 'ir.actions.act_window_close'} def save_sepa(self, cr, uid, ids, context=None): - ''' - Save the SEPA file: send the done signal to all payment + """Save the SEPA file: send the done signal to all payment orders in the file. With the default workflow, they will transition to 'done', while with the advanced workflow in account_banking_payment they will transition to 'sent' waiting reconciliation. - ''' + """ sepa_export = self.browse(cr, uid, ids[0], context=context) - self.pool.get('banking.export.sepa').write( + self.pool['banking.export.sepa'].write( cr, uid, sepa_export.file_id.id, {'state': 'sent'}, context=context) wf_service = netsvc.LocalService('workflow') diff --git a/__unported__/account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml b/account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml similarity index 100% rename from __unported__/account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml rename to account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml diff --git a/__unported__/account_banking_sepa_direct_debit/__init__.py b/account_banking_sepa_direct_debit/__init__.py similarity index 94% rename from __unported__/account_banking_sepa_direct_debit/__init__.py rename to account_banking_sepa_direct_debit/__init__.py index f852fb7bd..096fe8ad3 100644 --- a/__unported__/account_banking_sepa_direct_debit/__init__.py +++ b/account_banking_sepa_direct_debit/__init__.py @@ -20,6 +20,5 @@ # ############################################################################## -from . import company +from . import models from . import wizard -from . import account_banking_sdd diff --git a/__unported__/account_banking_sepa_direct_debit/__openerp__.py b/account_banking_sepa_direct_debit/__openerp__.py similarity index 70% rename from __unported__/account_banking_sepa_direct_debit/__openerp__.py rename to account_banking_sepa_direct_debit/__openerp__.py index 2e109be26..5f222df80 100644 --- a/__unported__/account_banking_sepa_direct_debit/__openerp__.py +++ b/account_banking_sepa_direct_debit/__openerp__.py @@ -26,47 +26,40 @@ 'license': 'AGPL-3', 'author': 'Akretion', 'website': 'http://www.akretion.com', + 'contributors': ['Pedro M. Baeza '], 'category': 'Banking addons', 'depends': ['account_direct_debit', 'account_banking_pain_base'], 'external_dependencies': { 'python': ['unidecode', 'lxml'], }, 'data': [ - 'security/original_mandate_required_security.xml', - 'account_banking_sdd_view.xml', - 'sdd_mandate_view.xml', - 'res_partner_bank_view.xml', - 'account_payment_view.xml', - 'company_view.xml', - 'mandate_expire_cron.xml', - 'account_invoice_view.xml', + 'views/account_banking_sdd_view.xml', + 'views/sdd_mandate_view.xml', + 'views/res_partner_bank_view.xml', + 'views/account_payment_view.xml', + 'views/res_company_view.xml', + 'views/account_invoice_view.xml', 'wizard/export_sdd_view.xml', + 'data/mandate_expire_cron.xml', 'data/payment_type_sdd.xml', 'data/mandate_reference_sequence.xml', + 'security/original_mandate_required_security.xml', 'security/ir.model.access.csv', ], - 'demo': ['sepa_direct_debit_demo.xml'], + 'demo': ['demo/sepa_direct_debit_demo.xml'], 'description': ''' Module to export direct debit payment orders in SEPA XML file format. SEPA PAIN (PAyment INitiation) is the new european standard for -Customer-to-Bank payment instructions. - -This module implements SEPA Direct Debit (SDD), more specifically PAIN -versions 008.001.02, 008.001.03 and 008.001.04. -It is part of the ISO 20022 standard, available on http://www.iso20022.org. +Customer-to-Bank payment instructions. This module implements SEPA Direct +Debit (SDD), more specifically PAIN versions 008.001.02, 008.001.03 and +008.001.04. It is part of the ISO 20022 standard, available on +http://www.iso20022.org. The Implementation Guidelines for SEPA Direct Debit published by the European Payments Council (http://http://www.europeanpaymentscouncil.eu) use PAIN -version 008.001.02. So if you don't know which version your bank supports, -you should try version 008.001.02 first. - -This module uses the framework provided by the banking addons, -cf https://www.github.com/OCA/banking-addons - -Please contact Alexis de Lattre from Akretion -for any help or question about this module. +version 008.001.02. So if you don't know which version your bank supports, you +should try version 008.001.02 first. ''', - 'active': False, - 'installable': False, + 'installable': True, } diff --git a/__unported__/account_banking_sepa_direct_debit/account_banking_sdd.py b/account_banking_sepa_direct_debit/account_banking_sdd.py similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/account_banking_sdd.py rename to account_banking_sepa_direct_debit/account_banking_sdd.py diff --git a/__unported__/account_banking_sepa_direct_debit/account_banking_sdd_view.xml b/account_banking_sepa_direct_debit/account_banking_sdd_view.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/account_banking_sdd_view.xml rename to account_banking_sepa_direct_debit/account_banking_sdd_view.xml diff --git a/__unported__/account_banking_sepa_direct_debit/account_invoice_view.xml b/account_banking_sepa_direct_debit/account_invoice_view.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/account_invoice_view.xml rename to account_banking_sepa_direct_debit/account_invoice_view.xml diff --git a/__unported__/account_banking_sepa_direct_debit/account_payment_view.xml b/account_banking_sepa_direct_debit/account_payment_view.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/account_payment_view.xml rename to account_banking_sepa_direct_debit/account_payment_view.xml diff --git a/__unported__/account_banking_sepa_direct_debit/company.py b/account_banking_sepa_direct_debit/company.py similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/company.py rename to account_banking_sepa_direct_debit/company.py diff --git a/__unported__/account_banking_sepa_direct_debit/company_view.xml b/account_banking_sepa_direct_debit/company_view.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/company_view.xml rename to account_banking_sepa_direct_debit/company_view.xml diff --git a/__unported__/account_banking_sepa_direct_debit/mandate_expire_cron.xml b/account_banking_sepa_direct_debit/data/mandate_expire_cron.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/mandate_expire_cron.xml rename to account_banking_sepa_direct_debit/data/mandate_expire_cron.xml diff --git a/__unported__/account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml b/account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml rename to account_banking_sepa_direct_debit/data/mandate_reference_sequence.xml diff --git a/__unported__/account_banking_sepa_direct_debit/data/pain.008.001.02.xsd b/account_banking_sepa_direct_debit/data/pain.008.001.02.xsd similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/data/pain.008.001.02.xsd rename to account_banking_sepa_direct_debit/data/pain.008.001.02.xsd diff --git a/__unported__/account_banking_sepa_direct_debit/data/pain.008.001.03.xsd b/account_banking_sepa_direct_debit/data/pain.008.001.03.xsd similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/data/pain.008.001.03.xsd rename to account_banking_sepa_direct_debit/data/pain.008.001.03.xsd diff --git a/__unported__/account_banking_sepa_direct_debit/data/pain.008.001.04.xsd b/account_banking_sepa_direct_debit/data/pain.008.001.04.xsd similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/data/pain.008.001.04.xsd rename to account_banking_sepa_direct_debit/data/pain.008.001.04.xsd diff --git a/__unported__/account_banking_sepa_direct_debit/data/payment_type_sdd.xml b/account_banking_sepa_direct_debit/data/payment_type_sdd.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/data/payment_type_sdd.xml rename to account_banking_sepa_direct_debit/data/payment_type_sdd.xml diff --git a/__unported__/account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml b/account_banking_sepa_direct_debit/demo/sepa_direct_debit_demo.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml rename to account_banking_sepa_direct_debit/demo/sepa_direct_debit_demo.xml diff --git a/__unported__/account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot b/account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot rename to account_banking_sepa_direct_debit/i18n/account_banking_sepa_direct_debit.pot diff --git a/__unported__/account_banking_sepa_direct_debit/i18n/fr.po b/account_banking_sepa_direct_debit/i18n/fr.po similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/i18n/fr.po rename to account_banking_sepa_direct_debit/i18n/fr.po diff --git a/__unported__/account_banking_sepa_direct_debit/i18n/nl.po b/account_banking_sepa_direct_debit/i18n/nl.po similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/i18n/nl.po rename to account_banking_sepa_direct_debit/i18n/nl.po diff --git a/account_banking_sepa_direct_debit/mandate_expire_cron.xml b/account_banking_sepa_direct_debit/mandate_expire_cron.xml new file mode 100644 index 000000000..4cb0693d2 --- /dev/null +++ b/account_banking_sepa_direct_debit/mandate_expire_cron.xml @@ -0,0 +1,26 @@ + + + + + + + + + Set SEPA Direct Debit Mandates to Expired + + + 1 + days + -1 + + + + + + + + diff --git a/account_banking_sepa_direct_debit/models/__init__.py b/account_banking_sepa_direct_debit/models/__init__.py new file mode 100644 index 000000000..36b8b4b56 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/__init__.py @@ -0,0 +1,28 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Direct Debit module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import account_invoice +from . import banking_export_sdd +from . import payment_line +from . import res_company +from . import res_partner_bank +from . import sdd_mandate diff --git a/account_banking_sepa_direct_debit/models/account_invoice.py b/account_banking_sepa_direct_debit/models/account_invoice.py new file mode 100644 index 000000000..eee2b7757 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/account_invoice.py @@ -0,0 +1,32 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Direct Debit module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields + + +class AccountInvoice(models.Model): + _inherit = 'account.invoice' + + sdd_mandate_id = fields.Many2one( + 'sdd.mandate', string='SEPA Direct Debit Mandate', + domain=[('state', '=', 'valid')], readonly=True, + states={'draft': [('readonly', False)]}) diff --git a/account_banking_sepa_direct_debit/models/banking_export_sdd.py b/account_banking_sepa_direct_debit/models/banking_export_sdd.py new file mode 100644 index 000000000..80f5f4a13 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/banking_export_sdd.py @@ -0,0 +1,78 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Direct Debit module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api +from openerp.addons.decimal_precision import decimal_precision as dp +from unidecode import unidecode + + +class BankingExportSdd(models.Model): + """SEPA Direct Debit export""" + _name = 'banking.export.sdd' + _description = __doc__ + _rec_name = 'filename' + + @api.one + def _generate_filename(self): + filename = '' + if self.payment_order_ids: + ref = self.payment_order_ids[0].reference + label = unidecode(ref.replace('/', '-')) if ref else 'error' + filename = 'sdd_%s.xml' % label + self.filename = filename + + payment_order_ids = fields.Many2many( + comodel_name='payment.order', + relation='account_payment_order_sdd_rel', + column1='banking_export_sepa_id', column2='account_order_id', + string='Payment Orders', + readonly=True) + nb_transactions = fields.Integer( + string='Number of Transactions', readonly=True) + total_amount = fields.Float( + string='Total Amount', digits_compute=dp.get_precision('Account'), + readonly=True) + batch_booking = fields.Boolean( + 'Batch Booking', readonly=True, + help="If true, the bank statement will display only one credit line " + "for all the direct debits of the SEPA file ; if false, the bank " + "statement will display one credit line per direct debit of the " + "SEPA file.") + charge_bearer = fields.Selection( + [('SLEV', 'Following Service Level'), + ('SHAR', 'Shared'), + ('CRED', 'Borne by Creditor'), + ('DEBT', 'Borne by Debtor')], 'Charge Bearer', readonly=True, + help="Following service level : transaction charges are to be applied " + "following the rules agreed in the service level and/or scheme " + "(SEPA Core messages must use this). Shared : transaction " + "charges on the creditor side are to be borne by the creditor, " + "transaction charges on the debtor side are to be borne by the " + "debtor. Borne by creditor : all transaction charges are to be " + "borne by the creditor. Borne by debtor : all transaction " + "charges are to be borne by the debtor.") + create_date = fields.Datetime(string='Generation Date', readonly=True) + file = fields.Binary(string='SEPA File', readonly=True) + filename = fields.Char(compute=_generate_filename, size=256, + string='Filename', readonly=True, store=True) + state = fields.Selection([('draft', 'Draft'), ('sent', 'Sent')], + string='State', readonly=True, default='draft') diff --git a/account_banking_sepa_direct_debit/models/payment_line.py b/account_banking_sepa_direct_debit/models/payment_line.py new file mode 100644 index 000000000..31c47bd89 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/payment_line.py @@ -0,0 +1,74 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Direct Debit module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, exceptions, _ + + +class PaymentLine(models.Model): + _inherit = 'payment.line' + + sdd_mandate_id = fields.Many2one( + 'sdd.mandate', string='SEPA Direct Debit Mandate', + domain=[('state', '=', 'valid')]) + + def create(self, vals=None): + """If the customer invoice has a mandate, take it. Otherwise, take the + first valid mandate of the bank account. + """ + if not vals: + vals = {} + partner_bank_id = vals.get('bank_id') + if (self.env.context.get('search_payment_order_type') == 'debit' + and 'sdd_mandate_id' not in vals): + if vals.get('move_line_id'): + line = self.env['account.move.line'].browse( + vals['move_line_id']) + if (line.invoice and line.invoice.type == 'out_invoice' + and line.invoice.sdd_mandate_id): + vals.update( + {'sdd_mandate_id': line.invoice.sdd_mandate_id.id, + 'bank_id': + line.invoice.sdd_mandate_id.partner_bank_id.id}) + if partner_bank_id and 'sdd_mandate_id' not in vals: + mandates = self.env['sdd.mandate'].search( + [('partner_bank_id', '=', partner_bank_id), + ('state', '=', 'valid')]) + if mandates: + vals['sdd_mandate_id'] = mandates.ids[0] + return super(PaymentLine, self).create(vals) + + @api.one + @api.constrains('sdd_mandate_id', 'bank_id') + def _check_mandate_bank_link(self): + if (self.sdd_mandate_id and self.bank_id + and self.sdd_mandate_id.partner_bank_id.id != + self.bank_id.id): + raise exceptions.Warning( + _('Error:'), + _("The payment line with reference '%s' has the bank " + "account '%s' which is not attached to the mandate " + "'%s' (this mandate is attached to the bank account " + "'%s').") % + (self.name, + self.bank_id.name_get()[0][1], + self.sdd_mandate_id.unique_mandate_reference, + self.sdd_mandate_id.partner_bank_id.name_get()[0][1])) diff --git a/account_banking_sepa_direct_debit/models/res_company.py b/account_banking_sepa_direct_debit/models/res_company.py new file mode 100644 index 000000000..327edc401 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/res_company.py @@ -0,0 +1,80 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Direct Debit module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, exceptions, _ +import logging + +logger = logging.getLogger(__name__) + + +class ResCompany(models.Model): + _inherit = 'res.company' + + sepa_creditor_identifier = fields.Char( + string='SEPA Creditor Identifier', size=35, + help="Enter the Creditor Identifier that has been attributed to your " + "company to make SEPA Direct Debits. This identifier is composed " + "of :\n- your country ISO code (2 letters)\n- a 2-digits " + "checkum\n- a 3-letters business code\n- a country-specific " + "identifier") + original_creditor_identifier = fields.Char( + string='Original Creditor Identifier', size=70) + + def is_sepa_creditor_identifier_valid( + self, sepa_creditor_identifier): + """Check if SEPA Creditor Identifier is valid + @param sepa_creditor_identifier: SEPA Creditor Identifier as str + or unicode + @return: True if valid, False otherwise + """ + if not isinstance(sepa_creditor_identifier, (str, unicode)): + return False + try: + sci = str(sepa_creditor_identifier).lower() + except: + logger.warning( + "SEPA Creditor ID should contain only ASCII caracters.") + return False + if len(sci) < 9: + return False + before_replacement = sci[7:] + sci[0:2] + '00' + logger.debug( + "SEPA ID check before_replacement = %s" % before_replacement) + after_replacement = '' + for char in before_replacement: + if char.isalpha(): + after_replacement += str(ord(char)-87) + else: + after_replacement += char + logger.debug( + "SEPA ID check after_replacement = %s" % after_replacement) + return int(sci[2:4]) == (98 - (int(after_replacement) % 97)) + + @api.one + @api.constrains('sepa_creditor_identifier') + def _check_sepa_creditor_identifier(self): + if self.sepa_creditor_identifier: + if not self.is_sepa_creditor_identifier_valid( + self.sepa_creditor_identifier): + raise exceptions.Warning( + _('Error'), + _("Invalid SEPA Creditor Identifier.")) diff --git a/account_banking_sepa_direct_debit/models/res_partner_bank.py b/account_banking_sepa_direct_debit/models/res_partner_bank.py new file mode 100644 index 000000000..132a4fa42 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/res_partner_bank.py @@ -0,0 +1,30 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Direct Debit module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields + + +class ResPartnerBank(models.Model): + _inherit = 'res.partner.bank' + + sdd_mandate_ids = fields.One2many( + 'sdd.mandate', 'partner_bank_id', string='SEPA Direct Debit Mandates') diff --git a/account_banking_sepa_direct_debit/models/sdd_mandate.py b/account_banking_sepa_direct_debit/models/sdd_mandate.py new file mode 100644 index 000000000..ebee316d2 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/sdd_mandate.py @@ -0,0 +1,291 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# SEPA Direct Debit module for OpenERP +# Copyright (C) 2013 Akretion (http://www.akretion.com) +# @author: Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm, fields +from openerp.tools.translate import _ +from datetime import datetime +from dateutil.relativedelta import relativedelta +import logging + +NUMBER_OF_UNUSED_MONTHS_BEFORE_EXPIRY = 36 + +logger = logging.getLogger(__name__) + + +class SddMandate(orm.Model): + """SEPA Direct Debit Mandate""" + _name = 'sdd.mandate' + _description = __doc__ + _rec_name = 'unique_mandate_reference' + _inherit = ['mail.thread'] + _order = 'signature_date desc' + _track = { + 'state': { + 'account_banking_sepa_direct_debit.mandate_valid': + lambda self, cr, uid, obj, ctx=None: + obj['state'] == 'valid', + 'account_banking_sepa_direct_debit.mandate_expired': + lambda self, cr, uid, obj, ctx=None: + obj['state'] == 'expired', + 'account_banking_sepa_direct_debit.mandate_cancel': + lambda self, cr, uid, obj, ctx=None: + obj['state'] == 'cancel', + }, + 'recurrent_sequence_type': { + 'account_banking_sepa_direct_debit.recurrent_sequence_type_first': + lambda self, cr, uid, obj, ctx=None: + obj['recurrent_sequence_type'] == 'first', + 'account_banking_sepa_direct_debit.' + 'recurrent_sequence_type_recurring': + lambda self, cr, uid, obj, ctx=None: + obj['recurrent_sequence_type'] == 'recurring', + 'account_banking_sepa_direct_debit.recurrent_sequence_type_final': + lambda self, cr, uid, obj, ctx=None: + obj['recurrent_sequence_type'] == 'final', + } + } + + _columns = { + 'partner_bank_id': fields.many2one( + 'res.partner.bank', 'Bank Account', track_visibility='onchange'), + 'partner_id': fields.related( + 'partner_bank_id', 'partner_id', type='many2one', + relation='res.partner', string='Partner', readonly=True), + 'company_id': fields.many2one('res.company', 'Company', required=True), + 'unique_mandate_reference': fields.char( + 'Unique Mandate Reference', size=35, readonly=True, + track_visibility='always'), + 'type': fields.selection([ + ('recurrent', 'Recurrent'), + ('oneoff', 'One-Off'), + ], 'Type of Mandate', required=True, track_visibility='always'), + 'recurrent_sequence_type': fields.selection([ + ('first', 'First'), + ('recurring', 'Recurring'), + ('final', 'Final'), + ], 'Sequence Type for Next Debit', track_visibility='onchange', + help="This field is only used for Recurrent mandates, not for " + "One-Off mandates."), + 'signature_date': fields.date( + 'Date of Signature of the Mandate', track_visibility='onchange'), + 'scan': fields.binary('Scan of the Mandate'), + 'last_debit_date': fields.date( + 'Date of the Last Debit', readonly=True), + 'state': fields.selection([ + ('draft', 'Draft'), + ('valid', 'Valid'), + ('expired', 'Expired'), + ('cancel', 'Cancelled'), + ], 'Status', + help="Only valid mandates can be used in a payment line. A " + "cancelled mandate is a mandate that has been cancelled by " + "the customer. A one-off mandate expires after its first use. " + "A recurrent mandate expires after it's final use or if it " + "hasn't been used for 36 months."), + 'payment_line_ids': fields.one2many( + 'payment.line', 'sdd_mandate_id', "Related Payment Lines"), + 'sepa_migrated': fields.boolean( + 'Migrated to SEPA', track_visibility='onchange', + help="If this field is not active, the mandate section of the " + "next direct debit file that include this mandate will contain " + "the 'Original Mandate Identification' and the 'Original " + "Creditor Scheme Identification'. This is required in a few " + "countries (Belgium for instance), but not in all countries. " + "If this is not required in your country, you should keep this " + "field always active."), + 'original_mandate_identification': fields.char( + 'Original Mandate Identification', size=35, + track_visibility='onchange', + help="When the field 'Migrated to SEPA' is not active, this " + "field will be used as the Original Mandate Identification in " + "the Direct Debit file."), + 'scheme': fields.selection([('CORE', 'Basic (CORE)'), + ('B2B', 'Enterprise (B2B)')], + 'Scheme', required=True), + } + + _defaults = { + 'company_id': lambda self, cr, uid, context: + self.pool['res.company']._company_default_get( + cr, uid, 'sdd.mandate', context=context), + 'unique_mandate_reference': '/', + 'state': 'draft', + 'sepa_migrated': True, + 'scheme': 'CORE', + } + + _sql_constraints = [( + 'mandate_ref_company_uniq', + 'unique(unique_mandate_reference, company_id)', + 'A Mandate with the same reference already exists for this company !' + )] + + def create(self, cr, uid, vals, context=None): + if vals.get('unique_mandate_reference', '/') == '/': + vals['unique_mandate_reference'] = \ + self.pool['ir.sequence'].next_by_code( + cr, uid, 'sdd.mandate.reference', context=context) + return super(SddMandate, self).create(cr, uid, vals, context=context) + + def _check_sdd_mandate(self, cr, uid, ids): + for mandate in self.browse(cr, uid, ids): + if (mandate.signature_date and + mandate.signature_date > + datetime.today().strftime('%Y-%m-%d')): + raise orm.except_orm( + _('Error:'), + _("The date of signature of mandate '%s' is in the " + "future !") + % mandate.unique_mandate_reference) + if mandate.state == 'valid' and not mandate.signature_date: + raise orm.except_orm( + _('Error:'), + _("Cannot validate the mandate '%s' without a date of " + "signature.") + % mandate.unique_mandate_reference) + if mandate.state == 'valid' and not mandate.partner_bank_id: + raise orm.except_orm( + _('Error:'), + _("Cannot validate the mandate '%s' because it is not " + "attached to a bank account.") + % mandate.unique_mandate_reference) + + if (mandate.signature_date and mandate.last_debit_date and + mandate.signature_date > mandate.last_debit_date): + raise orm.except_orm( + _('Error:'), + _("The mandate '%s' can't have a date of last debit " + "before the date of signature.") + % mandate.unique_mandate_reference) + if (mandate.type == 'recurrent' + and not mandate.recurrent_sequence_type): + raise orm.except_orm( + _('Error:'), + _("The recurrent mandate '%s' must have a sequence type.") + % mandate.unique_mandate_reference) + if (mandate.type == 'recurrent' and not mandate.sepa_migrated + and mandate.recurrent_sequence_type != 'first'): + raise orm.except_orm( + _('Error:'), + _("The recurrent mandate '%s' which is not marked as " + "'Migrated to SEPA' must have its recurrent sequence " + "type set to 'First'.") + % mandate.unique_mandate_reference) + if (mandate.type == 'recurrent' and not mandate.sepa_migrated + and not mandate.original_mandate_identification): + raise orm.except_orm( + _('Error:'), + _("You must set the 'Original Mandate Identification' " + "on the recurrent mandate '%s' which is not marked " + "as 'Migrated to SEPA'.") + % mandate.unique_mandate_reference) + return True + + _constraints = [ + (_check_sdd_mandate, "Error msg in raise", [ + 'last_debit_date', 'signature_date', 'state', 'partner_bank_id', + 'type', 'recurrent_sequence_type', 'sepa_migrated', + 'original_mandate_identification', + ]), + ] + + def mandate_type_change(self, cr, uid, ids, type): + if type == 'recurrent': + recurrent_sequence_type = 'first' + else: + recurrent_sequence_type = False + res = {'value': {'recurrent_sequence_type': recurrent_sequence_type}} + return res + + def mandate_partner_bank_change( + self, cr, uid, ids, partner_bank_id, type, recurrent_sequence_type, + last_debit_date, state): + res = {'value': {}} + if partner_bank_id: + partner_bank_read = self.pool['res.partner.bank'].read( + cr, uid, partner_bank_id, ['partner_id'])['partner_id'] + if partner_bank_read: + res['value']['partner_id'] = partner_bank_read[0] + if (state == 'valid' and partner_bank_id + and type == 'recurrent' + and recurrent_sequence_type != 'first'): + res['value']['recurrent_sequence_type'] = 'first' + res['warning'] = { + 'title': _('Mandate update'), + 'message': _( + "As you changed the bank account attached to this " + "mandate, the 'Sequence Type' has been set back to " + "'First'."), + } + return res + + def validate(self, cr, uid, ids, context=None): + to_validate_ids = [] + for mandate in self.browse(cr, uid, ids, context=context): + assert mandate.state == 'draft', 'Mandate should be in draft state' + to_validate_ids.append(mandate.id) + self.write( + cr, uid, to_validate_ids, {'state': 'valid'}, context=context) + return True + + def cancel(self, cr, uid, ids, context=None): + to_cancel_ids = [] + for mandate in self.browse(cr, uid, ids, context=context): + assert mandate.state in ('draft', 'valid'),\ + 'Mandate should be in draft or valid state' + to_cancel_ids.append(mandate.id) + self.write( + cr, uid, to_cancel_ids, {'state': 'cancel'}, context=context) + return True + + def back2draft(self, cr, uid, ids, context=None): + to_draft_ids = [] + for mandate in self.browse(cr, uid, ids, context=context): + assert mandate.state == 'cancel',\ + 'Mandate should be in cancel state' + to_draft_ids.append(mandate.id) + self.write( + cr, uid, to_draft_ids, {'state': 'draft'}, context=context) + return True + + def _sdd_mandate_set_state_to_expired(self, cr, uid, context=None): + logger.info('Searching for SDD Mandates that must be set to Expired') + expire_limit_date = datetime.today() + \ + relativedelta(months=-NUMBER_OF_UNUSED_MONTHS_BEFORE_EXPIRY) + expire_limit_date_str = expire_limit_date.strftime('%Y-%m-%d') + expired_mandate_ids = self.search(cr, uid, [ + '|', + ('last_debit_date', '=', False), + ('last_debit_date', '<=', expire_limit_date_str), + ('state', '=', 'valid'), + ('signature_date', '<=', expire_limit_date_str), + ], context=context) + if expired_mandate_ids: + self.write( + cr, uid, expired_mandate_ids, {'state': 'expired'}, + context=context) + logger.info( + 'The following SDD Mandate IDs has been set to expired: %s' + % expired_mandate_ids) + else: + logger.info('0 SDD Mandates must be set to Expired') + return True diff --git a/__unported__/account_banking_sepa_direct_debit/res_partner_bank_view.xml b/account_banking_sepa_direct_debit/res_partner_bank_view.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/res_partner_bank_view.xml rename to account_banking_sepa_direct_debit/res_partner_bank_view.xml diff --git a/__unported__/account_banking_sepa_direct_debit/sdd_mandate_view.xml b/account_banking_sepa_direct_debit/sdd_mandate_view.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/sdd_mandate_view.xml rename to account_banking_sepa_direct_debit/sdd_mandate_view.xml diff --git a/__unported__/account_banking_sepa_direct_debit/security/ir.model.access.csv b/account_banking_sepa_direct_debit/security/ir.model.access.csv similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/security/ir.model.access.csv rename to account_banking_sepa_direct_debit/security/ir.model.access.csv diff --git a/__unported__/account_banking_sepa_direct_debit/security/original_mandate_required_security.xml b/account_banking_sepa_direct_debit/security/original_mandate_required_security.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/security/original_mandate_required_security.xml rename to account_banking_sepa_direct_debit/security/original_mandate_required_security.xml diff --git a/account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml b/account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml new file mode 100644 index 000000000..220261088 --- /dev/null +++ b/account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml @@ -0,0 +1,27 @@ + + + + + + + SEPA Direct Debit La Banque Postale + + + + + + + + FR78ZZZ424242 + + + + + recurrent + first + 2014-02-01 + valid + + + + diff --git a/account_banking_sepa_direct_debit/static/description/icon.svg b/account_banking_sepa_direct_debit/static/description/icon.svg new file mode 100644 index 000000000..c3bc242a4 --- /dev/null +++ b/account_banking_sepa_direct_debit/static/description/icon.svg @@ -0,0 +1,92 @@ + + + +image/svg+xmlDIRECTDEBIT + \ No newline at end of file diff --git a/__unported__/account_banking_sepa_direct_debit/static/src/img/icon.png b/account_banking_sepa_direct_debit/static/src/img/icon.png similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/static/src/img/icon.png rename to account_banking_sepa_direct_debit/static/src/img/icon.png diff --git a/account_banking_sepa_direct_debit/views/account_banking_sdd_view.xml b/account_banking_sepa_direct_debit/views/account_banking_sdd_view.xml new file mode 100644 index 000000000..f74b60353 --- /dev/null +++ b/account_banking_sepa_direct_debit/views/account_banking_sdd_view.xml @@ -0,0 +1,77 @@ + + + + + + + account.banking.export.sdd.form + banking.export.sdd + +
+
+ +
+ + + + + + + + + + + + + + + + +
+
+
+ + + + account.banking.export.sdd.tree + banking.export.sdd + + + + + + + + + + + + + SEPA Direct Debit Files + banking.export.sdd + form + tree,form + + + + + + + +
+
diff --git a/account_banking_sepa_direct_debit/views/account_invoice_view.xml b/account_banking_sepa_direct_debit/views/account_invoice_view.xml new file mode 100644 index 000000000..2ca480e54 --- /dev/null +++ b/account_banking_sepa_direct_debit/views/account_invoice_view.xml @@ -0,0 +1,22 @@ + + + + + + + add.sdd.mandate.on.customer.invoice.form + account.invoice + + + + + + + + + + diff --git a/account_banking_sepa_direct_debit/views/account_payment_view.xml b/account_banking_sepa_direct_debit/views/account_payment_view.xml new file mode 100644 index 000000000..74098c44e --- /dev/null +++ b/account_banking_sepa_direct_debit/views/account_payment_view.xml @@ -0,0 +1,26 @@ + + + + + + + sdd.payment.order.form + payment.order + + + + + + + + + + + + + + diff --git a/account_banking_sepa_direct_debit/views/res_company_view.xml b/account_banking_sepa_direct_debit/views/res_company_view.xml new file mode 100644 index 000000000..e4c9e0b93 --- /dev/null +++ b/account_banking_sepa_direct_debit/views/res_company_view.xml @@ -0,0 +1,23 @@ + + + + + + + sepa_direct_debit.res.company.form + res.company + + + + + + + + + + + diff --git a/account_banking_sepa_direct_debit/views/res_partner_bank_view.xml b/account_banking_sepa_direct_debit/views/res_partner_bank_view.xml new file mode 100644 index 000000000..0b32e9f1c --- /dev/null +++ b/account_banking_sepa_direct_debit/views/res_partner_bank_view.xml @@ -0,0 +1,48 @@ + + + + + + + sdd.mandate.res.partner.bank.form + res.partner.bank + + + + + + + + + + + + sdd.mandate.res.partner.bank.tree + res.partner.bank + + + + + + + + + + + sdd.mandate.partner.form + res.partner + + + + + + + + + + diff --git a/account_banking_sepa_direct_debit/views/sdd_mandate_view.xml b/account_banking_sepa_direct_debit/views/sdd_mandate_view.xml new file mode 100644 index 000000000..4388bd314 --- /dev/null +++ b/account_banking_sepa_direct_debit/views/sdd_mandate_view.xml @@ -0,0 +1,153 @@ + + + + + + + sdd.mandate.form + sdd.mandate + +
+
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + +
+
+ + +
+
+
+
+ + + sdd.mandate.tree + sdd.mandate + + + + + + + + + + + + + + + sdd.mandate.search + sdd.mandate + + + + + + + + + + + + + + + SEPA Direct Debit Mandates + sdd.mandate + form + tree,form + +

+ Click to create a new SEPA Direct Debit Mandate. +

+ A SEPA Direct Debit Mandate is a document signed by your customer that gives you the autorization to do one or several direct debits on his bank account. +

+
+
+ + + + + + Mandate Validated + sdd.mandate + + SEPA Direct Debit Mandate Validated + + + + Mandate Expired + sdd.mandate + + SEPA Direct Debit Mandate has Expired + + + + Mandate Cancelled + sdd.mandate + + SEPA Direct Debit Mandate Cancelled + + + + Sequence Type set to First + sdd.mandate + + Sequence Type set to First + + + + Sequence Type set to Recurring + sdd.mandate + + Sequence Type set to Recurring + + + + Sequence Type set to Final + sdd.mandate + + Sequence Type set to Final + + +
+
diff --git a/__unported__/account_banking_sepa_direct_debit/wizard/__init__.py b/account_banking_sepa_direct_debit/wizard/__init__.py similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/wizard/__init__.py rename to account_banking_sepa_direct_debit/wizard/__init__.py diff --git a/__unported__/account_banking_sepa_direct_debit/wizard/export_sdd.py b/account_banking_sepa_direct_debit/wizard/export_sdd.py similarity index 98% rename from __unported__/account_banking_sepa_direct_debit/wizard/export_sdd.py rename to account_banking_sepa_direct_debit/wizard/export_sdd.py index 19520d318..34e37fc59 100644 --- a/__unported__/account_banking_sepa_direct_debit/wizard/export_sdd.py +++ b/account_banking_sepa_direct_debit/wizard/export_sdd.py @@ -195,6 +195,7 @@ class banking_export_sdd_wizard(orm.TransientModel): "line with partner '%s' and Invoice ref '%s'.") % (line.partner_id.name, line.ml_inv_ref.number)) + scheme = line.sdd_mandate_id.scheme if line.sdd_mandate_id.state != 'valid': raise orm.except_orm( _('Error:'), @@ -225,8 +226,7 @@ class banking_export_sdd_wizard(orm.TransientModel): line.sdd_mandate_id.recurrent_sequence_type assert seq_type_label is not False seq_type = seq_type_map[seq_type_label] - - key = (requested_date, priority, seq_type) + key = (requested_date, priority, seq_type, scheme) if key in lines_per_group: lines_per_group[key].append(line) else: @@ -237,7 +237,7 @@ class banking_export_sdd_wizard(orm.TransientModel): cr, uid, line.id, {'date': requested_date}, context=context) - for (requested_date, priority, sequence_type), lines in \ + for (requested_date, priority, sequence_type, scheme), lines in \ lines_per_group.items(): # B. Payment info payment_info_2_0, nb_of_transactions_2_4, control_sum_2_5 = \ @@ -246,7 +246,7 @@ class banking_export_sdd_wizard(orm.TransientModel): "sepa_export.payment_order_ids[0].reference + '-' + " "sequence_type + '-' + requested_date.replace('-', '') " "+ '-' + priority", - priority, 'CORE', sequence_type, requested_date, { + priority, scheme, sequence_type, requested_date, { 'sepa_export': sepa_export, 'sequence_type': sequence_type, 'priority': priority, diff --git a/__unported__/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml b/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml similarity index 100% rename from __unported__/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml rename to account_banking_sepa_direct_debit/wizard/export_sdd_view.xml diff --git a/account_direct_debit/__init__.py b/account_direct_debit/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/account_direct_debit/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/__unported__/account_direct_debit/__openerp__.py b/account_direct_debit/__openerp__.py similarity index 80% rename from __unported__/account_direct_debit/__openerp__.py rename to account_direct_debit/__openerp__.py index 26f6beba7..b7f1660e3 100644 --- a/__unported__/account_direct_debit/__openerp__.py +++ b/account_direct_debit/__openerp__.py @@ -27,10 +27,10 @@ 'category': 'Banking addons', 'depends': ['account_banking_payment_export'], 'data': [ - 'view/account_payment.xml', - 'view/account_invoice.xml', - 'view/payment_mode.xml', - 'view/payment_mode_type.xml', + 'views/account_payment.xml', + 'views/account_invoice.xml', + 'views/payment_mode.xml', + 'views/payment_mode_type.xml', 'workflow/account_invoice.xml', 'data/account_payment_term.xml', ], @@ -44,11 +44,6 @@ in the Netherlands. Debit orders are advanced in total by the bank. Amounts that cannot be debited or are canceled by account owners are credited afterwards. Such a creditation is called a storno. This style of direct debit order may not apply to your country. - -This module depends on and is part of the banking addons for OpenERP. This set -of modules helps you to provide support for communications with your local -banking institutions. The banking addons are a continuation of Account Banking -Framework by Edusense BV. See https://launchpad.net/banking-addons. ''', - 'installable': False, + 'installable': True, } diff --git a/__unported__/account_direct_debit/data/account_payment_term.xml b/account_direct_debit/data/account_payment_term.xml similarity index 100% rename from __unported__/account_direct_debit/data/account_payment_term.xml rename to account_direct_debit/data/account_payment_term.xml diff --git a/__unported__/account_direct_debit/i18n/account_direct_debit.pot b/account_direct_debit/i18n/account_direct_debit.pot similarity index 100% rename from __unported__/account_direct_debit/i18n/account_direct_debit.pot rename to account_direct_debit/i18n/account_direct_debit.pot diff --git a/__unported__/account_direct_debit/i18n/nl.po b/account_direct_debit/i18n/nl.po similarity index 100% rename from __unported__/account_direct_debit/i18n/nl.po rename to account_direct_debit/i18n/nl.po diff --git a/__unported__/account_direct_debit/migrations/7.0.2/post-migration.py b/account_direct_debit/migrations/7.0.2/post-migration.py similarity index 100% rename from __unported__/account_direct_debit/migrations/7.0.2/post-migration.py rename to account_direct_debit/migrations/7.0.2/post-migration.py diff --git a/__unported__/account_direct_debit/migrations/7.0.2/pre-migration.py b/account_direct_debit/migrations/7.0.2/pre-migration.py similarity index 100% rename from __unported__/account_direct_debit/migrations/7.0.2/pre-migration.py rename to account_direct_debit/migrations/7.0.2/pre-migration.py diff --git a/account_direct_debit/models/__init__.py b/account_direct_debit/models/__init__.py new file mode 100644 index 000000000..ffb948151 --- /dev/null +++ b/account_direct_debit/models/__init__.py @@ -0,0 +1,4 @@ +from . import account_payment +from . import payment_line +from . import account_move_line +from . import account_invoice diff --git a/__unported__/account_direct_debit/model/account_invoice.py b/account_direct_debit/models/account_invoice.py similarity index 95% rename from __unported__/account_direct_debit/model/account_invoice.py rename to account_direct_debit/models/account_invoice.py index fe2e92337..246b7f413 100644 --- a/__unported__/account_direct_debit/model/account_invoice.py +++ b/account_direct_debit/models/account_invoice.py @@ -39,7 +39,7 @@ Invoice workflow: Balance: Debtors 2000 | - Sales | 2000 + Sales | 2000 2 an external booking takes place 1100 Bank 100 @@ -105,8 +105,8 @@ Two cases need to be distinguisted: uid, 'account.invoice', ids, 'debit_denied', cr) 2) If the storno is an error generated by the bank (assumingly non-fatal), - the invoice is reopened for the next debit run. - This is a call to existing + the invoice is reopened for the next debit run. This is a call to + existing netsvc.LocalService("workflow").trg_validate( uid, 'account.invoice', ids, 'open_test', cr) @@ -123,7 +123,7 @@ Two cases need to be distinguisted: """ -class account_invoice(orm.Model): +class AccountInvoice(orm.Model): _inherit = "account.invoice" def __init__(self, pool, cr): @@ -135,7 +135,7 @@ class account_invoice(orm.Model): Maybe apply a similar trick when overriding the buttons' 'states' attributes in the form view, manipulating the xml in fields_view_get(). """ - super(account_invoice, self).__init__(pool, cr) + super(AccountInvoice, self).__init__(pool, cr) invoice_obj = pool.get('account.invoice') invoice_obj._columns['state'].selection.append( ('debit_denied', 'Debit denied')) @@ -147,8 +147,8 @@ class account_invoice(orm.Model): cr, uid, invoice_id, ['number'], context=context)['number'] raise orm.except_orm( _('Error !'), - _("You cannot set invoice '%s' to state 'debit denied', " - 'as it is still reconciled.') % number) + _("You cannot set invoice '%s' to state 'debit " + "denied', as it is still reconciled.") % number) self.write(cr, uid, ids, {'state': 'debit_denied'}, context=context) for inv_id, name in self.name_get(cr, uid, ids, context=context): message = _("Invoice '%s': direct debit is denied.") % name diff --git a/__unported__/account_direct_debit/model/account_move_line.py b/account_direct_debit/models/account_move_line.py similarity index 86% rename from __unported__/account_direct_debit/model/account_move_line.py rename to account_direct_debit/models/account_move_line.py index 12842e45f..3e48e1f8a 100644 --- a/__unported__/account_direct_debit/model/account_move_line.py +++ b/account_direct_debit/models/account_move_line.py @@ -24,12 +24,11 @@ from operator import itemgetter from openerp.osv import fields, orm -class account_move_line(orm.Model): +class AccountMoveLine(orm.Model): _inherit = "account.move.line" - def amount_to_receive(self, cr, uid, ids, name, arg={}, context=None): - """ - Return the amount still to receive regarding all the debit orders + def _amount_to_receive(self, cr, uid, ids, name, arg={}, context=None): + """Return the amount still to receive regarding all the debit orders (excepting canceled orders). This is the reverse from amount_to_pay() in account_payment/account_move_line.py @@ -49,13 +48,12 @@ class account_move_line(orm.Model): AND pl.storno is false AND po.state != 'cancel') AS amount FROM account_move_line ml - WHERE id IN %s""", (tuple(ids), )) + WHERE id IN %s""", (tuple(ids),)) r = dict(cr.fetchall()) return r def _to_receive_search(self, cr, uid, obj, name, args, context=None): - """ - Reverse of account_payment/account_move_line.py:_to_pay_search() + """Reverse of account_payment/account_move_line.py:_to_pay_search(). """ if not args: return [] @@ -81,23 +79,21 @@ class account_move_line(orm.Model): WHERE type=%s AND active) AND reconcile_id IS null AND debit > 0 - AND ''' + where + ' and ' + query), ('receivable', ) + sql_args) + AND ''' + where + ' and ' + query), ('receivable',) + sql_args) res = cr.fetchall() if not res: return [('id', '=', '0')] - return [('id', 'in', map(lambda x: x[0], res))] + return [('id', 'in', map(lambda x:x[0], res))] def line2bank(self, cr, uid, ids, payment_mode_id, context=None): - '''I have to inherit this function for direct debits to fix the + """I have to inherit this function for direct debits to fix the following issue : if the customer invoice has a value for 'partner_bank_id', then it will take this partner_bank_id in the payment line... but, on a customer invoice, the partner_bank_id is the bank account of the company, not the bank account of the customer ! - ''' - if context is None: - context = {} + """ pay_mode_obj = self.pool['payment.mode'] if payment_mode_id: pay_mode = pay_mode_obj.browse( @@ -114,12 +110,12 @@ class account_move_line(orm.Model): line2bank[line.id] = bank.id break return line2bank - return super(account_move_line, self).line2bank( + return super(AccountMoveLine, self).line2bank( cr, uid, ids, payment_mode_id, context=context) _columns = { 'amount_to_receive': fields.function( - amount_to_receive, method=True, + _amount_to_receive, method=True, type='float', string='Amount to receive', fnct_search=_to_receive_search), } diff --git a/__unported__/account_direct_debit/model/account_payment.py b/account_direct_debit/models/account_payment.py similarity index 76% rename from __unported__/account_direct_debit/model/account_payment.py rename to account_direct_debit/models/account_payment.py index b346efec3..702477107 100644 --- a/__unported__/account_direct_debit/model/account_payment.py +++ b/account_direct_debit/models/account_payment.py @@ -2,12 +2,11 @@ from openerp.osv import orm -class payment_order(orm.Model): +class PaymentOrder(orm.Model): _inherit = 'payment.order' def test_undo_done(self, cr, uid, ids, context=None): - """ - Called from the workflow. Used to unset done state on + """Called from the workflow. Used to unset done state on payment orders that were reconciled with bank transfers which are being cancelled """ @@ -16,5 +15,5 @@ class payment_order(orm.Model): for line in order.line_ids: if line.storno: return False - return super(payment_order, self).test_undo_done( + return super(PaymentOrder, self).test_undo_done( cr, uid, ids, context=context) diff --git a/__unported__/account_direct_debit/model/payment_line.py b/account_direct_debit/models/payment_line.py similarity index 76% rename from __unported__/account_direct_debit/model/payment_line.py rename to account_direct_debit/models/payment_line.py index 2be0993db..da0a839cf 100644 --- a/__unported__/account_direct_debit/model/payment_line.py +++ b/account_direct_debit/models/payment_line.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- from openerp.osv import orm, fields -import netsvc -from tools.translate import _ +from openerp import netsvc +from openerp.tools.translate import _ -class payment_line(orm.Model): +class PaymentLine(orm.Model): _inherit = 'payment.line' def debit_storno(self, cr, uid, payment_line_id, amount, currency, storno_retry=True, context=None): - """ - The processing of a storno is triggered by a debit + """The processing of a storno is triggered by a debit transfer on one of the company's bank accounts. This method offers to re-reconcile the original debit payment. For this purpose, we have registered that @@ -23,15 +22,13 @@ class payment_line(orm.Model): :param payment_line_id: the single payment line id :param amount: the (signed) amount debited from the bank account :param currency: the bank account's currency *browse object* - :param boolean storno_retry: when True, attempt to reopen the \ - invoice, set the invoice to 'Debit denied' otherwise. + :param boolean storno_retry: when True, attempt to reopen the invoice, + set the invoice to 'Debit denied' otherwise. :return: an incomplete reconcile for the caller to fill :rtype: database id of an account.move.reconcile resource. """ - reconcile_obj = self.pool.get('account.move.reconcile') line = self.browse(cr, uid, payment_line_id) - transit_move_line = line.transit_move_line_id reconcile_id = False if (line.transit_move_line_id and not line.storno and self.pool.get('res.currency').is_zero( @@ -44,41 +41,45 @@ class payment_line(orm.Model): # Actually, given the nature of a direct debit order and storno, # we should not need to take partial into account on the side of # the transit_move_line. - if transit_move_line.reconcile_partial_id: - reconcile_id = transit_move_line.reconcile_partial_id.id - if len(transit_move_line.reconcile_id.line_partial_ids) == 2: + if line.transit_move_line_id.reconcile_partial_id: + reconcile_id = \ + line.transit_move_line_id.reconcile_partial_id.id + reconcile = line.transit_move_line_id.reconcile_id + if len(reconcile.line_partial_ids) == 2: # reuse the simple reconcile for the storno transfer reconcile_obj.write( cr, uid, reconcile_id, { - 'line_id': [(6, 0, transit_move_line.id)], + 'line_id': [(6, 0, line.transit_move_line_id.id)], 'line_partial_ids': [(6, 0, [])], }, context=context) else: # split up the original reconcile in a partial one # and a new one for reconciling the storno transfer + reconcile = { + 'line_partial_ids': [(3, line.transit_move_line_id.id)] + } reconcile_obj.write( - cr, uid, reconcile_id, { - 'line_partial_ids': [(3, transit_move_line.id)], - }, context=context) + cr, uid, reconcile_id, reconcile, context=context) reconcile_id = reconcile_obj.create( cr, uid, { 'type': 'auto', - 'line_id': [(6, 0, transit_move_line.id)], + 'line_id': [(6, 0, line.transit_move_line_id.id)], }, context=context) - elif transit_move_line.reconcile_id: - reconcile_id = transit_move_line.reconcile_id.id - if len(transit_move_line.reconcile_id.line_id) == 2: + elif line.transit_move_line_id.reconcile_id: + reconcile_id = line.transit_move_line_id.reconcile_id.id + if len(line.transit_move_line_id.reconcile_id.line_id) == 2: # reuse the simple reconcile for the storno transfer reconcile_obj.write( cr, uid, reconcile_id, { - 'line_id': [(6, 0, [transit_move_line.id])] + 'line_id': [(6, 0, [line.transit_move_line_id.id])] }, context=context) else: # split up the original reconcile in a partial one # and a new one for reconciling the storno transfer + reconcile = line.transit_move_line_id.reconcile_id partial_ids = [ - x.id for x in transit_move_line.reconcile_id.line_id - if x.id != transit_move_line.id + x.id for x in reconcile.line_id + if x.id != line.transit_move_line_id.id ] reconcile_obj.write( cr, uid, reconcile_id, { @@ -88,7 +89,7 @@ class payment_line(orm.Model): reconcile_id = reconcile_obj.create( cr, uid, { 'type': 'auto', - 'line_id': [(6, 0, transit_move_line.id)], + 'line_id': [(6, 0, line.transit_move_line_id.id)], }, context=context) # mark the payment line for storno processed if reconcile_id: @@ -103,10 +104,9 @@ class payment_line(orm.Model): activity, cr) return reconcile_id - def get_storno_account_id(self, cr, uid, payment_line_id, amount, - currency, context=None): - """ - Check the match of the arguments, and return the account associated + def get_storno_account_id( + self, cr, uid, payment_line_id, amount, currency, context=None): + """Check the match of the arguments, and return the account associated with the storno. Used in account_banking interactive mode @@ -116,7 +116,6 @@ class payment_line(orm.Model): :return: an account if there is a full match, False otherwise :rtype: database id of an account.account resource. """ - line = self.browse(cr, uid, payment_line_id) account_id = False if (line.transit_move_line_id and not line.storno and @@ -128,9 +127,7 @@ class payment_line(orm.Model): return account_id def debit_reconcile(self, cr, uid, payment_line_id, context=None): - """ - Raise if a payment line is passed for which storno is True - """ + """Raise if a payment line is passed for which storno is True.""" if isinstance(payment_line_id, (list, tuple)): payment_line_id = payment_line_id[0] payment_line_vals = self.read( @@ -140,7 +137,7 @@ class payment_line(orm.Model): _('Can not reconcile'), _('Cancelation of payment line \'%s\' has already been ' 'processed') % payment_line_vals['name']) - return super(payment_line, self).debit_reconcile( + return super(PaymentLine, self).debit_reconcile( cr, uid, payment_line_id, context=context) _columns = { diff --git a/__unported__/account_direct_debit/view/account_invoice.xml b/account_direct_debit/views/account_invoice.xml similarity index 100% rename from __unported__/account_direct_debit/view/account_invoice.xml rename to account_direct_debit/views/account_invoice.xml diff --git a/__unported__/account_direct_debit/view/account_payment.xml b/account_direct_debit/views/account_payment.xml similarity index 71% rename from __unported__/account_direct_debit/view/account_payment.xml rename to account_direct_debit/views/account_payment.xml index b5cbd73b2..8570789da 100644 --- a/__unported__/account_direct_debit/view/account_payment.xml +++ b/account_direct_debit/views/account_payment.xml @@ -19,7 +19,7 @@ [('payment_order_type', '=', 'debit')] A debit order is a debit request from your company to collect customer invoices. Here you can register all debit orders that should be done, keep track of all debit orders and mention the invoice reference and the partner the withdrawal should be done for.
- + @@ -29,23 +29,22 @@ - - - - - - {'invisible':['|',('state','!=','draft'),('payment_order_type', '!=', 'payment')]} - - - - +
+
[('payment_order_type', '=', payment_order_type)] diff --git a/__unported__/account_direct_debit/view/payment_mode.xml b/account_direct_debit/views/payment_mode.xml similarity index 100% rename from __unported__/account_direct_debit/view/payment_mode.xml rename to account_direct_debit/views/payment_mode.xml diff --git a/__unported__/account_direct_debit/view/payment_mode_type.xml b/account_direct_debit/views/payment_mode_type.xml similarity index 52% rename from __unported__/account_direct_debit/view/payment_mode_type.xml rename to account_direct_debit/views/payment_mode_type.xml index eb726750d..54c14367d 100644 --- a/__unported__/account_direct_debit/view/payment_mode_type.xml +++ b/account_direct_debit/views/payment_mode_type.xml @@ -2,15 +2,26 @@ - + + view.payment.mode.type.tree + payment.mode.type + + + + + + + + view.payment.mode.type.form payment.mode.type - + diff --git a/account_direct_debit/wizard/__init__.py b/account_direct_debit/wizard/__init__.py new file mode 100644 index 000000000..cbcdda94a --- /dev/null +++ b/account_direct_debit/wizard/__init__.py @@ -0,0 +1 @@ +from . import payment_order_create diff --git a/__unported__/account_direct_debit/model/payment_order_create.py b/account_direct_debit/wizard/payment_order_create.py similarity index 80% rename from __unported__/account_direct_debit/model/payment_order_create.py rename to account_direct_debit/wizard/payment_order_create.py index 5625faac2..d69a4eb78 100644 --- a/__unported__/account_direct_debit/model/payment_order_create.py +++ b/account_direct_debit/wizard/payment_order_create.py @@ -25,17 +25,15 @@ from openerp.osv import orm -class payment_order_create(orm.TransientModel): +class PaymentOrderCreate(orm.TransientModel): _inherit = 'payment.order.create' def extend_payment_order_domain( self, cr, uid, payment_order, domain, context=None): - super(payment_order_create, self).extend_payment_order_domain( + super(PaymentOrderCreate, self).extend_payment_order_domain( cr, uid, payment_order, domain, context=context) if payment_order.payment_order_type == 'debit': - domain += [ - ('account_id.type', '=', 'receivable'), - ('invoice.state', '!=', 'debit_denied'), - ('amount_to_receive', '>', 0), - ] + domain += [('account_id.type', '=', 'receivable'), + ('invoice.state', '!=', 'debit_denied'), + ('amount_to_receive', '>', 0)] return True diff --git a/__unported__/account_direct_debit/workflow/account_invoice.xml b/account_direct_debit/workflow/account_invoice.xml similarity index 100% rename from __unported__/account_direct_debit/workflow/account_invoice.xml rename to account_direct_debit/workflow/account_invoice.xml diff --git a/account_payment_partner/__init__.py b/account_payment_partner/__init__.py new file mode 100644 index 000000000..fe47437f2 --- /dev/null +++ b/account_payment_partner/__init__.py @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Partner module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import models +from . import wizard diff --git a/__unported__/account_payment_partner/__openerp__.py b/account_payment_partner/__openerp__.py similarity index 88% rename from __unported__/account_payment_partner/__openerp__.py rename to account_payment_partner/__openerp__.py index 1a2ffeea9..3f3a51f3f 100644 --- a/__unported__/account_payment_partner/__openerp__.py +++ b/account_payment_partner/__openerp__.py @@ -39,18 +39,15 @@ This module adds severals fields : On a Payment Order, in the wizard *Select Invoices to Pay*, the invoices will be filtered per Payment Mode. - -Please contact Alexis de Lattre from Akretion -for any help or question about this module. """, 'author': 'Akretion', 'website': 'http://www.akretion.com', + 'contributors': ['Pedro M. Baeza '], 'depends': ['account_banking_payment_export'], 'data': [ - 'view/partner.xml', - 'view/account_invoice.xml', + 'views/res_partner_view.xml', + 'views/account_invoice_view.xml', ], 'demo': ['demo/partner_demo.xml'], - 'active': False, - 'installable': False, + 'installable': True, } diff --git a/__unported__/account_payment_partner/demo/partner_demo.xml b/account_payment_partner/demo/partner_demo.xml similarity index 100% rename from __unported__/account_payment_partner/demo/partner_demo.xml rename to account_payment_partner/demo/partner_demo.xml diff --git a/__unported__/account_payment_partner/i18n/account_payment_partner.pot b/account_payment_partner/i18n/account_payment_partner.pot similarity index 100% rename from __unported__/account_payment_partner/i18n/account_payment_partner.pot rename to account_payment_partner/i18n/account_payment_partner.pot diff --git a/__unported__/account_payment_partner/i18n/nl.po b/account_payment_partner/i18n/nl.po similarity index 100% rename from __unported__/account_payment_partner/i18n/nl.po rename to account_payment_partner/i18n/nl.po diff --git a/__unported__/account_payment_partner/model/__init__.py b/account_payment_partner/models/__init__.py similarity index 94% rename from __unported__/account_payment_partner/model/__init__.py rename to account_payment_partner/models/__init__.py index 16ab8bc9e..c2c7b405d 100644 --- a/__unported__/account_payment_partner/model/__init__.py +++ b/account_payment_partner/models/__init__.py @@ -20,6 +20,5 @@ # ############################################################################## -from . import partner +from . import res_partner from . import account_invoice -from . import payment_order_create diff --git a/__unported__/account_payment_partner/model/account_invoice.py b/account_payment_partner/models/account_invoice.py similarity index 65% rename from __unported__/account_payment_partner/model/account_invoice.py rename to account_payment_partner/models/account_invoice.py index 607cda29a..cbbd4b5b9 100644 --- a/__unported__/account_payment_partner/model/account_invoice.py +++ b/account_payment_partner/models/account_invoice.py @@ -20,37 +20,32 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api -class account_invoice(orm.Model): +class AccountInvoice(models.Model): _inherit = 'account.invoice' - _columns = { - 'payment_mode_id': fields.many2one( - 'payment.mode', 'Payment Mode'), - } + payment_mode_id = fields.Many2one('payment.mode', string="Payment Mode") + @api.multi def onchange_partner_id( - self, cr, uid, ids, type, partner_id, date_invoice=False, + self, type, partner_id, date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False): - res = super(account_invoice, self).onchange_partner_id( - cr, uid, ids, type, partner_id, date_invoice=date_invoice, + res = super(AccountInvoice, self).onchange_partner_id( + type, partner_id, date_invoice=date_invoice, payment_term=payment_term, partner_bank_id=partner_bank_id, company_id=company_id) if partner_id: - partner = self.pool['res.partner'].browse(cr, uid, partner_id) + partner = self.env['res.partner'].browse(partner_id) if type == 'in_invoice': res['value']['payment_mode_id'] = \ - partner.supplier_payment_mode.id or False + partner.supplier_payment_mode.id elif type == 'out_invoice': res['value'].update({ - 'payment_mode_id': - partner.customer_payment_mode.id or False, - 'partner_bank_id': - partner.customer_payment_mode and - partner.customer_payment_mode.bank_id.id or False, - }) + 'payment_mode_id': partner.customer_payment_mode.id, + 'partner_bank_id': partner.customer_payment_mode.bank_id.id + }) else: res['value']['payment_mode_id'] = False return res diff --git a/__unported__/account_payment_partner/model/partner.py b/account_payment_partner/models/partner.py similarity index 100% rename from __unported__/account_payment_partner/model/partner.py rename to account_payment_partner/models/partner.py diff --git a/__unported__/account_payment_partner/model/payment_order_create.py b/account_payment_partner/models/payment_order_create.py similarity index 100% rename from __unported__/account_payment_partner/model/payment_order_create.py rename to account_payment_partner/models/payment_order_create.py diff --git a/account_payment_partner/models/res_partner.py b/account_payment_partner/models/res_partner.py new file mode 100644 index 000000000..c8762f7d5 --- /dev/null +++ b/account_payment_partner/models/res_partner.py @@ -0,0 +1,42 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Partner module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class ResPartner(models.Model): + _inherit = 'res.partner' + + supplier_payment_mode = fields.Many2one( + 'payment.mode', string='Supplier Payment Mode', company_dependent=True, + domain="[('payment_order_type', '=', 'payment')]", + help="Select the default payment mode for this supplier.") + customer_payment_mode = fields.Many2one( + 'payment.mode', string='Customer Payment Mode', company_dependent=True, + domain="[('payment_order_type', '=', 'debit')]", + help="Select the default payment mode for this customer.") + + @api.model + def _commercial_fields(self): + res = super(ResPartner, self)._commercial_fields() + res += ['supplier_payment_mode', 'customer_payment_mode'] + return res diff --git a/__unported__/account_payment_partner/view/account_invoice.xml b/account_payment_partner/views/account_invoice.xml similarity index 100% rename from __unported__/account_payment_partner/view/account_invoice.xml rename to account_payment_partner/views/account_invoice.xml diff --git a/account_payment_partner/views/account_invoice_view.xml b/account_payment_partner/views/account_invoice_view.xml new file mode 100644 index 000000000..f4805fa89 --- /dev/null +++ b/account_payment_partner/views/account_invoice_view.xml @@ -0,0 +1,40 @@ + + + + + + + + + + account_payment_partner.invoice_form + account.invoice + + + + + + + + + + + account_payment_partner.invoice_supplier_form + account.invoice + + + + + + + + + + + diff --git a/__unported__/account_payment_partner/view/partner.xml b/account_payment_partner/views/partner.xml similarity index 100% rename from __unported__/account_payment_partner/view/partner.xml rename to account_payment_partner/views/partner.xml diff --git a/account_payment_partner/views/res_partner_view.xml b/account_payment_partner/views/res_partner_view.xml new file mode 100644 index 000000000..3c6d670aa --- /dev/null +++ b/account_payment_partner/views/res_partner_view.xml @@ -0,0 +1,27 @@ + + + + + + + + + account_partner_payment.partner_form + res.partner + + + + + + + + + + + + + diff --git a/__unported__/account_payment_partner/__init__.py b/account_payment_partner/wizard/__init__.py similarity index 96% rename from __unported__/account_payment_partner/__init__.py rename to account_payment_partner/wizard/__init__.py index 161123944..f7107a63f 100644 --- a/__unported__/account_payment_partner/__init__.py +++ b/account_payment_partner/wizard/__init__.py @@ -20,4 +20,4 @@ # ############################################################################## -from . import model +from . import payment_order_create diff --git a/account_payment_partner/wizard/payment_order_create.py b/account_payment_partner/wizard/payment_order_create.py new file mode 100644 index 000000000..c26b7f9d9 --- /dev/null +++ b/account_payment_partner/wizard/payment_order_create.py @@ -0,0 +1,37 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Partner module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, api + + +class PaymentOrderCreate(models.TransientModel): + _inherit = 'payment.order.create' + + @api.model + def extend_payment_order_domain(self, payment_order, domain): + res = super(PaymentOrderCreate, self).extend_payment_order_domain( + payment_order, domain) + domain += ['|', '|', + ('invoice', '=', False), + ('invoice.payment_mode_id', '=', False), + ('invoice.payment_mode_id', '=', payment_order.mode.id)] + return res diff --git a/__unported__/account_payment_purchase/__init__.py b/account_payment_purchase/__init__.py similarity index 98% rename from __unported__/account_payment_purchase/__init__.py rename to account_payment_purchase/__init__.py index 59199014f..b21037b9f 100644 --- a/__unported__/account_payment_purchase/__init__.py +++ b/account_payment_purchase/__init__.py @@ -20,4 +20,4 @@ # ############################################################################## -from . import model +from . import models diff --git a/__unported__/account_payment_purchase/__openerp__.py b/account_payment_purchase/__openerp__.py similarity index 82% rename from __unported__/account_payment_purchase/__openerp__.py rename to account_payment_purchase/__openerp__.py index 25a2a73b7..e7c258f73 100644 --- a/__unported__/account_payment_purchase/__openerp__.py +++ b/account_payment_purchase/__openerp__.py @@ -30,26 +30,27 @@ Account Payment Purchase ======================== -This modules adds 2 fields on purchase orders : *Bank Account* and *Payment +This module adds 2 fields on purchase orders : *Bank Account* and *Payment Mode*. These fields are copied from partner to purchase order and then from purchase order to supplier invoice. This module is similar to the *purchase_payment* module ; the main difference is that it doesn't depend on the *account_payment_extension* module (it's not the only module to conflict with *account_payment_extension* ; all the SEPA -modules in the banking addons conflict with *account_payment_extension*, cf -banking-addons-70/account_banking_payment_export/__openerp__.py). - -Please contact Alexis de Lattre from Akretion -for any help or question about this module. +modules in the banking addons conflict with *account_payment_extension*). """, 'author': 'Akretion', 'website': 'http://www.akretion.com', - 'depends': ['purchase', 'account_payment_partner'], + 'contributors': ['Pedro M. Baeza '], + 'depends': [ + 'purchase', + 'stock_account', + 'account_payment_partner' + ], 'conflicts': ['purchase_payment'], 'data': [ - 'view/purchase.xml', + 'views/purchase_order_view.xml', ], - 'installable': False, + 'installable': True, 'active': False, } diff --git a/__unported__/account_payment_purchase/i18n/account_payment_purchase.pot b/account_payment_purchase/i18n/account_payment_purchase.pot similarity index 100% rename from __unported__/account_payment_purchase/i18n/account_payment_purchase.pot rename to account_payment_purchase/i18n/account_payment_purchase.pot diff --git a/__unported__/account_payment_purchase/i18n/fr.po b/account_payment_purchase/i18n/fr.po similarity index 100% rename from __unported__/account_payment_purchase/i18n/fr.po rename to account_payment_purchase/i18n/fr.po diff --git a/__unported__/account_payment_purchase/i18n/nl.po b/account_payment_purchase/i18n/nl.po similarity index 100% rename from __unported__/account_payment_purchase/i18n/nl.po rename to account_payment_purchase/i18n/nl.po diff --git a/__unported__/account_payment_purchase/model/__init__.py b/account_payment_purchase/model/__init__.py similarity index 100% rename from __unported__/account_payment_purchase/model/__init__.py rename to account_payment_purchase/model/__init__.py diff --git a/__unported__/account_payment_purchase/model/purchase.py b/account_payment_purchase/model/purchase.py similarity index 100% rename from __unported__/account_payment_purchase/model/purchase.py rename to account_payment_purchase/model/purchase.py diff --git a/__unported__/account_payment_purchase/model/stock.py b/account_payment_purchase/model/stock.py similarity index 100% rename from __unported__/account_payment_purchase/model/stock.py rename to account_payment_purchase/model/stock.py diff --git a/account_payment_purchase/models/__init__.py b/account_payment_purchase/models/__init__.py new file mode 100644 index 000000000..3d13bc0e4 --- /dev/null +++ b/account_payment_purchase/models/__init__.py @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Purchase module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import purchase_order +from . import stock_picking diff --git a/account_payment_purchase/models/purchase_order.py b/account_payment_purchase/models/purchase_order.py new file mode 100644 index 000000000..e1ca139ff --- /dev/null +++ b/account_payment_purchase/models/purchase_order.py @@ -0,0 +1,63 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Purchase module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + supplier_partner_bank_id = fields.Many2one( + 'res.partner.bank', string='Supplier Bank Account', + domain="[('partner_id', '=', partner_id)]", + help="Select the bank account of your supplier on which your company " + "should send the payment. This field is copied from the partner " + "and will be copied to the supplier invoice.") + payment_mode_id = fields.Many2one( + 'payment.mode', string='Payment Mode', + domain="[('payment_order_type', '=', 'payment')]") + + @api.model + def _get_default_supplier_partner_bank(self, partner): + """This function is designed to be inherited""" + return partner.bank_ids and partner.bank_ids[0].id or False + + @api.multi + def onchange_partner_id(self, partner_id): + res = super(PurchaseOrder, self).onchange_partner_id(partner_id) + if partner_id: + partner = self.env['res.partner'].browse(partner_id) + res['value']['supplier_partner_bank_id'] = \ + self._get_default_supplier_partner_bank(partner) + res['value']['payment_mode_id'] = partner.supplier_payment_mode.id + else: + res['value']['supplier_partner_bank_id'] = False + res['value']['payment_mode_id'] = False + return res + + @api.model + def _prepare_invoice(self, order, line_ids): + res = super(PurchaseOrder, self)._prepare_invoice(order, line_ids) + if order: + res['partner_bank_id'] = order.supplier_partner_bank_id.id + res['payment_mode_id'] = order.payment_mode_id.id + return res diff --git a/account_payment_purchase/models/stock_picking.py b/account_payment_purchase/models/stock_picking.py new file mode 100644 index 000000000..2ab8c6073 --- /dev/null +++ b/account_payment_purchase/models/stock_picking.py @@ -0,0 +1,38 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Purchase module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, api + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + @api.model + def _create_invoice_from_picking(self, picking, vals): + if picking and picking.move_lines: + # Get purchase order from first move line + if picking.move_lines[0].purchase_line_id: + purchase = picking.move_lines[0].purchase_line_id.order_id + vals['partner_bank_id'] = purchase.supplier_partner_bank_id.id + vals['payment_mode_id'] = purchase.payment_mode_id.id + return super(StockPicking, self)._create_invoice_from_picking(picking, + vals) diff --git a/__unported__/account_payment_purchase/view/purchase.xml b/account_payment_purchase/view/purchase.xml similarity index 100% rename from __unported__/account_payment_purchase/view/purchase.xml rename to account_payment_purchase/view/purchase.xml diff --git a/account_payment_purchase/views/purchase_order_view.xml b/account_payment_purchase/views/purchase_order_view.xml new file mode 100644 index 000000000..0e25c175e --- /dev/null +++ b/account_payment_purchase/views/purchase_order_view.xml @@ -0,0 +1,25 @@ + + + + + + + + + account_payment_purchase.purchase_order.form + purchase.order + + + + + + + + + + + diff --git a/__unported__/account_payment_sale/__init__.py b/account_payment_sale/__init__.py similarity index 98% rename from __unported__/account_payment_sale/__init__.py rename to account_payment_sale/__init__.py index 83c0dcfe2..11323c6e9 100644 --- a/__unported__/account_payment_sale/__init__.py +++ b/account_payment_sale/__init__.py @@ -20,4 +20,4 @@ # ############################################################################## -from . import model +from . import models diff --git a/__unported__/account_payment_sale/__openerp__.py b/account_payment_sale/__openerp__.py similarity index 85% rename from __unported__/account_payment_sale/__openerp__.py rename to account_payment_sale/__openerp__.py index b5b53fccd..99266a10a 100644 --- a/__unported__/account_payment_sale/__openerp__.py +++ b/account_payment_sale/__openerp__.py @@ -37,19 +37,19 @@ customer invoice. This module is similar to the *sale_payment* module ; the main difference is that it doesn't depend on the *account_payment_extension* module (it's not the only module to conflict with *account_payment_extension* ; all the SEPA -modules in the banking addons conflict with *account_payment_extension*, cf -banking-addons-70/account_banking_payment_export/__openerp__.py). - -Please contact Alexis de Lattre from Akretion -for any help or question about this module. +modules in the banking addons conflict with *account_payment_extension*. """, 'author': 'Akretion', 'website': 'http://www.akretion.com', - 'depends': ['sale', 'account_payment_partner'], + 'contributors': ['Pedro M. Baeza '], + 'depends': [ + 'sale', + 'stock_account', + 'account_payment_partner' + ], 'conflicts': ['sale_payment'], 'data': [ - 'view/sale.xml', + 'views/sale_order_view.xml', ], - 'installable': False, - 'active': False, + 'installable': True, } diff --git a/__unported__/account_payment_sale/i18n/account_payment_sale.pot b/account_payment_sale/i18n/account_payment_sale.pot similarity index 100% rename from __unported__/account_payment_sale/i18n/account_payment_sale.pot rename to account_payment_sale/i18n/account_payment_sale.pot diff --git a/__unported__/account_payment_sale/i18n/nl.po b/account_payment_sale/i18n/nl.po similarity index 100% rename from __unported__/account_payment_sale/i18n/nl.po rename to account_payment_sale/i18n/nl.po diff --git a/__unported__/account_payment_sale/model/__init__.py b/account_payment_sale/model/__init__.py similarity index 100% rename from __unported__/account_payment_sale/model/__init__.py rename to account_payment_sale/model/__init__.py diff --git a/__unported__/account_payment_sale/model/sale.py b/account_payment_sale/model/sale.py similarity index 100% rename from __unported__/account_payment_sale/model/sale.py rename to account_payment_sale/model/sale.py diff --git a/account_payment_sale/models/__init__.py b/account_payment_sale/models/__init__.py new file mode 100644 index 000000000..9de52dd65 --- /dev/null +++ b/account_payment_sale/models/__init__.py @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Sale module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import sale_order +from . import stock_picking diff --git a/account_payment_sale/models/sale_order.py b/account_payment_sale/models/sale_order.py new file mode 100644 index 000000000..cd93e56d7 --- /dev/null +++ b/account_payment_sale/models/sale_order.py @@ -0,0 +1,50 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Sale module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + payment_mode_id = fields.Many2one( + 'payment.mode', string='Payment Mode', + domain="[('payment_order_type', '=', 'debit')]") + + @api.multi + def onchange_partner_id(self, partner_id): + res = super(SaleOrder, self).onchange_partner_id(partner_id) + if partner_id: + partner = self.env['res.partner'].browse(partner_id) + res['value']['payment_mode_id'] = partner.customer_payment_mode.id + else: + res['value']['payment_mode_id'] = False + return res + + @api.model + def _prepare_invoice(self, order, lines): + """Copy bank partner from sale order to invoice""" + vals = super(SaleOrder, self)._prepare_invoice(order, lines) + vals['payment_mode_id'] = order.payment_mode_id.id, + vals['partner_bank_id'] = (order.payment_mode_id and + order.payment_mode_id.bank_id.id) + return vals diff --git a/account_payment_sale/models/stock_picking.py b/account_payment_sale/models/stock_picking.py new file mode 100644 index 000000000..f9d48f688 --- /dev/null +++ b/account_payment_sale/models/stock_picking.py @@ -0,0 +1,40 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Account Payment Purchase module for OpenERP +# Copyright (C) 2014 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp import models, api + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + @api.model + def _create_invoice_from_picking(self, picking, vals): + if picking: + # Search if this picking comes from a sale order + sale_order_obj = self.env['sale.order'] + sale_order = sale_order_obj.search( + [('picking_ids', 'in', picking.id)], limit=1) + if sale_order: + vals['partner_bank_id'] = sale_order.payment_mode_id.bank_id.id + vals['payment_mode_id'] = sale_order.payment_mode_id.id + return super(StockPicking, self)._create_invoice_from_picking(picking, + vals) diff --git a/__unported__/account_payment_sale/view/sale.xml b/account_payment_sale/view/sale.xml similarity index 100% rename from __unported__/account_payment_sale/view/sale.xml rename to account_payment_sale/view/sale.xml diff --git a/account_payment_sale/views/sale_order_view.xml b/account_payment_sale/views/sale_order_view.xml new file mode 100644 index 000000000..016598e09 --- /dev/null +++ b/account_payment_sale/views/sale_order_view.xml @@ -0,0 +1,24 @@ + + + + + + + + + account_payment_sale.sale_order.form + sale.order + + + + + + + + + +