[IMP] account: edi export/import review

bzr revid: odo@openerp.com-20111005003409-7umxxyebrh6jf8r2
This commit is contained in:
Olivier Dony 2011-10-05 02:34:09 +02:00
parent 77180a5bcc
commit 05497056de
6 changed files with 189 additions and 241 deletions

View File

@ -35,5 +35,5 @@ import product
import sequence import sequence
import company import company
import res_currency import res_currency
import edi_invoice import edi
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -53,7 +53,7 @@ module named account_voucher.
'website': 'http://www.openerp.com', 'website': 'http://www.openerp.com',
'images' : ['images/accounts.jpeg','images/bank_statement.jpeg','images/cash_register.jpeg','images/chart_of_accounts.jpeg','images/customer_invoice.jpeg','images/journal_entries.jpeg'], 'images' : ['images/accounts.jpeg','images/bank_statement.jpeg','images/cash_register.jpeg','images/chart_of_accounts.jpeg','images/customer_invoice.jpeg','images/journal_entries.jpeg'],
'init_xml': [], 'init_xml': [],
"depends" : ["base_setup", "product", "analytic", "process","board", "email_template"], "depends" : ["base_setup", "product", "analytic", "process", "board", "edi", "email_template"],
'update_xml': [ 'update_xml': [
'security/account_security.xml', 'security/account_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
@ -124,7 +124,7 @@ module named account_voucher.
'board_account_view.xml', 'board_account_view.xml',
"wizard/account_report_profit_loss_view.xml", "wizard/account_report_profit_loss_view.xml",
"wizard/account_report_balance_sheet_view.xml", "wizard/account_report_balance_sheet_view.xml",
"edi_invoice_action_data.xml", "edi/invoice_action_data.xml",
"account_bank_view.xml", "account_bank_view.xml",
], ],
'demo_xml': [ 'demo_xml': [

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2011 OpenERP S.A. <http://openerp.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/>.
#
##############################################################################
import invoice

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
############################################################################## ##############################################################################
# #
# OpenERP, Open Source Management Solution # OpenERP, Open Source Business Applications
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). # Copyright (c) 2011 OpenERP S.A. <http://openerp.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as # it under the terms of the GNU Affero General Public License as
@ -20,10 +20,10 @@
############################################################################## ##############################################################################
from osv import fields, osv, orm from osv import fields, osv, orm
from base.ir import ir_edi from edi import EDIMixin
from tools.translate import _ from tools.translate import _
class account_invoice(osv.osv, ir_edi.edi): class account_invoice(osv.osv, EDIMixin):
_inherit = 'account.invoice' _inherit = 'account.invoice'
def edi_export(self, cr, uid, records, edi_struct=None, context=None): def edi_export(self, cr, uid, records, edi_struct=None, context=None):
@ -35,24 +35,19 @@ class account_invoice(osv.osv, ir_edi.edi):
'type': True, # -> reversed at import 'type': True, # -> reversed at import
'internal_number': True, # -> reference at import 'internal_number': True, # -> reference at import
'comment': True, 'comment': True,
'reference': True,
'amount_untaxed': True,
'amount_tax': True,
'amount_total': True,
'reconciled': True,
'date_invoice': True, 'date_invoice': True,
'date_due': True, 'date_due': True,
'partner_id': True, 'partner_id': True,
'address_invoice_id': True, #only one address needed 'address_invoice_id': True, #only one address needed
'payment_term': True, 'payment_term': True,
'currency_id': True, 'currency_id': True, # TODO: should perhaps include sample rate + rounding
'invoice_line': { 'invoice_line': {
'name': True, 'name': True,
'origin': True, 'origin': True,
'uos_id': True, 'uos_id': True,
'product_id': True, 'product_id': True,
'price_unit': True, 'price_unit': True,
'price_subtotal': True, #'price_subtotal': True,
'quantity': True, 'quantity': True,
'discount': True, 'discount': True,
'note': True, 'note': True,
@ -66,40 +61,20 @@ class account_invoice(osv.osv, ir_edi.edi):
'base_amount': True, 'base_amount': True,
'tax_amount': True, 'tax_amount': True,
}, },
#'paid': True,
} }
company_pool = self.pool.get('res.company') res_company = self.pool.get('res.company')
edi_doc_list = [] edi_doc_list = []
for invoice in records: for invoice in records:
# Get EDI doc based on struct. The result will also contain all metadata fields and attachments. edi_doc = super(account_invoice,self).edi_export(cr, uid, [invoice], edi_struct, context)[0]
edi_doc = super(account_invoice,self).edi_export(cr, uid, [invoice], edi_struct, context)
if not edi_doc:
continue
edi_doc = edi_doc[0]
# Add company info and address
edi_company_document = company_pool.edi_export_address(cr, uid, [invoice.company_id], context=context)[invoice.company_id.id]
edi_doc.update({ edi_doc.update({
'company_address': edi_company_document['company_address'], 'company_address': res_company.edi_export_address(cr, uid, invoice.company_id, context=context),
#'company_logo': edi_company_document['company_logo'],#TODO #'company_logo': #TODO
}) })
edi_doc_list.append(edi_doc) edi_doc_list.append(edi_doc)
return edi_doc_list return edi_doc_list
def get_invoice_journal(self, cr, uid, invoice_type, context=None): def _edi_tax_account(self, cr, uid, invoice_type='out_invoice', context=None):
if context is None: #TODO/FIXME: should select proper Tax Account
context = {}
account_journal_pool = self.pool.get('account.journal')
journal_context = context.copy()
journal_context.update({'type':invoice_type})
journal_id = self._get_journal(cr, uid, context=journal_context)
journal = False
if journal_id:
journal = account_journal_pool.browse(cr, uid, journal_id, context=context)
return journal
def get_tax_account(self, cr, uid, invoice_type='out_invoice', context=None):
#TOCHECK: should select account of output VAT for Customer Invoice and Input VAT for Supplier Invoice
account_pool = self.pool.get('account.account') account_pool = self.pool.get('account.account')
account_ids = account_pool.search(cr, uid, [('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')]) account_ids = account_pool.search(cr, uid, [('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')])
tax_account = False tax_account = False
@ -107,7 +82,7 @@ class account_invoice(osv.osv, ir_edi.edi):
tax_account = account_pool.browse(cr, uid, account_ids[0]) tax_account = account_pool.browse(cr, uid, account_ids[0])
return tax_account return tax_account
def get_invoice_account(self, cr, uid, partner_id, invoice_type, context=None): def _edi_invoice_account(self, cr, uid, partner_id, invoice_type, context=None):
partner_pool = self.pool.get('res.partner') partner_pool = self.pool.get('res.partner')
partner = partner_pool.browse(cr, uid, partner_id, context=context) partner = partner_pool.browse(cr, uid, partner_id, context=context)
if invoice_type in ('out_invoice', 'out_refund'): if invoice_type in ('out_invoice', 'out_refund'):
@ -116,45 +91,47 @@ class account_invoice(osv.osv, ir_edi.edi):
invoice_account = partner.property_account_payable invoice_account = partner.property_account_payable
return invoice_account return invoice_account
def get_product_account(self, cr, uid, product_id, invoice_type, context=None): def _edi_product_account(self, cr, uid, product_id, invoice_type, context=None):
product_pool = self.pool.get('product.product') product_pool = self.pool.get('product.product')
product = product_pool.browse(cr, uid, product_id, context=context) product = product_pool.browse(cr, uid, product_id, context=context)
account = False
if invoice_type in ('out_invoice','out_refund'): if invoice_type in ('out_invoice','out_refund'):
account = product.product_tmpl_id.property_account_income account = product.property_account_income or product.categ_id.property_account_income_categ
if not account:
account = product.categ_id.property_account_income_categ
else: else:
account = product.product_tmpl_id.property_account_expense account = product.property_account_expense or product.categ_id.property_account_expense_categ
if not account:
account = product.categ_id.property_account_expense_categ
return account return account
def edi_import_company(self, cr, uid, edi_document, context=None): def _edi_import_company(self, cr, uid, edi_document, context=None):
partner_address_pool = self.pool.get('res.partner.address') self._edi_requires_attributes(('company_id','company_address','type'), edi_document)
partner_pool = self.pool.get('res.partner') res_partner_address = self.pool.get('res.partner.address')
company_pool = self.pool.get('res.company') res_partner = self.pool.get('res.partner')
# import company as a new partner, if type==in then supplier=1, else customer=1 # imported company = new partner
# company_address data used to add address to new partner company_id, company_name = edi_document['company_id']
partner_id = self.edi_import_relation(cr, uid, 'res.partner', company_name,
company_id, context=context)
invoice_type = edi_document['type'] invoice_type = edi_document['type']
partner_value = {} partner_value = {}
if invoice_type in ('out_invoice', 'in_refund'): if invoice_type in ('out_invoice', 'out_refund'):
partner_value.update({'customer': True}) partner_value.update({'customer': True})
if invoice_type in ('in_invoice', 'out_refund'): if invoice_type in ('in_invoice', 'in_refund'):
partner_value.update({'supplier': True}) partner_value.update({'supplier': True})
partner_id = company_pool.edi_import_as_partner(cr, uid, edi_document, values=partner_value, context=context) partner_id = res_partner.write(cr, uid, [partner_id], partner_value, context=context)
# partner_id field is modified to point to the new partner # imported company_address = new partner address
res = partner_pool.address_get(cr, uid, [partner_id], ['contact', 'invoice']) address_info = edi_document['company_address']
address_id = res['invoice'] address_info['partner_id'] = (company_id, company_name)
partner = partner_pool.browse(cr, uid, partner_id, context=context) address_info['type'] = 'invoice'
partner_address = partner_address_pool.browse(cr, uid, address_id, context=context) address_id = res_partner_address.edi_import(cr, uid, address_info, context=context)
edi_document['partner_id'] = self.edi_m2o(cr, uid, partner, context=context)
edi_document['address_invoice_id'] = self.edi_m2o(cr, uid, partner_address, context=context) # modify edi_document to refer to new partner
del edi_document['company_id'] del edi_document['company_id']
del edi_document['company_address']
partner_address = res_partner_address.browse(cr, uid, address_id, context=context)
edi_document['partner_id'] = (company_id, company_name)
edi_document['address_invoice_id'] = self.edi_m2o(cr, uid, partner_address, context=context)
return partner_id return partner_id
def edi_import(self, cr, uid, edi_document, context=None): def edi_import(self, cr, uid, edi_document, context=None):
""" During import, invoices will import the company that is provided in the invoice as """ During import, invoices will import the company that is provided in the invoice as
@ -168,7 +145,7 @@ class account_invoice(osv.osv, ir_edi.edi):
- reference: should contain the value of the 'internal_number' - reference: should contain the value of the 'internal_number'
- reference_type: 'none' - reference_type: 'none'
- internal number: reset to False, auto-generated - internal number: reset to False, auto-generated
- journal_id: should be selected based on type: simply put the 'type' - journal_id: should be selected based on type: simply put the 'type'
in the context when calling create(), will be selected correctly in the context when calling create(), will be selected correctly
- payment_term: if set, create a default one based on name... - payment_term: if set, create a default one based on name...
- for invoice lines, the account_id value should be taken from the - for invoice lines, the account_id value should be taken from the
@ -176,21 +153,22 @@ class account_invoice(osv.osv, ir_edi.edi):
be provided. be provided.
- for tax lines, we disconnect from the invoice.line, so all tax lines - for tax lines, we disconnect from the invoice.line, so all tax lines
will be of type 'manual', and default accounts should be picked based will be of type 'manual', and default accounts should be picked based
on the tax config of the DB where it is imported. on the tax config of the DB where it is imported.
""" """
if context is None: if context is None:
context = {} context = {}
self._edi_requires_attributes(('company_id','company_address','type','invoice_line'), edi_document)
#import company as a new partner
partner_id = self.edi_import_company(cr, uid, edi_document, context=context)
# change type: out_invoice'<->'in_invoice','out_refund'<->'in_refund' # change type: out_invoice'<->'in_invoice','out_refund'<->'in_refund'
invoice_type = edi_document['type'] invoice_type = edi_document['type']
invoice_type = invoice_type.startswith('in_') and invoice_type.replace('in_','out_') or invoice_type.replace('out_','in_') invoice_type = invoice_type.startswith('in_') and invoice_type.replace('in_','out_') or invoice_type.replace('out_','in_')
edi_document['type'] = invoice_type edi_document['type'] = invoice_type
#import company as a new partner
partner_id = self._edi_import_company(cr, uid, edi_document, context=context)
# Set Account # Set Account
invoice_account = self.get_invoice_account(cr, uid, partner_id, invoice_type, context=context) invoice_account = self._edi_invoice_account(cr, uid, partner_id, invoice_type, context=context)
edi_document['account_id'] = invoice_account and self.edi_m2o(cr, uid, invoice_account, context=context) or False edi_document['account_id'] = invoice_account and self.edi_m2o(cr, uid, invoice_account, context=context) or False
# reference: should contain the value of the 'internal_number' # reference: should contain the value of the 'internal_number'
@ -200,44 +178,34 @@ class account_invoice(osv.osv, ir_edi.edi):
# internal number: reset to False, auto-generated # internal number: reset to False, auto-generated
edi_document['internal_number'] = False edi_document['internal_number'] = False
# journal_id: should be selected based on type: simply put the 'type' in the context when calling create(), will be selected correctly # journal_id: should be selected based on type: simply put the 'type' in the context when calling create(), will be selected correctly
journal = self.get_invoice_journal(cr, uid, invoice_type, context=context) context.update(type=invoice_type)
edi_document['journal_id'] = journal and self.edi_m2o(cr, uid, journal, context=context) or False
# for invoice lines, the account_id value should be taken from the product's default, i.e. from the default category, as it will not be provided. # for invoice lines, the account_id value should be taken from the product's default, i.e. from the default category, as it will not be provided.
for edi_invoice_line in edi_document.get('invoice_line', []): for edi_invoice_line in edi_document['invoice_line']:
product_id = edi_invoice_line.get('product_id', False) product_info = edi_invoice_line['product_id']
account = False product_id = self.edi_import_relation(cr, uid, 'product.product', product_info[1],
if product_id: product_info[0], context=context)
product_name = product_id and product_id[1] account = self._edi_product_account(cr, uid, product_id, invoice_type, context=context)
product_id = self.edi_import_relation(cr, uid, 'product.product', product_name, context=context) # TODO: could be improved with fiscal positions perhaps
account = self.get_product_account(cr, uid, product_id, invoice_type, context=context)
# TODO: add effect of fiscal position
# account = fpos_obj.map_account(cr, uid, fiscal_position_id, account.id) # account = fpos_obj.map_account(cr, uid, fiscal_position_id, account.id)
edi_invoice_line['account_id'] = account and self.edi_m2o(cr, uid, account, context=context) or False edi_invoice_line['account_id'] = self.edi_m2o(cr, uid, account, context=context) if account else False
# for tax lines, we disconnect from the invoice.line, so all tax lines will be of type 'manual', and default accounts should be picked based # for tax lines, we disconnect from the invoice.line, so all tax lines will be of type 'manual', and default accounts should be picked based
# on the tax config of the DB where it is imported. # on the tax config of the DB where it is imported.
tax_account = self._edi_tax_account(cr, uid, context=context)
tax_account_info = self.edi_m2o(cr, uid, tax_account, context=context)
for edi_tax_line in edi_document.get('tax_line', []): for edi_tax_line in edi_document.get('tax_line', []):
tax_account = self.get_tax_account(cr, uid, context=context) edi_tax_line['account_id'] = tax_account_info
if tax_account:
edi_tax_line['account_id'] = self.edi_m2o(cr, uid, tax_account, context=context)
edi_tax_line['manual'] = True edi_tax_line['manual'] = True
# TODO :=> payment_term: if set, create a default one based on name...
return super(account_invoice,self).edi_import(cr, uid, edi_document, context=context) return super(account_invoice,self).edi_import(cr, uid, edi_document, context=context)
account_invoice()
class account_invoice_line(osv.osv, ir_edi.edi): class account_invoice_line(osv.osv, EDIMixin):
_inherit='account.invoice.line' _inherit='account.invoice.line'
account_invoice_line() class account_invoice_tax(osv.osv, EDIMixin):
class account_invoice_tax(osv.osv, ir_edi.edi):
_inherit = "account.invoice.tax" _inherit = "account.invoice.tax"
account_invoice_tax()

