1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
22 from osv import fields, osv, orm
23 from base.ir import ir_edi
24 from tools.translate import _
26 class account_invoice(osv.osv, ir_edi.edi):
27 _inherit = 'account.invoice'
29 def edi_export(self, cr, uid, records, edi_struct=None, context=None):
30 """Exports a supplier or customer invoice"""
34 'company_id': True, # -> to be changed into partner
35 'type': True, # -> reversed at import
36 'internal_number': True, # -> reference at import
39 'amount_untaxed': True,
46 'address_invoice_id': True, #only one address needed
55 'price_subtotal': True,
71 company_pool = self.pool.get('res.company')
73 for invoice in records:
74 # Get EDI doc based on struct. The result will also contain all metadata fields and attachments.
75 edi_doc = super(account_invoice,self).edi_export(cr, uid, [invoice], edi_struct, context)
80 # Add company info and address
81 edi_company_document = company_pool.edi_export_address(cr, uid, [invoice.company_id], context=context)[invoice.company_id.id]
83 'company_address': edi_company_document['company_address'],
84 #'company_logo': edi_company_document['company_logo'],#TODO
86 edi_doc_list.append(edi_doc)
89 def get_invoice_journal(self, cr, uid, invoice_type, context=None):
92 account_journal_pool = self.pool.get('account.journal')
93 journal_context = context.copy()
94 journal_context.update({'type':invoice_type})
95 journal_id = self._get_journal(cr, uid, context=journal_context)
98 journal = account_journal_pool.browse(cr, uid, journal_id, context=context)
101 def get_tax_account(self, cr, uid, invoice_type='out_invoice', context=None):
102 #TOCHECK: should select account of output VAT for Customer Invoice and Input VAT for Supplier Invoice
103 account_pool = self.pool.get('account.account')
104 account_ids = account_pool.search(cr, uid, [('type','<>','view'),('type','<>','income'), ('type', '<>', 'closed')])
107 tax_account = account_pool.browse(cr, uid, account_ids[0])
110 def get_invoice_account(self, cr, uid, partner_id, invoice_type, context=None):
111 partner_pool = self.pool.get('res.partner')
112 partner = partner_pool.browse(cr, uid, partner_id, context=context)
113 if invoice_type in ('out_invoice', 'out_refund'):
114 invoice_account = partner.property_account_receivable
116 invoice_account = partner.property_account_payable
117 return invoice_account
119 def get_product_account(self, cr, uid, product_id, invoice_type, context=None):
120 product_pool = self.pool.get('product.product')
121 product = product_pool.browse(cr, uid, product_id, context=context)
123 if invoice_type in ('out_invoice','out_refund'):
124 account = product.product_tmpl_id.property_account_income
126 account = product.categ_id.property_account_income_categ
128 account = product.product_tmpl_id.property_account_expense
130 account = product.categ_id.property_account_expense_categ
133 def edi_import_company(self, cr, uid, edi_document, context=None):
134 partner_address_pool = self.pool.get('res.partner.address')
135 partner_pool = self.pool.get('res.partner')
136 company_pool = self.pool.get('res.company')
138 # import company as a new partner, if type==in then supplier=1, else customer=1
139 # company_address data used to add address to new partner
140 invoice_type = edi_document['type']
142 if invoice_type in ('out_invoice', 'in_refund'):
143 partner_value.update({'customer': True})
144 if invoice_type in ('in_invoice', 'out_refund'):
145 partner_value.update({'supplier': True})
146 partner_id = company_pool.edi_import_as_partner(cr, uid, edi_document, values=partner_value, context=context)
148 # partner_id field is modified to point to the new partner
149 res = partner_pool.address_get(cr, uid, [partner_id], ['contact', 'invoice'])
150 address_id = res['invoice']
151 partner = partner_pool.browse(cr, uid, partner_id, context=context)
152 partner_address = partner_address_pool.browse(cr, uid, address_id, context=context)
153 edi_document['partner_id'] = self.edi_m2o(cr, uid, partner, context=context)
154 edi_document['address_invoice_id'] = self.edi_m2o(cr, uid, partner_address, context=context)
155 del edi_document['company_id']
159 def edi_import(self, cr, uid, edi_document, context=None):
160 """ During import, invoices will import the company that is provided in the invoice as
161 a new partner (e.g. supplier company for a customer invoice will be come a supplier
162 record for the new invoice.
163 Summary of tasks that need to be done:
164 - import company as a new partner, if type==in then supplier=1, else customer=1
165 - partner_id field is modified to point to the new partner
166 - company_address data used to add address to new partner
167 - change type: out_invoice'<->'in_invoice','out_refund'<->'in_refund'
168 - reference: should contain the value of the 'internal_number'
169 - reference_type: 'none'
170 - internal number: reset to False, auto-generated
171 - journal_id: should be selected based on type: simply put the 'type'
172 in the context when calling create(), will be selected correctly
173 - payment_term: if set, create a default one based on name...
174 - for invoice lines, the account_id value should be taken from the
175 product's default, i.e. from the default category, as it will not
177 - for tax lines, we disconnect from the invoice.line, so all tax lines
178 will be of type 'manual', and default accounts should be picked based
179 on the tax config of the DB where it is imported.
184 #import company as a new partner
185 partner_id = self.edi_import_company(cr, uid, edi_document, context=context)
187 # change type: out_invoice'<->'in_invoice','out_refund'<->'in_refund'
188 invoice_type = edi_document['type']
189 invoice_type = invoice_type.startswith('in_') and invoice_type.replace('in_','out_') or invoice_type.replace('out_','in_')
190 edi_document['type'] = invoice_type
193 invoice_account = self.get_invoice_account(cr, uid, partner_id, invoice_type, context=context)
194 edi_document['account_id'] = invoice_account and self.edi_m2o(cr, uid, invoice_account, context=context) or False
196 # reference: should contain the value of the 'internal_number'
197 edi_document['reference'] = edi_document.get('internal_number', False)
198 # reference_type: 'none'
199 edi_document['reference_type'] = 'none'
201 # internal number: reset to False, auto-generated
202 edi_document['internal_number'] = False
205 # journal_id: should be selected based on type: simply put the 'type' in the context when calling create(), will be selected correctly
206 journal = self.get_invoice_journal(cr, uid, invoice_type, context=context)
207 edi_document['journal_id'] = journal and self.edi_m2o(cr, uid, journal, context=context) or False
209 # 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.
210 for edi_invoice_line in edi_document.get('invoice_line', []):
211 product_id = edi_invoice_line.get('product_id', False)
214 product_name = product_id and product_id[1]
215 product_id = self.edi_import_relation(cr, uid, 'product.product', product_name, context=context)
216 account = self.get_product_account(cr, uid, product_id, invoice_type, context=context)
217 # TODO: add effect of fiscal position
218 # account = fpos_obj.map_account(cr, uid, fiscal_position_id, account.id)
219 edi_invoice_line['account_id'] = account and self.edi_m2o(cr, uid, account, context=context) or False
221 # 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
222 # on the tax config of the DB where it is imported.
223 for edi_tax_line in edi_document.get('tax_line', []):
224 tax_account = self.get_tax_account(cr, uid, context=context)
226 edi_tax_line['account_id'] = self.edi_m2o(cr, uid, tax_account, context=context)
227 edi_tax_line['manual'] = True
229 # TODO :=> payment_term: if set, create a default one based on name...
230 return super(account_invoice,self).edi_import(cr, uid, edi_document, context=context)
234 class account_invoice_line(osv.osv, ir_edi.edi):
235 _inherit='account.invoice.line'
237 account_invoice_line()
238 class account_invoice_tax(osv.osv, ir_edi.edi):
239 _inherit = "account.invoice.tax"
241 account_invoice_tax()