[MIG] account_banking_pain_base: Migration to 8.0

This commit is contained in:
Pedro M. Baeza
2014-09-10 12:19:20 +02:00
committed by Pedro M. Baeza
parent bdc1cbff53
commit 7c655e0092
13 changed files with 321 additions and 136 deletions

View File

@@ -20,7 +20,4 @@
#
##############################################################################
from . import payment_line
from . import payment_mode
from . import company
from . import banking_export_pain
from . import models

View File

@@ -22,19 +22,23 @@
{
'name': 'Account Banking PAIN Base Module',
'summary': 'Base module for PAIN file generation',
'version': '0.1',
'version': '8.0.0.2.0',
'license': 'AGPL-3',
'author': 'Akretion, Noviat',
'website': 'http://openerp-community-association.org/',
'author': "Akretion, "
"Noviat, "
"Serv. Tecnol. Avanzados - Pedro M. Baeza, "
"Odoo Community Association (OCA)",
'website': 'https://github.com/OCA/bank-payment',
'contributors': ['Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>'],
'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 +47,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': True,
}

View File

@@ -1,13 +1,13 @@
# Translation of OpenERP Server.
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_banking_pain_base
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-23 21:26+0000\n"
"PO-Revision-Date: 2013-12-23 21:26+0000\n"
"POT-Creation-Date: 2014-10-31 22:52+0000\n"
"PO-Revision-Date: 2014-10-31 22:52+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -15,20 +15,80 @@ msgstr ""
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:74
#, python-format
msgid "Cannot compute the '%s' of the Payment Line with reference '%s'."
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:80
#, python-format
msgid "Cannot compute the '%s'."
msgstr ""
#. module: account_banking_pain_base
#: model:ir.model,name:account_banking_pain_base.model_res_company
msgid "Companies"
msgstr ""
#. module: account_banking_pain_base
#: field:payment.mode,convert_to_ascii:0
msgid "Convert to ASCII"
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:47
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:73
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:79
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:89
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:124
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:303
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:385
#, python-format
msgid "Error:"
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:83
#, python-format
msgid "Field type error:"
msgstr ""
#. module: account_banking_pain_base
#: selection:payment.line,priority:0
msgid "High"
msgstr ""
#. module: account_banking_pain_base
#: field:banking.export.pain,id:0
msgid "ID"
msgstr ""
#. module: account_banking_pain_base
#: help:payment.mode,convert_to_ascii:0
msgid "If active, Odoo will convert each accented caracter to the corresponding unaccented caracter, so that only ASCII caracters are used in the generated PAIN file."
msgstr ""
#. module: account_banking_pain_base
#: field:res.company,initiating_party_issuer:0
msgid "Initiating Party Issuer"
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:122
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:386
#, python-format
msgid "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"
msgid "Missing 'Structured Communication Type' on payment line with reference '%s'."
msgstr ""
#. module: account_banking_pain_base
#: field:payment.line,priority:0
msgid "Priority"
#: selection:payment.line,priority:0
msgid "Normal"
msgstr ""
#. module: account_banking_pain_base
#: view:res.company:account_banking_pain_base.view_company_form
msgid "Payment Initiation"
msgstr ""
#. module: account_banking_pain_base
@@ -42,65 +102,8 @@ msgid "Payment Mode"
msgstr ""
#. module: account_banking_pain_base
#: help:res.company,initiating_party_issuer:0
msgid "This will be used as the 'Initiating Party Issuer' in the PAIN files generated by OpenERP."
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:351
#, python-format
msgid "Missing 'Structured Communication Type' on payment line with reference '%s'."
msgstr ""
#. module: account_banking_pain_base
#: selection:payment.line,priority:0
msgid "Normal"
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:70
#, python-format
msgid "Cannot compute the '%s' of the Payment Line with reference '%s'."
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:77
#, python-format
msgid "Cannot compute the '%s'."
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:81
#, python-format
msgid "The type of the field '%s' is %s. It should be a string or unicode."
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:47
#: code:addons/account_banking_pain_base/banking_export_pain.py:69
#: code:addons/account_banking_pain_base/banking_export_pain.py:76
#: code:addons/account_banking_pain_base/banking_export_pain.py:86
#: code:addons/account_banking_pain_base/banking_export_pain.py:121
#: code:addons/account_banking_pain_base/banking_export_pain.py:350
#, python-format
msgid "Error:"
msgstr ""
#. module: account_banking_pain_base
#: model:ir.model,name:account_banking_pain_base.model_res_company
msgid "Companies"
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:47
#, python-format
msgid "This IBAN is not valid : %s"
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:80
#, python-format
msgid "Field type error:"
#: field:payment.line,priority:0
msgid "Priority"
msgstr ""
#. module: account_banking_pain_base
@@ -109,19 +112,33 @@ msgid "Structured Communication Type"
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/banking_export_pain.py:87
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:90
#, python-format
msgid "The '%s' is empty or 0. It should have a non-null value."
msgstr ""
#. module: account_banking_pain_base
#: model:ir.model,name:account_banking_pain_base.model_banking_export_pain
msgid "banking.export.pain"
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:304
#, python-format
msgid "The bank account with IBAN '%s' of partner '%s' must have an associated BIC because it is a cross-border SEPA operation."
msgstr ""
#. module: account_banking_pain_base
#: help:payment.mode,convert_to_ascii:0
msgid "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."
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:125
#, python-format
msgid "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"
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:84
#, python-format
msgid "The type of the field '%s' is %s. It should be a string or unicode."
msgstr ""
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:47
#, python-format
msgid "This IBAN is not valid : %s"
msgstr ""
#. module: account_banking_pain_base
@@ -130,17 +147,7 @@ msgid "This field will be used as the 'Instruction Priority' in the generated PA
msgstr ""
#. module: account_banking_pain_base
#: view:res.company:0
msgid "Payment Initiation"
msgstr ""
#. module: account_banking_pain_base
#: selection:payment.line,priority:0
msgid "High"
msgstr ""
#. module: account_banking_pain_base
#: field:payment.mode,convert_to_ascii:0
msgid "Convert to ASCII"
#: help:res.company,initiating_party_issuer:0
msgid "This will be used as the 'Initiating Party Issuer' in the PAIN files generated by Odoo."
msgstr ""

