2011-06-27 06:49:49 +00:00
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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/>.
#
##############################################################################
2011-06-21 13:30:26 +00:00
2011-06-24 13:11:17 +00:00
from osv import fields , osv , orm
2011-06-21 13:30:26 +00:00
from base . ir import ir_edi
2011-06-24 13:11:17 +00:00
from tools . translate import _
2011-06-21 13:30:26 +00:00
2011-06-27 08:32:28 +00:00
class account_invoice ( osv . osv , ir_edi . edi ) :
2011-06-21 13:30:26 +00:00
_inherit = ' account.invoice '
2011-06-27 08:32:28 +00:00
def edi_export ( self , cr , uid , records , edi_struct = None , context = None ) :
2011-06-21 13:30:26 +00:00
""" Exports a supplier or customer invoice """
edi_struct = {
' name ' : True ,
' origin ' : True ,
' company_id ' : True , # -> to be changed into partner
' type ' : True , # -> reversed at import
' internal_number ' : True , # -> reference at import
' comment ' : True ,
2011-07-13 10:19:07 +00:00
' reference ' : True ,
' amount_untaxed ' : True ,
' amount_tax ' : True ,
' amount_total ' : True ,
2011-07-15 08:43:43 +00:00
' reconciled ' : True ,
2011-06-21 13:30:26 +00:00
' date_invoice ' : True ,
' date_due ' : True ,
' partner_id ' : True ,
' address_invoice_id ' : True , #only one address needed
' payment_term ' : True ,
' currency_id ' : True ,
' invoice_line ' : {
' name ' : True ,
' origin ' : True ,
' uos_id ' : True ,
' product_id ' : True ,
' price_unit ' : True ,
2011-07-13 10:19:07 +00:00
' price_subtotal ' : True ,
2011-06-21 13:30:26 +00:00
' quantity ' : True ,
' discount ' : True ,
' note ' : True ,
} ,
' tax_line ' : {
' name ' : True ,
' base ' : True ,
' amount ' : True ,
' manual ' : True ,
' sequence ' : True ,
' base_amount ' : True ,
' tax_amount ' : True ,
} ,
}
2011-06-27 08:32:28 +00:00
partner_pool = self . pool . get ( ' res.partner ' )
partner_address_pool = self . pool . get ( ' res.partner.address ' )
company_address_dict = {
' street ' : True ,
' street2 ' : True ,
' zip ' : True ,
' city ' : True ,
' state_id ' : True ,
' country_id ' : True ,
' email ' : True ,
' phone ' : True ,
}
edi_doc_list = [ ]
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 )
if not edi_doc :
continue
edi_doc = edi_doc [ 0 ]
# Add company info and address
res = partner_pool . address_get ( cr , uid , [ invoice . company_id . partner_id . id ] , [ ' contact ' , ' invoice ' ] )
contact_addr_id = res [ ' contact ' ]
invoice_addr_id = res [ ' invoice ' ]
2011-06-27 06:49:49 +00:00
2011-06-27 08:32:28 +00:00
address = partner_address_pool . browse ( cr , uid , invoice_addr_id , context = context )
edi_company_address_dict = { }
for key , value in company_address_dict . items ( ) :
if not value :
continue
address_rec = getattr ( address , key )
if not address_rec :
continue
if key . endswith ( ' _id ' ) :
address_rec = self . edi_m2o ( cr , uid , address_rec , context = context )
edi_company_address_dict [ key ] = address_rec
edi_doc . update ( {
' company_address ' : edi_company_address_dict ,
#'company_logo': inv_comp.logo,#TODO
#'paid': inv_comp.paid, #TODO
} )
edi_doc_list . append ( edi_doc )
return edi_doc_list
2011-06-27 06:49:49 +00:00
2011-06-21 13:30:26 +00:00
def edi_import ( self , cr , uid , edi_document , context = None ) :
""" During import, invoices will import the company that is provided in the invoice as
a new partner ( e . g . supplier company for a customer invoice will be come a supplier
record for the new invoice .
Summary of tasks that need to be done :
- import company as a new partner , if type == in then supplier = 1 , else customer = 1
- partner_id field is modified to point to the new partner
- company_address data used to add address to new partner
- change type : out_invoice ' <-> ' in_invoice ' , ' out_refund ' <-> ' in_refund '
- reference : should contain the value of the ' internal_number '
- reference_type : ' none '
- internal number : reset to False , auto - generated
- journal_id : should be selected based on type : simply put the ' type '
in the context when calling create ( ) , will be selected correctly
2011-06-27 06:49:49 +00:00
- payment_term : if set , create a default one based on name . . .
2011-06-21 13:30:26 +00:00
- 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 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 .
"""
2011-06-27 06:53:31 +00:00
2011-06-27 12:26:16 +00:00
partner_pool = self . pool . get ( ' res.partner ' )
partner_address_pool = self . pool . get ( ' res.partner.address ' )
model_data_pool = self . pool . get ( ' ir.model.data ' )
product_pool = self . pool . get ( ' product.product ' )
product_categ_pool = self . pool . get ( ' product.category ' )
company_pool = self . pool . get ( ' res.company ' )
country_pool = self . pool . get ( ' res.country ' )
state_pool = self . pool . get ( ' res.country.state ' )
account_journal_pool = self . pool . get ( ' account.journal ' )
invoice_line_pool = self . pool . get ( ' account.invoice.line ' )
account_pool = self . pool . get ( ' account.account ' )
2011-06-21 13:30:26 +00:00
tax_id = [ ]
account_id = [ ]
partner_id = None
company_id = None
if context is None :
context = { }
2011-06-27 12:26:16 +00:00
# import company as a new partner, if type==in then supplier=1, else customer=1
# partner_id field is modified to point to the new partner
# company_address data used to add address to new partner
edi_company_address = edi_document [ ' company_address ' ]
edi_partner_id = edi_document [ ' partner_id ' ]
company_name = edi_document [ ' company_id ' ] [ 1 ]
invoice_type = edi_document [ ' type ' ]
state_id = edi_company_address . get ( ' state_id ' , False )
state_name = state_id and state_id [ 1 ]
country_id = edi_company_address . get ( ' country_id ' , False )
country_name = country_id and country_id [ 1 ]
country_id = country_name and self . edi_import_relation ( cr , uid , ' res.country ' , country_name , context = context ) or False
state_id = state_name and self . edi_import_relation ( cr , uid , ' res.country.state ' , state_name ,
values = { ' country_id ' : country_id , ' code ' : state_name } , context = context ) or False
address_value = {
' street ' : edi_company_address . get ( ' street ' , False ) ,
' street2 ' : edi_company_address . get ( ' street2 ' , False ) ,
' zip ' : edi_company_address . get ( ' zip ' , False ) ,
' city ' : edi_company_address . get ( ' city ' , False ) ,
' state_id ' : state_id ,
' country_id ' : country_id ,
' email ' : edi_company_address . get ( ' email ' , False ) ,
' phone ' : edi_company_address . get ( ' phone ' , False ) ,
2011-06-21 13:30:26 +00:00
2011-06-27 12:26:16 +00:00
}
2011-06-21 13:30:26 +00:00
2011-06-27 12:26:16 +00:00
partner_value = { ' name ' : company_name }
if invoice_type in ( ' out_invoice ' , ' in_refund ' ) :
partner_value . update ( { ' customer ' : True , ' supplier ' : False } )
if invoice_type in ( ' in_invoice ' , ' out_refund ' ) :
partner_value . update ( { ' customer ' : False , ' supplier ' : True } )
partner_id = partner_pool . create ( cr , uid , partner_value , context = context )
address_value . update ( { ' partner_id ' : partner_id } )
address_id = partner_address_pool . create ( cr , uid , address_value , context = context )
partner = partner_pool . browse ( cr , uid , partner_id , context = context )
edi_document [ ' partner_id ' ] = self . edi_m2o ( cr , uid , partner , context = context )
2011-07-15 10:59:13 +00:00
partner_address = partner_address_pool . browse ( cr , uid , address_id , context = context )
edi_document [ ' address_invoice_id ' ] = self . edi_m2o ( cr , uid , partner_address , context = context )
2011-06-27 12:26:16 +00:00
# change type: out_invoice'<->'in_invoice','out_refund'<->'in_refund'
invoice_type = invoice_type . startswith ( ' in_ ' ) and invoice_type . replace ( ' in_ ' , ' out_ ' ) or invoice_type . replace ( ' out_ ' , ' in_ ' )
edi_document [ ' type ' ] = invoice_type
# Set Account
if invoice_type in ( ' out_invoice ' , ' out_refund ' ) :
invoice_account = partner . property_account_receivable
else :
invoice_account = partner . property_account_payable
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'
edi_document [ ' reference ' ] = edi_document . get ( ' internal_number ' , False )
# reference_type: 'none'
edi_document [ ' reference_type ' ] = ' none '
# internal number: reset to False, auto-generated
edi_document [ ' internal_number ' ] = False
# company should set by default so delete company data from edi Document
2011-06-21 13:30:26 +00:00
del edi_document [ ' company_address ' ]
2011-06-27 12:26:16 +00:00
del edi_document [ ' company_id ' ]
# journal_id: should be selected based on type: simply put the 'type' in the context when calling create(), will be selected correctly
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 )
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 edi_invoice_line in edi_document . get ( ' invoice_line ' , [ ] ) :
product_id = edi_invoice_line . get ( ' product_id ' , False )
account = False
if product_id :
product_name = product_id and product_id [ 1 ]
product_id = self . edi_import_relation ( cr , uid , ' product.product ' , product_name , context = context )
product = product_pool . browse ( cr , uid , product_id , context = context )
if invoice_type in ( ' out_invoice ' , ' out_refund ' ) :
account = product . product_tmpl_id . property_account_income
if not account :
account = product . categ_id . property_account_income_categ
else :
account = product . product_tmpl_id . property_account_expense
if not account :
account = product . categ_id . property_account_expense_categ
# TODO: add effect of fiscal position
# 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
2011-06-28 13:43:26 +00:00
2011-06-27 12:26:16 +00:00
# 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.
for edi_tax_line in edi_document . get ( ' tax_line ' , [ ] ) :
account_ids = account_pool . search ( cr , uid , [ ( ' type ' , ' <> ' , ' view ' ) , ( ' type ' , ' <> ' , ' income ' ) , ( ' type ' , ' <> ' , ' closed ' ) ] )
if account_ids :
2011-06-29 05:27:22 +00:00
tax_account = account_pool . browse ( cr , uid , account_ids [ 0 ] )
edi_tax_line [ ' account_id ' ] = self . edi_m2o ( cr , uid , tax_account , context = context ) #TODO should select account of output VAT for Customer Invoice and Input VAT for Supplier Invoice
2011-06-27 12:26:16 +00:00
edi_tax_line [ ' manual ' ] = True
# TODO :=> payment_term: if set, create a default one based on name...
2011-06-28 13:43:26 +00:00
2011-06-27 12:26:16 +00:00
return super ( account_invoice , self ) . edi_import ( cr , uid , edi_document , context = context )
2011-06-21 13:30:26 +00:00
account_invoice ( )
class account_invoice_line ( osv . osv , ir_edi . edi ) :
_inherit = ' account.invoice.line '
account_invoice_line ( )
class account_invoice_tax ( osv . osv , ir_edi . edi ) :
_inherit = " account.invoice.tax "
account_invoice_tax ( )