View File

@ -3,7 +3,7 @@
<data> <data>
<!-- EDI Export + Send email Action --> <!-- EDI Export + Send email Action -->
<record id="ir_actions_server_edi_invoice" model="ir.actions.server"> <record id="ir_actions_server_edi_invoice" model="ir.actions.server">
<field name="code"> <field name="code"><![CDATA[
try: try:
if not object.partner_id.opt_out: if not object.partner_id.opt_out:
web_root_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default="<WEB_ROOT_URL>") web_root_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default="<WEB_ROOT_URL>")
@ -12,11 +12,11 @@ try:
tmpl = self.pool.get('ir.model.data').get_object(cr, uid, 'account', 'email_template_edi_invoice')[1] tmpl = self.pool.get('ir.model.data').get_object(cr, uid, 'account', 'email_template_edi_invoice')[1]
edi_token = self.pool.get('ir.edi.document').export_edi(cr, uid, [object], context = context)[0] edi_token = self.pool.get('ir.edi.document').export_edi(cr, uid, [object], context = context)[0]
context.update(edi_web_invoice_url_view='%s/web/view_edi?db=%s&token=%s' %(web_root_url,cr.dbname, edi_token)) context.update(edi_web_invoice_url_view='%s/web/view_edi?db=%s&token=%s' %(web_root_url, cr.dbname, edi_token))
self.pool.get('email.template').send_mail(cr, uid,tmpl.id,object.id,context=context) self.pool.get('email.template').send_mail(cr, uid,tmpl.id,object.id,context=context)
except: except:
pass pass
</field> ]]></field>
<field eval="6" name="sequence"/> <field eval="6" name="sequence"/>
<field name="state">code</field> <field name="state">code</field>
<field name="type">ir.actions.server</field> <field name="type">ir.actions.server</field>
@ -41,75 +41,75 @@ except:
<field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a' })</field> <field name="subject">${object.company_id.name} Invoice (Ref ${object.number or 'n/a' })</field>
<field name="email_to">${object.address_invoice_id.email or ''}</field> <field name="email_to">${object.address_invoice_id.email or ''}</field>
<field name="model_id" ref="account.model_account_invoice"/> <field name="model_id" ref="account.model_account_invoice"/>
<field name="body_html"> <field name="body_html"><![CDATA[
&lt;div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); "&gt; <div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
&lt;p&gt;Hello${object.address_invoice_id.name and ' ' or ''}${object.address_invoice_id.name or ''},&lt;/p&gt; <p>Hello${object.address_invoice_id.name and ' ' or ''}${object.address_invoice_id.name or ''},</p>
&lt;p&gt;A new invoice is available for ${object.partner_id.name}: &lt;/p&gt; <p>A new invoice is available for ${object.partner_id.name}: </p>
&lt;p style="border-left: 1px solid #8e0000; margin-left: 30px;"&gt; <p style="border-left: 1px solid #8e0000; margin-left: 30px;">
&nbsp;&nbsp;&lt;strong&gt;REFERENCES&lt;/strong&gt;&lt;br /&gt; &nbsp;&nbsp;<strong>REFERENCES</strong><br />
&nbsp;&nbsp;Invoice number: &lt;strong&gt;${object.number}&lt;/strong&gt;&lt;br /&gt; &nbsp;&nbsp;Invoice number: <strong>${object.number}</strong><br />
&nbsp;&nbsp;Invoice amount: &lt;strong&gt;${object.amount_total} ${object.currency_id.name}&lt;/strong&gt;&lt;br /&gt; &nbsp;&nbsp;Invoice amount: <strong>${object.amount_total} ${object.currency_id.name}</strong><br />
&nbsp;&nbsp;Invoice date: ${object.date_invoice or 'n/a'}&lt;br /&gt; &nbsp;&nbsp;Invoice date: ${object.date_invoice or 'n/a'}<br />
&nbsp;&nbsp;Order reference: ${object.origin or 'n/a'}&lt;br /&gt; &nbsp;&nbsp;Order reference: ${object.origin or 'n/a'}<br />
&nbsp;&nbsp;Your contact: &lt;a href="mailto:${object.user_id.user_email or ''}?subject=Invoice%20${object.number}"&gt;${object.user_id.name}&lt;/a&gt; &nbsp;&nbsp;Your contact: <a href="mailto:${object.user_id.user_email or ''}?subject=Invoice%20${object.number}">${object.user_id.name}</a>
&lt;/p&gt; </p>
&lt;p&gt; <p>
You can view the invoice document, download it and pay online using the following link: You can view the invoice document, download it and pay online using the following link:
&lt;/p&gt; </p>
&lt;a style="display:block; width: 150px; height:20px; margin-left: 120px; color: #FFF; font-family: 'Lucida Grande', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: bold; text-align: center; text-decoration: none !important; line-height: 1; padding: 5px 0px 0px 0px; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(142, 0, 0); border-radius: 2px 2px; background-position: 0% 0%; background-repeat: repeat no-repeat;" <a style="display:block; width: 150px; height:20px; margin-left: 120px; color: #FFF; font-family: 'Lucida Grande', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: bold; text-align: center; text-decoration: none !important; line-height: 1; padding: 5px 0px 0px 0px; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(142, 0, 0); border-radius: 2px 2px; background-position: 0% 0%; background-repeat: repeat no-repeat;"
href="${ctx.get('edi_web_invoice_url_view') or ''}"&gt;View Invoice&lt;/a&gt; href="${ctx.get('edi_web_invoice_url_view') or ''}">View Invoice</a>
% if object.company_id.paypal_account: % if object.company_id.paypal_account:
&lt;br/&gt; <br/>
&lt;p&gt;It is also possible to directly pay with Paypal:&lt;/p&gt; <p>It is also possible to directly pay with Paypal:</p>
&lt;a style="display:block; width: 150px; height:20px; margin-left: 120px; color: #FFF; font-family: 'Lucida Grande', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: bold; text-align: center; text-decoration: none !important; line-height: 1; padding: 5px 0px 0px 0px; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(142, 0, 0); border-radius: 2px 2px; background-position: 0% 0%; background-repeat: repeat no-repeat;" <a style="display:block; width: 150px; height:20px; margin-left: 120px; color: #FFF; font-family: 'Lucida Grande', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: bold; text-align: center; text-decoration: none !important; line-height: 1; padding: 5px 0px 0px 0px; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(142, 0, 0); border-radius: 2px 2px; background-position: 0% 0%; background-repeat: repeat no-repeat;"
href="${"https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&amp;business=%s&amp;item_name=OpenERP%%20Invoice%%20%s&amp;invoice=%s&amp;amount=%s&amp;currency_code=%s&amp;button_subtype=services&amp;no_note=1&amp;bn=OpenERP_Invoice_PayNow_%s"%(object.company_id.paypal_account,object.number and object.number.replace('/','%2f') or '', object.number and object.number.replace('/','%2f') or '', object.amount_total, object.currency_id.name, object.currency_id.name)}" href="${"https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&amp;business=%s&amp;item_name=OpenERP%%20Invoice%%20%s&amp;invoice=%s&amp;amount=%s&amp;currency_code=%s&amp;button_subtype=services&amp;no_note=1&amp;bn=OpenERP_Invoice_PayNow_%s"%(object.company_id.paypal_account,object.number and object.number.replace('/','%2f') or '', object.number and object.number.replace('/','%2f') or '', object.amount_total, object.currency_id.name, object.currency_id.name)}"
&gt;Pay with Paypal&lt;/a&gt; >Pay with Paypal</a>
% endif % endif
&lt;br/&gt; <br/>
&lt;p&gt;If you have any question, do not hesitate to contact us.&lt;/p&gt; <p>If you have any question, do not hesitate to contact us.</p>
&lt;p&gt;Thank you for choosing ${object.company_id.name or 'us'}!&lt;/p&gt; <p>Thank you for choosing ${object.company_id.name or 'us'}!</p>
&lt;br/&gt; <br/>
&lt;br/&gt; <br/>
&lt;div style="width: 375px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; overflow-x: hidden; overflow-y: hidden; zoom: 1; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(142, 0, 0); border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; border-bottom-right-radius: 0px 0px; border-bottom-left-radius: 0px 0px; background-position: 0% 0%; background-repeat: repeat no-repeat; "&gt; <div style="width: 375px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; overflow-x: hidden; overflow-y: hidden; zoom: 1; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(142, 0, 0); border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; border-bottom-right-radius: 0px 0px; border-bottom-left-radius: 0px 0px; background-position: 0% 0%; background-repeat: repeat no-repeat; ">
&lt;h3 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 9px; padding-right: 14px; padding-bottom: 9px; padding-left: 14px; font-size: 12px; font-weight: normal; font-style: normal; color: rgb(255, 255, 255); "&gt; <h3 style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 9px; padding-right: 14px; padding-bottom: 9px; padding-left: 14px; font-size: 12px; font-weight: normal; font-style: normal; color: rgb(255, 255, 255); ">
&lt;strong style="text-transform:uppercase;"&gt;${object.company_id.name}&lt;/strong&gt;&lt;/h3&gt; <strong style="text-transform:uppercase;">${object.company_id.name}</strong></h3>
&lt;/div&gt; </div>
&lt;div style="width: 347px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 12px; padding-right: 14px; padding-bottom: 12px; padding-left: 14px; overflow-x: hidden; overflow-y: hidden; zoom: 1; line-height: 16px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(242, 242, 242); "&gt; <div style="width: 347px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 12px; padding-right: 14px; padding-bottom: 12px; padding-left: 14px; overflow-x: hidden; overflow-y: hidden; zoom: 1; line-height: 16px; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(242, 242, 242); ">
&lt;span style="color: rgb(38, 72, 149); margin-bottom: 5px; display: block; "&gt; <span style="color: rgb(38, 72, 149); margin-bottom: 5px; display: block; ">
% if object.company_id.street: % if object.company_id.street:
${object.company_id.street}&lt;br/&gt; ${object.company_id.street}<br/>
% endif % endif
% if object.company_id.street2: % if object.company_id.street2:
${object.company_id.street2}&lt;br/&gt; ${object.company_id.street2}<br/>
% endif % endif
% if object.company_id.city or object.company_id.zip: % if object.company_id.city or object.company_id.zip:
${object.company_id.zip} ${object.company_id.city}&lt;br/&gt; ${object.company_id.zip} ${object.company_id.city}<br/>
% endif % endif
% if object.company_id.country_id: % if object.company_id.country_id:
${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}&lt;br/&gt; ${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}<br/>
% endif % endif
&lt;/span&gt; </span>
% if object.company_id.phone: % if object.company_id.phone:
&lt;div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt; <div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">
Phone:&nbsp; ${object.company_id.phone} Phone:&nbsp; ${object.company_id.phone}
&lt;/div&gt; </div>
% endif % endif
% if object.company_id.website: % if object.company_id.website:
&lt;div&gt; <div>
Web :&nbsp;&lt;a href="${object.company_id.website}"&gt;${object.company_id.website}&lt;/a&gt; Web :&nbsp;<a href="${object.company_id.website}">${object.company_id.website}</a>
&lt;/div&gt; </div>
%endif %endif
&lt;p&gt;&lt;/p&gt; <p></p>
&lt;/div&gt; </div>
&lt;/div&gt; </div>
</field> ]]></field>
<field name="body_text"> <field name="body_text"><![CDATA[
Hello${object.address_invoice_id.name and ' ' or ''}${object.address_invoice_id.name or ''}, Hello${object.address_invoice_id.name and ' ' or ''}${object.address_invoice_id.name or ''},
A new invoice is available for ${object.partner_id.name}: A new invoice is available for ${object.partner_id.name}:
@ -154,7 +154,7 @@ Phone: ${object.company_id.phone}
% if object.company_id.website: % if object.company_id.website:
${object.company_id.website or ''} ${object.company_id.website or ''}
% endif % endif
</field> ]]></field>
</record> </record>
</data> </data>
</openerp> </openerp>