View File

@@ -0,0 +1,153 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_banking_pain_base
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-10-31 22:52+0000\n"
"PO-Revision-Date: 2014-10-31 22:52+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:74
#, python-format
msgid "Cannot compute the '%s' of the Payment Line with reference '%s'."
msgstr "No se puede procesar el campo '%s' de la línea de pago con referencia '%s'."
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:80
#, python-format
msgid "Cannot compute the '%s'."
msgstr "No se puede procesar el campo '%s'."
#. module: account_banking_pain_base
#: model:ir.model,name:account_banking_pain_base.model_res_company
msgid "Companies"
msgstr "Compañías"
#. module: account_banking_pain_base
#: field:payment.mode,convert_to_ascii:0
msgid "Convert to ASCII"
msgstr "Convertir a ASCII"
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:47
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:73
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:79
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:89
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:124
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:303
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:385
#, python-format
msgid "Error:"
msgstr "Error:"
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:83
#, python-format
msgid "Field type error:"
msgstr ""
#. module: account_banking_pain_base
#: selection:payment.line,priority:0
msgid "High"
msgstr "Alta"
#. module: account_banking_pain_base
#: field:banking.export.pain,id:0
msgid "ID"
msgstr "ID"
#. module: account_banking_pain_base
#: help:payment.mode,convert_to_ascii:0
msgid "If active, Odoo will convert each accented caracter to the corresponding unaccented caracter, so that only ASCII caracters are used in the generated PAIN file."
msgstr "Si está marcado, Odoo convertirá cada carácter acentuado en el correspondiente carácter no acentuado, para que sólo se usen caracteres ASCII en el archivo PAIN generado."
#. module: account_banking_pain_base
#: field:res.company,initiating_party_issuer:0
msgid "Initiating Party Issuer"
msgstr "Emisor de la transacción"
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:386
#, python-format
msgid "Missing 'Structured Communication Type' on payment line with reference '%s'."
msgstr "Falta el campo 'Tipo de comunicación estructurada' en la línea de pago con referencia '%s'."
#. module: account_banking_pain_base
#: selection:payment.line,priority:0
msgid "Normal"
msgstr "Normal"
#. module: account_banking_pain_base
#: view:res.company:account_banking_pain_base.view_company_form
msgid "Payment Initiation"
msgstr "Iniciación del pago"
#. module: account_banking_pain_base
#: model:ir.model,name:account_banking_pain_base.model_payment_line
msgid "Payment Line"
msgstr "Línea de pago"
#. module: account_banking_pain_base
#: model:ir.model,name:account_banking_pain_base.model_payment_mode
msgid "Payment Mode"
msgstr "Modo de pago"
#. module: account_banking_pain_base
#: field:payment.line,priority:0
msgid "Priority"
msgstr "Prioridad"
#. module: account_banking_pain_base
#: field:payment.line,struct_communication_type:0
msgid "Structured Communication Type"
msgstr "Tipo de comunicación estructurada"
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:90
#, python-format
msgid "The '%s' is empty or 0. It should have a non-null value."
msgstr "'%s' está vacío o es 0. Debería tener un valor no nulo."
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:304
#, python-format
msgid "The bank account with IBAN '%s' of partner '%s' must have an associated BIC because it is a cross-border SEPA operation."
msgstr "La cuenta bancaria con IBAN '%s' de la empresa '%s' debe tener un BIC asociado, porque es una operación SEPA transfronteriza."
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:125
#, python-format
msgid "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"
msgstr "El archivo XML generado no se puede validar contra la definición de esquema XML oficial. El archivo XML generado el error completo se ha escrito en los registros del servidor. Aquí está el error, que le puede dar una idea de la causa del problema : %s"
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:84
#, python-format
msgid "The type of the field '%s' is %s. It should be a string or unicode."
msgstr "El tipo del campo '%s' es %s. Debería ser una cadena o unicode."
#. module: account_banking_pain_base
#: code:addons/account_banking_pain_base/models/banking_export_pain.py:47
#, python-format
msgid "This IBAN is not valid : %s"
msgstr "Este IBAN no es válido: %s"
#. module: account_banking_pain_base
#: help:payment.line,priority:0
msgid "This field will be used as the 'Instruction Priority' in the generated PAIN file."
msgstr "Este campo se usará como 'Prioridad de instrucción' en el archivo PAIN generado."
#. module: account_banking_pain_base
#: help:res.company,initiating_party_issuer:0
msgid "This will be used as the 'Initiating Party Issuer' in the PAIN files generated by Odoo."
msgstr "Este campo se usará como 'Emisor de la transacción' en los archivos PAIN generados por Odoo."

View File

@@ -0,0 +1,26 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# PAIN Base module for OpenERP
# Copyright (C) 2013 Akretion (http://www.akretion.com)
# @author: Alexis de Lattre <alexis.delattre@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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import payment_line
from . import payment_mode
from . import res_company
from . import banking_export_pain

View File

@@ -24,21 +24,26 @@ 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
try:
from unidecode import unidecode
except ImportError:
unidecode = None
logger = logging.getLogger(__name__)
class banking_export_pain(orm.AbstractModel):
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'''
"""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(' ', '')
@@ -46,10 +51,9 @@ class banking_export_pain(orm.AbstractModel):
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 !'''
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'
@@ -163,7 +167,7 @@ class banking_export_pain(orm.AbstractModel):
'res_model': self._name,
'res_id': ids[0],
'target': 'new',
}
}
return action
def generate_group_header_block(
@@ -210,6 +214,8 @@ class banking_export_pain(orm.AbstractModel):
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 = \
@@ -282,8 +288,8 @@ class banking_export_pain(orm.AbstractModel):
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'''
"""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(
@@ -323,8 +329,8 @@ class banking_export_pain(orm.AbstractModel):
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'''
"""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'
@@ -384,7 +390,7 @@ class banking_export_pain(orm.AbstractModel):
_('Error:'),
_("Missing 'Structured Communication Type' on payment "
"line with reference '%s'.")
% (line.name))
% line.name)
remittance_info_structured_2_100 = etree.SubElement(
remittance_info_2_91, 'Strd')
creditor_ref_information_2_120 = etree.SubElement(
@@ -424,9 +430,8 @@ class banking_export_pain(orm.AbstractModel):
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_id = etree.SubElement(parent_node, 'Id')
csi_privateid = 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(

View File

@@ -23,19 +23,18 @@
from openerp.osv import orm, fields
class payment_line(orm.Model):
class PaymentLine(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',
'priority': fields.selection(
[('NORM', 'Normal'),
('HIGH', 'High')], 'Priority',
help="This field will be used as the 'Instruction Priority' in "
"the generated PAIN file."),
"the generated PAIN file."),
# Update size from 64 to 140, because PAIN allows 140 caracters
'communication': fields.char(
'Communication', size=140, required=True,

View File

@@ -29,7 +29,7 @@ class payment_mode(orm.Model):
_columns = {
'convert_to_ascii': fields.boolean(
'Convert to ASCII',
help="If active, OpenERP will convert each accented caracter to "
help="If active, Odoo will convert each accented caracter to "
"the corresponding unaccented caracter, so that only ASCII "
"caracters are used in the generated PAIN file."),
}

View File

@@ -25,39 +25,37 @@
from openerp.osv import orm, fields
class res_company(orm.Model):
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."),
"PAIN files generated by Odoo."),
}
def _get_initiating_party_identifier(
self, cr, uid, company_id, context=None):
'''The code here may be different from one country to another.
"""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'''
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:
party_identifier = company.sepa_creditor_identifier
if not party_identifier and 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
"""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'''
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB