diff --git a/account_banking_pain_base/banking_export_pain.py b/account_banking_pain_base/banking_export_pain.py deleted file mode 100644 index 279dc5f5a..000000000 --- a/account_banking_pain_base/banking_export_pain.py +++ /dev/null @@ -1,439 +0,0 @@ -# -*- 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 banking_export_pain(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'] - 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/account_banking_pain_base/company.py b/account_banking_pain_base/company.py deleted file mode 100644 index 222786c27..000000000 --- a/account_banking_pain_base/company.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- 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 res_company(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/company_view.xml b/account_banking_pain_base/company_view.xml deleted file mode 100644 index a98d9b641..000000000 --- a/account_banking_pain_base/company_view.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - pain.group.on.res.company.form - res.company - - - - - - - - - - - - diff --git a/account_banking_pain_base/payment_line.py b/account_banking_pain_base/payment_line.py deleted file mode 100644 index 0dffbcf42..000000000 --- a/account_banking_pain_base/payment_line.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- 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/account_banking_pain_base/payment_line_view.xml b/account_banking_pain_base/payment_line_view.xml deleted file mode 100644 index f92b1bbf5..000000000 --- a/account_banking_pain_base/payment_line_view.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - pain.base.payment.line.form - payment.line - - - - - - - - - - - - - - pain.base.payment.line.inside.order.form - payment.order - - - - - - - - - - - - - - diff --git a/account_banking_pain_base/payment_mode.py b/account_banking_pain_base/payment_mode.py deleted file mode 100644 index 540d01b67..000000000 --- a/account_banking_pain_base/payment_mode.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- 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/account_banking_pain_base/payment_mode_view.xml b/account_banking_pain_base/payment_mode_view.xml deleted file mode 100644 index 2deb24999..000000000 --- a/account_banking_pain_base/payment_mode_view.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - add.convert_to_ascii.in.payment.mode.form - payment.mode - - - - - - - - - - diff --git a/account_banking_sepa_credit_transfer/account_banking_sepa.py b/account_banking_sepa_credit_transfer/account_banking_sepa.py deleted file mode 100644 index 99d5b022b..000000000 --- a/account_banking_sepa_credit_transfer/account_banking_sepa.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- 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.osv import orm, fields -from openerp.addons.decimal_precision import decimal_precision as dp -from unidecode import unidecode - - -class banking_export_sepa(orm.Model): - '''SEPA export''' - _name = 'banking.export.sepa' - _description = __doc__ - _rec_name = 'filename' - - def _generate_filename(self, cr, uid, ids, name, arg, context=None): - res = {} - for sepa_file in self.browse(cr, uid, ids, context=context): - ref = sepa_file.payment_order_ids[0].reference - if ref: - label = unidecode(ref.replace('/', '-')) - else: - label = 'error' - res[sepa_file.id] = 'sct_%s.xml' % label - return res - - _columns = { - 'payment_order_ids': fields.many2many( - 'payment.order', - 'account_payment_order_sepa_rel', - 'banking_export_sepa_id', 'account_order_id', - 'Payment Orders', - readonly=True), - 'nb_transactions': fields.integer( - 'Number of Transactions', readonly=True), - 'total_amount': fields.float( - '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'), - ], '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.function( - _generate_filename, type='char', size=256, string='Filename', - readonly=True), - 'state': fields.selection([ - ('draft', 'Draft'), - ('sent', 'Sent'), - ], 'State', readonly=True), - } - - _defaults = { - 'state': 'draft', - } diff --git a/account_banking_sepa_credit_transfer/account_banking_sepa_view.xml b/account_banking_sepa_credit_transfer/account_banking_sepa_view.xml deleted file mode 100644 index a5896c757..000000000 --- a/account_banking_sepa_credit_transfer/account_banking_sepa_view.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - 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/account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml b/account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml deleted file mode 100644 index 77abf1b34..000000000 --- a/account_banking_sepa_credit_transfer/sepa_credit_transfer_demo.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - SEPA Credit Transfer La Banque Postale - - - - - - - - diff --git a/account_banking_sepa_direct_debit/account_banking_sdd.py b/account_banking_sepa_direct_debit/account_banking_sdd.py deleted file mode 100644 index 87e50111b..000000000 --- a/account_banking_sepa_direct_debit/account_banking_sdd.py +++ /dev/null @@ -1,440 +0,0 @@ -# -*- 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 openerp.addons.decimal_precision import decimal_precision as dp -from unidecode import unidecode -from datetime import datetime -from dateutil.relativedelta import relativedelta -import logging - -NUMBER_OF_UNUSED_MONTHS_BEFORE_EXPIRY = 36 - -logger = logging.getLogger(__name__) - - -class banking_export_sdd(orm.Model): - '''SEPA Direct Debit export''' - _name = 'banking.export.sdd' - _description = __doc__ - _rec_name = 'filename' - - def _generate_filename(self, cr, uid, ids, name, arg, context=None): - res = {} - for sepa_file in self.browse(cr, uid, ids, context=context): - ref = sepa_file.payment_order_ids[0].reference - if ref: - label = unidecode(ref.replace('/', '-')) - else: - label = 'error' - res[sepa_file.id] = 'sdd_%s.xml' % label - return res - - _columns = { - 'payment_order_ids': fields.many2many( - 'payment.order', - 'account_payment_order_sdd_rel', - 'banking_export_sepa_id', 'account_order_id', - 'Payment Orders', - readonly=True), - 'nb_transactions': fields.integer( - 'Number of Transactions', readonly=True), - 'total_amount': fields.float( - '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('Generation Date', readonly=True), - 'file': fields.binary('SEPA File', readonly=True), - 'filename': fields.function( - _generate_filename, type='char', size=256, - string='Filename', readonly=True, store=True), - 'state': fields.selection([ - ('draft', 'Draft'), - ('sent', 'Sent'), - ], 'State', readonly=True), - } - - _defaults = { - 'state': 'draft', - } - - -class sdd_mandate(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."), - } - - _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, - } - - _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(sdd_mandate, 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 - - -class res_partner_bank(orm.Model): - _inherit = 'res.partner.bank' - - _columns = { - 'sdd_mandate_ids': fields.one2many( - 'sdd.mandate', 'partner_bank_id', 'SEPA Direct Debit Mandates'), - } - - -class payment_line(orm.Model): - _inherit = 'payment.line' - - _columns = { - 'sdd_mandate_id': fields.many2one( - 'sdd.mandate', 'SEPA Direct Debit Mandate', - domain=[('state', '=', 'valid')]), - } - - def create(self, cr, uid, vals, context=None): - '''If the customer invoice has a mandate, take it - otherwise, take the first valid mandate of the bank account''' - if context is None: - context = {} - if not vals: - vals = {} - partner_bank_id = vals.get('bank_id') - move_line_id = vals.get('move_line_id') - if (context.get('default_payment_order_type') == 'debit' - and 'sdd_mandate_id' not in vals): - if move_line_id: - line = self.pool['account.move.line'].browse( - cr, uid, move_line_id, context=context) - 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: - mandate_ids = self.pool['sdd.mandate'].search(cr, uid, [ - ('partner_bank_id', '=', partner_bank_id), - ('state', '=', 'valid'), - ], context=context) - if mandate_ids: - vals['sdd_mandate_id'] = mandate_ids[0] - return super(payment_line, self).create(cr, uid, vals, context=context) - - def _check_mandate_bank_link(self, cr, uid, ids): - for payline in self.browse(cr, uid, ids): - if (payline.sdd_mandate_id and payline.bank_id - and payline.sdd_mandate_id.partner_bank_id.id != - payline.bank_id.id): - raise orm.except_orm( - _('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').") % ( - payline.name, - self.pool['res.partner.bank'].name_get( - cr, uid, [payline.bank_id.id])[0][1], - payline.sdd_mandate_id.unique_mandate_reference, - self.pool['res.partner.bank'].name_get( - cr, uid, - [payline.sdd_mandate_id.partner_bank_id.id])[0][1], - )) - return True - - _constraints = [ - (_check_mandate_bank_link, 'Error msg in raise', - ['sdd_mandate_id', 'bank_id']), - ] - - -class account_invoice(orm.Model): - _inherit = 'account.invoice' - - _columns = { - 'sdd_mandate_id': fields.many2one( - 'sdd.mandate', 'SEPA Direct Debit Mandate', - domain=[('state', '=', 'valid')], readonly=True, - states={'draft': [('readonly', False)]}) - } diff --git a/account_banking_sepa_direct_debit/account_banking_sdd_view.xml b/account_banking_sepa_direct_debit/account_banking_sdd_view.xml deleted file mode 100644 index f74b60353..000000000 --- a/account_banking_sepa_direct_debit/account_banking_sdd_view.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - 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/account_invoice_view.xml b/account_banking_sepa_direct_debit/account_invoice_view.xml deleted file mode 100644 index 2ca480e54..000000000 --- a/account_banking_sepa_direct_debit/account_invoice_view.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - add.sdd.mandate.on.customer.invoice.form - account.invoice - - - - - - - - - - diff --git a/account_banking_sepa_direct_debit/account_payment_view.xml b/account_banking_sepa_direct_debit/account_payment_view.xml deleted file mode 100644 index 74098c44e..000000000 --- a/account_banking_sepa_direct_debit/account_payment_view.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - sdd.payment.order.form - payment.order - - - - - - - - - - - - - - diff --git a/account_banking_sepa_direct_debit/company.py b/account_banking_sepa_direct_debit/company.py deleted file mode 100644 index 6d54ba8e6..000000000 --- a/account_banking_sepa_direct_debit/company.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- 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 -import logging - -logger = logging.getLogger(__name__) - - -class res_company(orm.Model): - _inherit = 'res.company' - - _columns = { - 'sepa_creditor_identifier': fields.char( - '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( - 'Original Creditor Identifier', size=70), - } - - def is_sepa_creditor_identifier_valid( - self, cr, uid, sepa_creditor_identifier, context=None): - """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 = str(sepa_creditor_identifier) - except: - logger.warning( - "SEPA Creditor ID should contain only ASCII caracters.") - return False - sci = sci_str.lower() - 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) - if int(sci[2:4]) == (98 - (int(after_replacement) % 97)): - return True - else: - return False - - def _check_sepa_creditor_identifier(self, cr, uid, ids): - for company in self.browse(cr, uid, ids): - if company.sepa_creditor_identifier: - if not self.is_sepa_creditor_identifier_valid( - cr, uid, company.sepa_creditor_identifier): - return False - return True - - _constraints = [ - (_check_sepa_creditor_identifier, - "Invalid SEPA Creditor Identifier.", - ['sepa_creditor_identifier']), - ] diff --git a/account_banking_sepa_direct_debit/company_view.xml b/account_banking_sepa_direct_debit/company_view.xml deleted file mode 100644 index e4c9e0b93..000000000 --- a/account_banking_sepa_direct_debit/company_view.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - sepa_direct_debit.res.company.form - res.company - - - - - - - - - - - diff --git a/account_banking_sepa_direct_debit/mandate_expire_cron.xml b/account_banking_sepa_direct_debit/mandate_expire_cron.xml deleted file mode 100644 index 4cb0693d2..000000000 --- a/account_banking_sepa_direct_debit/mandate_expire_cron.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - Set SEPA Direct Debit Mandates to Expired - - - 1 - days - -1 - - - - - - - - diff --git a/account_banking_sepa_direct_debit/res_partner_bank_view.xml b/account_banking_sepa_direct_debit/res_partner_bank_view.xml deleted file mode 100644 index 0b32e9f1c..000000000 --- a/account_banking_sepa_direct_debit/res_partner_bank_view.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - 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/sdd_mandate_view.xml b/account_banking_sepa_direct_debit/sdd_mandate_view.xml deleted file mode 100644 index bd1dd6e79..000000000 --- a/account_banking_sepa_direct_debit/sdd_mandate_view.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - 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/account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml b/account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml deleted file mode 100644 index 220261088..000000000 --- a/account_banking_sepa_direct_debit/sepa_direct_debit_demo.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - SEPA Direct Debit La Banque Postale - - - - - - - - FR78ZZZ424242 - - - - - recurrent - first - 2014-02-01 - valid - - - - diff --git a/account_payment_partner/__openerp__.py b/account_payment_partner/__openerp__.py index 3f3a51f3f..b499d6028 100644 --- a/account_payment_partner/__openerp__.py +++ b/account_payment_partner/__openerp__.py @@ -51,3 +51,62 @@ be filtered per Payment Mode. 'demo': ['demo/partner_demo.xml'], 'installable': True, } + +from openerp import models, fields, api, exceptions +from datetime import datetime + + +class CrmLead(models.Model): + _inherit = 'crm.lead' + + @api.one + @api.constrains('state', 'code') + def _check_code(self): + if self.state == 'won': + if not self.code: + raise exceptions.Warning('Debe poner un código cuando la etapa se pasa a ganado.') + + @api.constrains('state', 'code') + def _check_code(self): + for record in self: + if record.state == 'won': + if not record.code: + raise exceptions.Warning('Debe poner un código cuando la etapa se pasa a ganado.') + + def do_something(self, vals): + pass + + def create(self, vals): + # Complementar valores del create + rec_id = super(CrmLead, self).create(vals) + # Crear registros accesorios + analytic_acc_obj = self.env['account.analytic.account'] + analytic_acc_obj.create({'name': vals['name'], + 'type': 'project', + 'date': datetime.now(), + 'project_id': rec_id}) + analytic_accs = analytic_acc_obj.search([('type', '=', 'project')], + order='partner_id', limit=1) + analytic_accs.write({'partner_id': 1}) + return rec_id + + def copy(self, default): + default['name'] = self.name + " (copia)" + return super(CrmLead, self).copy(default) + + def search(self, domain): + return {1: {''}, 2: {} } + + @api.one + def unlink(self): + if self.state in ('to_invoice', 'done'): + raise exceptions.Warning('No se puede borrar un pedido confirmado.') + super(CrmLead, self).unlink() + return True + + def write(self, vals): + if vals.get('state') == 'won': + for record in self: + if not record.code and not vals.get('code'): + raise exceptions.Warning('Debe poner un código cuando la etapa se pasa a ganado.') + return super(CrmLead, self).write(vals) diff --git a/account_payment_partner/models/account_invoice.py b/account_payment_partner/models/account_invoice.py index cbbd4b5b9..1c2428eb6 100644 --- a/account_payment_partner/models/account_invoice.py +++ b/account_payment_partner/models/account_invoice.py @@ -26,7 +26,10 @@ from openerp import models, fields, api class AccountInvoice(models.Model): _inherit = 'account.invoice' - payment_mode_id = fields.Many2one('payment.mode', string="Payment Mode") + type = fields.Selection('out', 'in') + + payment_mode_id = fields.Many2one('payment.mode', string="Payment Mode", + domain="[('type', '=', type)]") @api.multi def onchange_partner_id( diff --git a/account_payment_purchase/model/__init__.py b/account_payment_purchase/model/__init__.py deleted file mode 100644 index fe39c6366..000000000 --- a/account_payment_purchase/model/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- 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 -from . import stock diff --git a/account_payment_purchase/model/purchase.py b/account_payment_purchase/model/purchase.py deleted file mode 100644 index f397a6a61..000000000 --- a/account_payment_purchase/model/purchase.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- 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.osv import orm, fields - - -class purchase_order(orm.Model): - _inherit = "purchase.order" - - _columns = { - 'supplier_partner_bank_id': fields.many2one( - 'res.partner.bank', 'Supplier Bank Account', - 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', 'Payment Mode'), - } - - def _get_default_supplier_partner_bank( - self, cr, uid, partner, context=None): - '''This function is designed to be inherited''' - if partner.bank_ids: - return partner.bank_ids[0].id - else: - return False - - def onchange_partner_id(self, cr, uid, ids, partner_id): - res = super(purchase_order, self).onchange_partner_id( - cr, uid, ids, partner_id) - if partner_id: - partner = self.pool['res.partner'].browse( - cr, uid, partner_id) - res['value'].update({ - 'supplier_partner_bank_id': - self._get_default_supplier_partner_bank( - cr, uid, partner), - 'payment_mode_id': - partner.supplier_payment_mode.id or False, - }) - else: - res['value'].update({ - 'supplier_partner_bank_id': False, - 'payment_mode_id': False, - }) - return res - - def action_invoice_create(self, cr, uid, ids, context=None): - """Copy bank partner + payment type from PO to invoice""" - # as of OpenERP 7.0, there is no _prepare function for - # the invoice (the _prepare function only exists for invoice lines) - res = super(purchase_order, self).action_invoice_create( - cr, uid, ids, context=context) - for order in self.browse(cr, uid, ids, context=context): - for invoice in order.invoice_ids: - if invoice.state == 'draft': - invoice.write({ - 'partner_bank_id': - order.supplier_partner_bank_id.id or False, - 'payment_mode_id': - order.payment_mode_id.id or False, - }, context=context) - return res diff --git a/account_payment_purchase/model/stock.py b/account_payment_purchase/model/stock.py deleted file mode 100644 index e2f83663b..000000000 --- a/account_payment_purchase/model/stock.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- 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.osv import orm - - -class stock_picking(orm.Model): - _inherit = "stock.picking" - - def _prepare_invoice( - self, cr, uid, picking, partner, inv_type, journal_id, - context=None): - """Copy bank partner and payment type from PO to invoice""" - invoice_vals = super(stock_picking, self)._prepare_invoice( - cr, uid, picking, partner, inv_type, journal_id, context=context) - if picking.purchase_id: - invoice_vals.update({ - 'partner_bank_id': - picking.purchase_id.supplier_partner_bank.id or False, - 'payment_mode_type': - picking.purchase_id.payment_mode_type.id or False, - }) - return invoice_vals diff --git a/account_payment_sale/models/sale_order.py b/account_payment_sale/models/sale_order.py index fa30ccf2d..0906beae0 100644 --- a/account_payment_sale/models/sale_order.py +++ b/account_payment_sale/models/sale_order.py @@ -46,6 +46,5 @@ class SaleOrder(models.Model): vals = super(SaleOrder, self)._prepare_invoice(order, lines) if order.payment_mode_id: 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) + vals['partner_bank_id'] = order.payment_mode_id.bank_id.id return vals