View File

@ -1,38 +1,20 @@
- -
I create a company for Customer In order to test the EDI export features of Invoices
- -
!record {model: res.company, id: res_company_test11}: First I create a draft customer invoice
name: Thomson pvt. ltd.
partner_id: 1
rml_header: 1
rml_header2: 1
rml_header3: 1
currency_id: 1
- -
I create a partner which is a my customer !record {model: account.invoice, id: invoice_edi_1}:
-
!record {model: res.partner, id: res_partner_test20}:
name: Junjun wala
supplier: False
company_id: res_company_test11
opt_out: True
-
I create one customer invoice
-
!record {model: account.invoice, id: customer_invoice_test}:
journal_id: 1 journal_id: 1
partner_id: res_partner_test20 partner_id: base.res_partner_agrolait
currency_id: base.EUR currency_id: base.EUR
address_invoice_id: base.res_partner_address_11 address_invoice_id: base.res_partner_address_8invoice
company_id: res_company_test11 company_id: 1
account_id: account.a_pay account_id: account.a_pay
date_invoice: '2011-06-22' date_invoice: '2011-06-22'
name: selling product name: selling product
type: 'out_invoice' type: 'out_invoice'
invoice_line: invoice_line:
- product_id: product.product_product_pc1 - product_id: product.product_product_pc1
partner_id: res_partner_test20
uos_id: 1 uos_id: 1
quantity: 1.0 quantity: 1.0
price_unit: 10.0 price_unit: 10.0
@ -40,117 +22,93 @@
account_id: account.a_pay account_id: account.a_pay
invoice_line: invoice_line:
- product_id: product.product_product_pc3 - product_id: product.product_product_pc3
partner_id: res_partner_test20
uos_id: 1 uos_id: 1
quantity: 5.0 quantity: 5.0
price_unit: 100.0 price_unit: 100.0
name: 'Medium PC' name: 'Medium PC'
account_id: account.a_pay account_id: account.a_pay
tax_line: tax_line:
- name: sale tax - name: sale tax
account_id: account.a_pay account_id: account.a_pay
manual: True manual: True
amount: 1000.00 amount: 1000.00
- -
I Open the Invoice I confirm and open the invoice
-
!workflow {model: account.invoice, ref: invoice_edi_1, action: invoice_open}
-
Then I export the customer invoice
-
!python {model: edi.document}: |
invoice_pool = self.pool.get('account.invoice')
invoice = invoice_pool.browse(cr, uid, ref("invoice_edi_1"))
token = self.export_edi(cr, uid, [invoice])
assert token, 'Invalid EDI Token'
-
Then I import a sample EDI document of another customer invoice
- -
!python {model: account.invoice}: | !python {model: account.invoice}: |
invoices = self.browse(cr, uid, ref("customer_invoice_test"))
import netsvc
wf_service = netsvc.LocalService("workflow")
wf_service.trg_validate(uid, 'account.invoice',invoices.id,'invoice_open', cr)
-
I Testing of EDI functionality. First I export customer invoice from my company than import that invoice into customer company
-
!python {model: ir.edi.document}: |
invoice_pool = self.pool.get('account.invoice')
invoice = invoice_pool.browse(cr, uid, ref("customer_invoice_test"))
tokens = self.export_edi(cr, uid, [invoice])
assert tokens, 'Token is not generated'
-
I import of EDI document of custmer invoice
-
!python {model: ir.edi.document}: |
invoice_pool = self.pool.get('account.invoice')
edi_document = { edi_document = {
"__id": "account:b22acf7a-ddcd-11e0-a4db-701a04e25543.random_invoice_763jsms",
"__module": "account",
"__model": "account.invoice",
"__version": [6,1,0],
"internal_number": "SAJ/2011/002", "internal_number": "SAJ/2011/002",
"company_address": { "company_address": {
"__id": "base:b22acf7a-ddcd-11e0-a4db-701a04e25543.main_address",
"__module": "base",
"__model": "res.partner.address",
"city": "Gerompont", "city": "Gerompont",
"zip": "1367", "zip": "1367",
"__last_update": False, "country_id": ["base:b22acf7a-ddcd-11e0-a4db-701a04e25543.be", "Belgium"],
"country_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:base.be", "Belgium"],
"__id": "b22acf7a-ddcd-11e0-a4db-701a04e25543:base.main_address",
"phone": "(+32).81.81.37.00", "phone": "(+32).81.81.37.00",
"street": "Chaussee de Namur 40" "street": "Chaussee de Namur 40"
}, },
"company_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:account.res_company_test11", "Thomson pvt. ltd."], "company_id": ["account:b22acf7a-ddcd-11e0-a4db-701a04e25543.res_company_test11", "Thomson pvt. ltd."],
"currency_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:base.EUR", "EUR (\u20ac)"], "currency_id": ["base:b22acf7a-ddcd-11e0-a4db-701a04e25543.EUR", "EUR (€)"],
"address_invoice_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:base.res_partner_address_11", "Sebastien LANGE, France, Alencon, 1 place de l'\u00c9glise"], "address_invoice_id": ["base:b22acf7a-ddcd-11e0-a4db-701a04e25543.res_partner_address_11", "Sebastien LANGE, France, Alencon, 1 place de l'\u00c9glise"],
"partner_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:account.res_partner_test20", "Junjun wala"], "partner_id": ["account:b22acf7a-ddcd-11e0-a4db-701a04e25543.res_partner_test20", "Junjun wala"],
"__attachments": [],
"__module": "account",
"amount_total": 1010.0,
"date_invoice": "2011-06-22", "date_invoice": "2011-06-22",
"amount_untaxed": 10.0, "name": "sample invoice",
"name": "selling product",
"__model": "account.invoice",
"__last_update": False,
"tax_line": [{ "tax_line": [{
"__id": "account:b22acf7a-ddcd-11e0-a4db-701a04e25543.account_invoice_tax-4g4EutbiEMVl",
"__module": "account",
"__model": "account.invoice.tax",
"amount": 1000.0, "amount": 1000.0,
"manual": True, "manual": True,
"__id": "b22acf7a-ddcd-11e0-a4db-701a04e25543:b22acf7a-ddcd-11e0-a4db-701a04e25543:account.account_invoice_tax-4g4EutbiEMVl",
"name": "sale tax", "name": "sale tax",
"__last_update": False
}], }],
"__id": "b22acf7a-ddcd-11e0-a4db-701a04e25543:account.customer_invoice_test",
"amount_tax": 1000.0,
"__version": [6, 1],
"type": "out_invoice", "type": "out_invoice",
"invoice_line": [{ "invoice_line": [{
"uos_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:product.product_uom_unit", "PCE"], "__module": "account",
"name": "basic pc", "__model": "account.invoice.line",
"__last_update": False, "__id": "account:b22acf7a-ddcd-11e0-a4db-701a04e25543.account_invoice_line-1RP3so",
"uos_id": ["product:b22acf7a-ddcd-11e0-a4db-701a04e25543.product_uom_unit", "PCE"],
"name": "Basic PC",
"price_unit": 10.0, "price_unit": 10.0,
"price_subtotal": 10.0, "product_id": ["product:b22acf7a-ddcd-11e0-a4db-701a04e25543.product_product_pc1", "[PC1] Basic PC"],
"__id": "b22acf7a-ddcd-11e0-a4db-701a04e25543:b22acf7a-ddcd-11e0-a4db-701a04e25543:account.account_invoice_line-1RP3so-u2vV4",
"product_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:product.product_product_pc1", "[PC1] Basic PC"],
"quantity": 1.0 "quantity": 1.0
}, },
{ {
"uos_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:product.product_uom_unit", "PCE"], "__module": "account",
"name": "Medim PC", "__model": "account.invoice.line",
"__last_update": False, "__id": "account:b22acf7a-ddcd-11e0-a4db-701a04e25543.account_invoice_line-u2XV5",
"uos_id": ["product:b22acf7a-ddcd-11e0-a4db-701a04e25543.product_uom_unit", "PCE"],
"name": "Medium PC",
"price_unit": 100.0, "price_unit": 100.0,
"price_subtotal": 100.0, "product_id": ["product:b22acf7a-ddcd-11e0-a4db-701a04e25543.product_product_pc3", "[PC3] Medium PC"],
"__id": "b22acf7a-ddcd-11e0-a4db-701a04e25543:b22acf7a-ddcd-11e0-a4db-701a04e25543:account.account_invoice_line-1RP3so-u2vV4",
"product_id": ["b22acf7a-ddcd-11e0-a4db-701a04e25543:product.product_product_pc3", "[PC3] Medium PC"],
"quantity": 5.0 "quantity": 5.0
}] }]
} }
invoice_id = self.edi_import(cr, uid, edi_document, context=context)
invoice_id = invoice_pool.edi_import(cr, uid, edi_document, context=context) assert invoice_id, 'EDI import failed'
invoice_new = invoice_pool.browse(cr, uid, invoice_id, context=context) invoice_new = self.browse(cr, uid, invoice_id)
assert invoice_id, 'Invoice is not imported' assert invoice_new.partner_id.supplier, 'Imported Partner is not marked as supplier'
-
I Checking the out invoice become in invoice or not after import
-
!python {model: account.invoice}: |
new_partner_id = self.pool.get('res.partner').name_search(cr, uid, "Thomson pvt. ltd.")
assert new_partner_id, 'Partner is not created of Supplier'
ids = self.search(cr, uid, [('partner_id','=',new_partner_id[0][0]),('reference','=',"SAJ/2011/002")])
assert ids, 'Invoice does not have created of party'
invoice_new = self.browse(cr, uid, ids[0])
assert invoice_new.reference == "SAJ/2011/002", "internal number is not stored in reference" assert invoice_new.reference == "SAJ/2011/002", "internal number is not stored in reference"
assert invoice_new.reference_type == 'none', "reference type is not set to 'None'" assert invoice_new.reference_type == 'none', "reference type is not set to 'none'"
assert invoice_new.internal_number == False, "internal number is not reset" assert invoice_new.internal_number == False, "internal number is not reset"
assert invoice_new.journal_id.id, "journal id is not selected" assert invoice_new.journal_id.id, "journal id is not selected"
assert invoice_new.type == 'in_invoice', "Imported in voice is not supplier invoice" assert invoice_new.type == 'in_invoice', "Invoice type was not set properly"
assert len(invoice_new.invoice_line) == 2, "invoice lines are not same" assert len(invoice_new.invoice_line) == 2, "invoice lines are not same"
for inv_line in invoice_new.invoice_line: for inv_line in invoice_new.invoice_line:
if inv_line.name == 'basic pc': if inv_line.name == 'basic pc':
@ -162,7 +120,7 @@
assert inv_line.uos_id.name == "PCE" , "uom is not same" assert inv_line.uos_id.name == "PCE" , "uom is not same"
assert inv_line.price_unit == 100 , "price unit is not same" assert inv_line.price_unit == 100 , "price unit is not same"
assert inv_line.quantity == 5 , "product qty is not same" assert inv_line.quantity == 5 , "product qty is not same"
assert inv_line.price_subtotal == 100, "price sub total is not same" assert inv_line.price_subtotal == 500, "price sub total is not same"
else: else:
assert 'wrong product imported in invoice lines' assert 'wrong product imported in invoice lines'
for inv_tax in invoice_new.tax_line: for inv_tax in invoice_new.tax_line: