[IMP] account_bank_statement_import_paypal: better wizard

This commit is contained in:
Alexey Pelykh
2020-04-08 09:00:59 +02:00
parent 273f33a5ca
commit 5703ac3ef7
8 changed files with 392 additions and 79 deletions

View File

@@ -17,6 +17,8 @@
'installable': True,
'depends': [
'account_bank_statement_import',
'multi_step_wizard',
'web_widget_dropdown_dynamic',
],
'external_dependencies': {
'python': [

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 Tecnativa - Vicent Cubells
Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo noupdate="1">
@@ -51,4 +51,49 @@
<field name="note_column">Note</field>
</record>
<record id="paypal_statement_map_es" model="account.bank.statement.import.paypal.mapping">
<field name="name">PayPal Statement (ES)</field>
<field name="float_thousands_sep">dot</field>
<field name="float_decimal_sep">comma</field>
<field name="date_format">%d/%m/%Y</field>
<field name="time_format">%H:%M:%S</field>
<field name="date_column">Fecha</field>
<field name="time_column">Hora</field>
<field name="tz_column">Zona horaria</field>
<field name="name_column">Nombre</field>
<field name="currency_column">Divisa</field>
<field name="gross_column">Bruto</field>
<field name="fee_column">Comisión</field>
<field name="balance_column">Saldo</field>
<field name="transaction_id_column">Id. de transacción</field>
<field name="description_column">Descripción</field>
<field name="from_email_address_column">Correo electrónico del remitente</field>
<field name="invoice_id_column">Id. de factura</field>
<field name="bank_name_column">Nombre del banco</field>
<field name="bank_account_column">Cuenta bancaria</field>
</record>
<record id="paypal_activity_map_es" model="account.bank.statement.import.paypal.mapping">
<field name="name">PayPal Activity (ES)</field>
<field name="float_thousands_sep">dot</field>
<field name="float_decimal_sep">comma</field>
<field name="date_format">%d/%m/%Y</field>
<field name="time_format">%H:%M:%S</field>
<field name="date_column">Fecha</field>
<field name="time_column">Hora</field>
<field name="tz_column">Zona horaria</field>
<field name="name_column">Nombre</field>
<field name="currency_column">Divisa</field>
<field name="gross_column">Bruto</field>
<field name="fee_column">Tarifa</field>
<field name="balance_column">Saldo</field>
<field name="transaction_id_column">Id. de transacción</field>
<field name="type_column">Tipo</field>
<field name="from_email_address_column">Correo electrónico del remitente</field>
<field name="to_email_address_column">Correo electrónico del destinatario</field>
<field name="invoice_id_column">Número de factura</field>
<field name="subject_column">Asunto</field>
<field name="note_column">Nota</field>
</record>
</odoo>

View File

@@ -9,12 +9,12 @@
"9/27/2018","21:33:27","America/Los_Angeles","General Currency Conversion","EUR","9,648.13","0.00","9,648.13","0.75","TID8","","","","","0.00","0.00","","TID7"
"9/4/2018","20:44:10","America/Los_Angeles","Express Checkout Payment","USD","1,309.80","-48.76","1,261.04","1,261.93","TID9","paypal@partner1.com","Partner 1","","","0.00","0.00","361",""
"9/4/2018","21:15:11","America/Los_Angeles","General Currency Conversion","USD","-1,261.00","0.00","-1,261.00","0.93","TID10","","","","","0.00","0.00","","TID1"
"9/10/2018","17:48:19","America/Los_Angeles","Express Checkout Payment","USD","3,840.60","-142.40","3,698.20","3,699.13","TID11","paypa@partner2.com","Partner 2","","","0.00","0.00","362",""
"9/10/2018","17:48:19","America/Los_Angeles","Express Checkout Payment","USD","3,840.60","-142.40","3,698.20","3,699.13","TID11","paypal@partner2.com","Partner 2","","","0.00","0.00","362",""
"9/11/2018","00:01:50","America/Los_Angeles","General Currency Conversion","USD","-3,699.00","0.00","-3,699.00","0.13","TID12","","","","","0.00","0.00","","TID3"
"9/24/2018","16:41:01","America/Los_Angeles","Express Checkout Payment","USD","4,447.40","-164.85","4,282.55","4,282.68","TID13","paypa@partner2.com","Partner 2","","","0.00","0.00","363",""
"9/24/2018","16:41:01","America/Los_Angeles","Express Checkout Payment","USD","4,447.40","-164.85","4,282.55","4,282.68","TID13","paypal@partner2.com","Partner 2","","","0.00","0.00","363",""
"9/25/2018","04:22:39","America/Los_Angeles","General Currency Conversion","USD","-4,282.00","0.00","-4,282.00","0.68","TID14","","","","","0.00","0.00","","TID5"
"9/27/2018","18:15:34","America/Los_Angeles","Express Checkout Payment","USD","5,600.00","-207.50","5,392.50","5,393.18","TID15","paypa@partner3.com","Partner 3","","","0.00","0.00","366",""
"9/27/2018","18:16:12","CET","Express Checkout Payment","USD","920.70","-34.37","886.33","6,279.51","TID16","paypa@partner3.com","Partner 3","","","0.00","0.00","367",""
"9/27/2018","18:17:59","America/Los_Angeles","Express Checkout Payment","USD","5,600.00","-207.50","5,392.50","11,672.01","TID17","paypa@partner3.com","Partner 3","","","0.00","0.00","371",""
"9/27/2018","18:15:34","America/Los_Angeles","Express Checkout Payment","USD","5,600.00","-207.50","5,392.50","5,393.18","TID15","paypal@partner3.com","Partner 3","","","0.00","0.00","366",""
"9/27/2018","18:16:12","CET","Express Checkout Payment","USD","920.70","-34.37","886.33","6,279.51","TID16","paypal@partner3.com","Partner 3","","","0.00","0.00","367",""
"9/27/2018","18:17:59","America/Los_Angeles","Express Checkout Payment","USD","5,600.00","-207.50","5,392.50","11,672.01","TID17","paypal@partner3.com","Partner 3","","","0.00","0.00","371",""
"9/27/2018","21:33:27","America/Los_Angeles","General Currency Conversion","USD","-11,672.00","0.00","-11,672.00","0.01","TID18","","","","","0.00","0.00","","TID7"
"9/30/2018","21:22:33","America/Los_Angeles","Express Checkout Payment","USD","292.30","-11.12","281.18","281.19","TID19","paypal@partner1.com","Partner 1","","","0.00","0.00","380",""
1 Date Time Time Zone Description Currency Gross Fee Net Balance Transaction ID From Email Address Name Bank Name Bank Account Shipping and Handling Amount Sales Tax Invoice ID Reference Txn ID
9 9/27/2018 21:33:27 America/Los_Angeles General Currency Conversion EUR 9,648.13 0.00 9,648.13 0.75 TID8 0.00 0.00 TID7
10 9/4/2018 20:44:10 America/Los_Angeles Express Checkout Payment USD 1,309.80 -48.76 1,261.04 1,261.93 TID9 paypal@partner1.com Partner 1 0.00 0.00 361
11 9/4/2018 21:15:11 America/Los_Angeles General Currency Conversion USD -1,261.00 0.00 -1,261.00 0.93 TID10 0.00 0.00 TID1
12 9/10/2018 17:48:19 America/Los_Angeles Express Checkout Payment USD 3,840.60 -142.40 3,698.20 3,699.13 TID11 paypa@partner2.com paypal@partner2.com Partner 2 0.00 0.00 362
13 9/11/2018 00:01:50 America/Los_Angeles General Currency Conversion USD -3,699.00 0.00 -3,699.00 0.13 TID12 0.00 0.00 TID3
14 9/24/2018 16:41:01 America/Los_Angeles Express Checkout Payment USD 4,447.40 -164.85 4,282.55 4,282.68 TID13 paypa@partner2.com paypal@partner2.com Partner 2 0.00 0.00 363
15 9/25/2018 04:22:39 America/Los_Angeles General Currency Conversion USD -4,282.00 0.00 -4,282.00 0.68 TID14 0.00 0.00 TID5
16 9/27/2018 18:15:34 America/Los_Angeles Express Checkout Payment USD 5,600.00 -207.50 5,392.50 5,393.18 TID15 paypa@partner3.com paypal@partner3.com Partner 3 0.00 0.00 366
17 9/27/2018 18:16:12 CET Express Checkout Payment USD 920.70 -34.37 886.33 6,279.51 TID16 paypa@partner3.com paypal@partner3.com Partner 3 0.00 0.00 367
18 9/27/2018 18:17:59 America/Los_Angeles Express Checkout Payment USD 5,600.00 -207.50 5,392.50 11,672.01 TID17 paypa@partner3.com paypal@partner3.com Partner 3 0.00 0.00 371
19 9/27/2018 21:33:27 America/Los_Angeles General Currency Conversion USD -11,672.00 0.00 -11,672.00 0.01 TID18 0.00 0.00 TID7
20 9/30/2018 21:22:33 America/Los_Angeles Express Checkout Payment USD 292.30 -11.12 281.18 281.19 TID19 paypal@partner1.com Partner 1 0.00 0.00 380

View File

@@ -0,0 +1,5 @@
"Fecha","Hora","Zona horaria","Descripción","Divisa","Bruto","Comisión","Neto","Saldo","Id. de transacción","Correo electrónico del remitente","Nombre","Nombre del banco","Cuenta bancaria","Importe de envío y manipulación","Impuesto de ventas","Id. de factura","Id. de referencia de trans.",,,,,,
"2/1/2020","11:05:56","Europe/Berlin","Pago estándar","EUR","49,37","-1,78","47,59","4.626,81","TID1","paypal@partner1.com","Partner 1","","","0,00","0,00","",""
"2/1/2020","13:06:07","Europe/Berlin","Pago estándar","EUR","28,82","-1,19","27,63","4.654,44","TID2","paypal@partner2.com","Partner 2","","","0,00","0,00","",""
"2/1/2020","19:20:05","Europe/Berlin","Pago estándar","EUR","35,78","-1,39","34,39","4.688,83","TID3","paypal@partner3.com","Partner 3","","","0,00","0,00","",""
"3/1/2020","09:44:24","Europe/Berlin","Pago estándar","EUR","22,47","-1,00","21,47","4.710,30","TID4","paypal@partner4.com","Partner 4","","","0,00","0,00","",""
1 Fecha Hora Zona horaria Descripción Divisa Bruto Comisión Neto Saldo Id. de transacción Correo electrónico del remitente Nombre Nombre del banco Cuenta bancaria Importe de envío y manipulación Impuesto de ventas Id. de factura Id. de referencia de trans.
2 2/1/2020 11:05:56 Europe/Berlin Pago estándar EUR 49,37 -1,78 47,59 4.626,81 TID1 paypal@partner1.com Partner 1 0,00 0,00
3 2/1/2020 13:06:07 Europe/Berlin Pago estándar EUR 28,82 -1,19 27,63 4.654,44 TID2 paypal@partner2.com Partner 2 0,00 0,00
4 2/1/2020 19:20:05 Europe/Berlin Pago estándar EUR 35,78 -1,39 34,39 4.688,83 TID3 paypal@partner3.com Partner 3 0,00 0,00
5 3/1/2020 09:44:24 Europe/Berlin Pago estándar EUR 22,47 -1,00 21,47 4.710,30 TID4 paypal@partner4.com Partner 4 0,00 0,00

View File

@@ -20,6 +20,9 @@ class TestAccountBankStatementImportPayPal(common.TransactionCase):
self.paypal_statement_map_en = self.env.ref(
'account_bank_statement_import_paypal.paypal_statement_map_en'
)
self.paypal_statement_map_es = self.env.ref(
'account_bank_statement_import_paypal.paypal_statement_map_es'
)
self.paypal_activity_map_en = self.env.ref(
'account_bank_statement_import_paypal.paypal_activity_map_en'
)
@@ -63,6 +66,30 @@ class TestAccountBankStatementImportPayPal(common.TransactionCase):
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 18)
def test_import_statement_es(self):
journal = self.AccountJournal.create({
'name': 'PayPal',
'type': 'bank',
'code': 'PP',
'currency_id': self.currency_eur.id,
})
wizard = self.AccountBankStatementImport.with_context({
'journal_id': journal.id,
}).create({
'filename': 'fixtures/statement_es.csv',
'data_file': self._data_file('fixtures/statement_es.csv'),
'paypal_mapping_id': self.paypal_statement_map_es.id,
})
wizard.with_context({
'journal_id': journal.id,
'account_bank_statement_import_paypal_test': True,
}).import_file()
statement = self.AccountBankStatement.search([
('journal_id', '=', journal.id),
])
self.assertEqual(len(statement), 1)
self.assertEqual(len(statement.line_ids), 8)
def test_import_activity_en(self):
journal = self.AccountJournal.create({
'name': 'PayPal',
@@ -112,21 +139,39 @@ class TestAccountBankStatementImportPayPal(common.TransactionCase):
self.assertEqual(len(statement), 0)
def test_import_activity_mapping_en(self):
wizard = self.AccountBankStatementImportPayPalMappingWizard.create({
'filename': 'fixtures/activity_en.csv',
'data_file': self._data_file('fixtures/activity_en.csv'),
})
mapping = self.AccountBankStatementImportPayPalMapping.browse(
wizard.import_mapping()['res_id']
)
self.assertTrue(mapping)
with common.Form(
self.AccountBankStatementImportPayPalMappingWizard) as form:
form.filename = 'fixtures/activity_en.csv'
form.data_file = self._data_file(
'fixtures/activity_en.csv'
)
self.assertEqual(
len(
self.AccountBankStatementImportPayPalMappingWizard
.with_context(
header=form.header,
).statement_columns()
),
22
)
wizard = form.save()
wizard.import_mapping()
def test_import_statement_mapping_en(self):
wizard = self.AccountBankStatementImportPayPalMappingWizard.create({
'filename': 'fixtures/statement_en.csv',
'data_file': self._data_file('fixtures/statement_en.csv'),
})
mapping = self.AccountBankStatementImportPayPalMapping.browse(
wizard.import_mapping()['res_id']
)
self.assertTrue(mapping)
with common.Form(
self.AccountBankStatementImportPayPalMappingWizard) as form:
form.filename = 'fixtures/statement_en.csv'
form.data_file = self._data_file(
'fixtures/statement_en.csv'
)
self.assertEqual(
len(
self.AccountBankStatementImportPayPalMappingWizard
.with_context(
header=form.header,
).statement_columns()
),
18
)
wizard = form.save()
wizard.import_mapping()

View File

@@ -1,78 +1,162 @@
# Copyright 2019 Tecnativa - Vicent Cubells
# Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
# Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from base64 import b64decode
import json
from os import path
class AccountBankStatementImportPayPalMappingWizard(models.TransientModel):
_name = 'account.bank.statement.import.paypal.mapping.wizard'
_description = 'Account Bank Statement Import PayPal Mapping Wizard'
_inherit = ['multi.step.wizard.mixin']
data_file = fields.Binary(
string='Bank Statement File',
string='PayPal Report File',
required=True,
)
filename = fields.Char()
header = fields.Char()
date_column = fields.Char(
string='"Date" column',
)
time_column = fields.Char(
string='"Time" column',
)
tz_column = fields.Char(
string='"Timezone" column',
)
name_column = fields.Char(
string='"Name" column',
)
currency_column = fields.Char(
string='"Currency" column',
)
gross_column = fields.Char(
string='"Gross" column',
)
fee_column = fields.Char(
string='"Fee" column',
)
balance_column = fields.Char(
string='"Balance" column',
)
transaction_id_column = fields.Char(
string='"Transaction ID" column',
)
description_column = fields.Char(
string='"Description" column',
)
type_column = fields.Char(
string='"Type" column',
)
from_email_address_column = fields.Char(
string='"From Email Address" column',
)
to_email_address_column = fields.Char(
string='"To Email Address" column',
)
invoice_id_column = fields.Char(
string='"Invoice ID" column',
)
subject_column = fields.Char(
string='"Subject" column',
)
note_column = fields.Char(
string='"Note" column',
)
bank_name_column = fields.Char(
string='"Bank Name" column',
)
bank_account_column = fields.Char(
string='"Bank Account" column',
)
@api.onchange('data_file')
def _onchange_data_file(self):
Parser = self.env['account.bank.statement.import.paypal.parser']
if not self.data_file:
return
header = Parser.parse_header(b64decode(self.data_file))
header = [column for column in header if column]
self.header = json.dumps(header)
if len(header) == 22:
self.date_column = header[0]
self.time_column = header[1]
self.tz_column = header[2]
self.name_column = header[3]
self.currency_column = header[6]
self.gross_column = header[7]
self.fee_column = header[8]
self.balance_column = header[18]
self.transaction_id_column = header[12]
self.type_column = header[4]
self.from_email_address_column = header[10]
self.to_email_address_column = header[11]
self.invoice_id_column = header[16]
self.subject_column = header[20]
self.note_column = header[21]
elif len(header) == 18:
self.date_column = header[0]
self.time_column = header[1]
self.tz_column = header[2]
self.name_column = header[11]
self.currency_column = header[4]
self.gross_column = header[5]
self.fee_column = header[6]
self.balance_column = header[8]
self.transaction_id_column = header[9]
self.description_column = header[3]
self.from_email_address_column = header[10]
self.invoice_id_column = header[16]
self.bank_name_column = header[12]
self.bank_account_column = header[13]
@api.model
def statement_columns(self):
header = self.env.context.get('header')
if not header:
return []
return [(x, x) for x in json.loads(header)]
@api.multi
def import_mapping(self):
def _get_mapping_values(self):
"""Hook for extension"""
self.ensure_one()
mapping_values = {
return {
'name': _('Mapping from %s') % path.basename(self.filename),
'float_thousands_sep': 'comma',
'float_decimal_sep': 'dot',
'date_format': '%d/%m/%Y',
'time_format': '%H:%M:%S',
'date_column': self.date_column,
'time_column': self.time_column,
'tz_column': self.tz_column,
'name_column': self.name_column,
'currency_column': self.currency_column,
'gross_column': self.gross_column,
'fee_column': self.fee_column,
'balance_column': self.balance_column,
'transaction_id_column': self.transaction_id_column,
'description_column': self.description_column,
'type_column': self.type_column,
'from_email_address_column': self.from_email_address_column,
'to_email_address_column': self.to_email_address_column,
'invoice_id_column': self.invoice_id_column,
'subject_column': self.subject_column,
'note_column': self.note_column,
'bank_name_column': self.bank_name_column,
'bank_account_column': self.bank_account_column,
}
header = self.env['account.bank.statement.import.paypal.parser'] \
.parse_header(b64decode(self.data_file))
if len(header) == 22:
mapping_values.update({
'date_column': header[0],
'time_column': header[1],
'tz_column': header[2],
'name_column': header[3],
'currency_column': header[6],
'gross_column': header[7],
'fee_column': header[8],
'balance_column': header[18],
'transaction_id_column': header[12],
'type_column': header[4],
'from_email_address_column': header[10],
'to_email_address_column': header[11],
'invoice_id_column': header[16],
'subject_column': header[20],
'note_column': header[21],
})
elif len(header) == 18:
mapping_values.update({
'date_column': header[0],
'time_column': header[1],
'tz_column': header[2],
'name_column': header[11],
'currency_column': header[4],
'gross_column': header[5],
'fee_column': header[6],
'balance_column': header[8],
'transaction_id_column': header[9],
'description_column': header[3],
'from_email_address_column': header[10],
'invoice_id_column': header[16],
'bank_name_column': header[12],
'bank_account_column': header[13],
})
else:
raise UserError(_(
'File structure does not look like a PayPal report, please '
'check the file or create the mapping manually.'
))
@api.multi
def import_mapping(self):
self.ensure_one()
mapping = self.env['account.bank.statement.import.paypal.mapping']\
.create(mapping_values)
.create(self._get_mapping_values())
return {
'type': 'ir.actions.act_window',
'name': _('Imported Mapping'),

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 Tecnativa - Vicent Cubells
Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
@@ -9,16 +9,147 @@
<record id="account_bank_statement_import_paypal_mapping_wizard_form" model="ir.ui.view">
<field name="name">account.bank.statement.import.paypal.mapping.wizard.form</field>
<field name="model">account.bank.statement.import.paypal.mapping.wizard</field>
<field name="mode">primary</field>
<field name="inherit_id" ref="multi_step_wizard.multi_step_wizard_form"/>
<field name="arch" type="xml">
<form>
<xpath expr="//footer" position="before">
<h2>Select a PayPal report file to import mapping.</h2>
<field name="data_file" filename="filename" placeholder="Choose a file to import..."/>
<field name="filename" invisible="1"/>
<footer>
<button name="import_mapping" string="Import" type="object" class="btn-primary" />
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
<group name="start" attrs="{'invisible': [('state', '!=', 'start')]}">
<group colspan="2">
<field name="data_file" filename="filename" placeholder="Choose a file to import..."/>
<field name="filename" invisible="1"/>
</group>
</group>
<group name="final" attrs="{'invisible': [('state', '!=', 'final')]}">
<group colspan="2">
<field name="header" invisible="1"/>
<field
name="date_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="time_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="tz_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="name_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="currency_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="gross_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="fee_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="balance_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="transaction_id_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
attrs="{'required': [('state', '=', 'final')]}"
/>
<field
name="description_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
<field
name="type_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
<field
name="from_email_address_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
<field
name="to_email_address_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
<field
name="invoice_id_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
<field
name="subject_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
<field
name="note_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
<field
name="bank_name_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
<field
name="bank_account_column"
widget="dynamic_dropdown"
values="statement_columns"
context="{'header': header}"
/>
</group>
</group>
</xpath>
<xpath expr="//div[@name='final_buttons']/button" position="attributes">
<attribute name="class">btn-default</attribute>
<attribute name="string">Cancel</attribute>
</xpath>
<xpath expr="//div[@name='final_buttons']/button" position="before">
<button name="import_mapping" string="Import" type="object" class="btn-primary" />
</xpath>
</field>
</record>

View File

@@ -1 +1,2 @@
web
server-ux