Merge lp:~camptocamp/new-report-intrastat/5.0-constraint-1317063-gbr into lp:new-report-intrastat

Proposed by Guewen Baconnier @ Camptocamp
Status: Superseded
Proposed branch: lp:~camptocamp/new-report-intrastat/5.0-constraint-1317063-gbr
Merge into: lp:new-report-intrastat
Diff against target: 853 lines (+491/-0) (has conflicts)
10 files modified
intrastat_base/intrastat_demo.xml (+4/-0)
intrastat_base/product.py (+12/-0)
l10n_fr_intrastat_product/intrastat_product.py (+307/-0)
l10n_fr_intrastat_product/intrastat_type.py (+23/-0)
l10n_fr_intrastat_product/product.py (+50/-0)
l10n_fr_intrastat_product/product_view.xml (+13/-0)
l10n_fr_intrastat_product/purchase.py (+14/-0)
l10n_fr_intrastat_product/sale.py (+16/-0)
l10n_fr_intrastat_product/stock.py (+9/-0)
l10n_fr_intrastat_service/intrastat_service.py (+43/-0)
Text conflict in intrastat_base/intrastat_demo.xml
Text conflict in intrastat_base/product.py
Text conflict in l10n_fr_intrastat_product/intrastat_product.py
Text conflict in l10n_fr_intrastat_product/intrastat_type.py
Text conflict in l10n_fr_intrastat_product/product.py
Text conflict in l10n_fr_intrastat_product/purchase.py
Text conflict in l10n_fr_intrastat_product/sale.py
Text conflict in l10n_fr_intrastat_product/stock.py
Text conflict in l10n_fr_intrastat_service/intrastat_service.py
To merge this branch: bzr merge lp:~camptocamp/new-report-intrastat/5.0-constraint-1317063-gbr
Reviewer Review Type Date Requested Status
New report intrastat commiters Pending
Review via email: mp+218603@code.launchpad.net

This proposal has been superseded by a proposal from 2014-05-07.

Description of the change

Fixes lp:1317063

This is a backport from the 7.0 version. I just took the exact same code for the constraint.

To post a comment you must log in.

Unmerged revisions

50. By Guewen Baconnier @ Camptocamp

constraint takes a while to execute because it executes a select on *every* supplierinfo

49. By Alexis de Lattre

Fixes bug 955065 : don't declare DEB lines with value = 0

48. By Alexis de Lattre

Now support weight computation when UoM category is "Unit" and UoM != PCE
Factorize code

47. By Alexis de Lattre

Now manage UoM other than PCE. If the UoM required by the H.S. code is not the UoM of the invoice, it will do the conversion (if possible).
Now possible to have a country of origin on the 'supplier information' instead of on the product form (usefull when the origin of a product depend on the supplier).

46. By Alexis de Lattre

Longer description for HS code.

45. By Alexis de Lattre

Modify help message.

44. By Alexis de Lattre

Comment or remove prints.

43. By Alexis de Lattre

Same modification as my previous commit for DEB : when we sell to a physical person in the EU with VAT, the move is not declared in DEB, so it must not block with a "raise" if the partner doesn't have a VAT number.

42. By Alexis de Lattre

l10n_fr_intrastat_service : Moved the raise if the Partner VAT number is missing, so that, when we sell to a physical person in the EU, we don't get the raise.
Thanks to Anevia for this interesting bug report !
We need to do the same thing in l10n_fr_intrastat_product.

41. By Alexis de Lattre

Translation and strings update.
Add demo data.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'intrastat_base/intrastat_demo.xml'
2--- intrastat_base/intrastat_demo.xml 2013-04-24 08:55:14 +0000
3+++ intrastat_base/intrastat_demo.xml 2014-05-07 12:14:44 +0000
4@@ -13,7 +13,11 @@
5 <field name="vat">FR58441019213</field>
6 </record>
7
8+<<<<<<< TREE
9 <record id="base.res_partner_8" model="res.partner"> <!-- MediaPole -->
10+=======
11+<record id="base.res_partner_6" model="res.partner"> <!-- Elec Import -->
12+>>>>>>> MERGE-SOURCE
13 <field name="vat">BE0828696437</field>
14 <field name="supplier">True</field>
15 </record>
16
17=== modified file 'intrastat_base/product.py'
18--- intrastat_base/product.py 2014-04-14 14:32:08 +0000
19+++ intrastat_base/product.py 2014-05-07 12:14:44 +0000
20@@ -27,6 +27,7 @@
21 class product_template(orm.Model):
22 _inherit = "product.template"
23 _columns = {
24+<<<<<<< TREE
25 'exclude_from_intrastat': fields.boolean(
26 'Exclude from Intrastat reports',
27 help="If set to True, the product or service will not be "
28@@ -60,3 +61,14 @@
29 (_check_accessory_cost, "Error msg is in raise",
30 ['is_accessory_cost', 'type'])
31 ]
32+=======
33+ 'exclude_from_intrastat': fields.boolean('Exclude from Intrastat reports', help="If set to True, the product or service will not be taken into account for Intrastat Product or Service reports. So you should leave this field to False unless you have a very good reason."),
34+ }
35+
36+ _default = {
37+ 'exclude_from_intrastat': lambda *a: False,
38+ }
39+
40+product_template()
41+
42+>>>>>>> MERGE-SOURCE
43
44=== modified file 'l10n_fr_intrastat_product/intrastat_product.py'
45--- l10n_fr_intrastat_product/intrastat_product.py 2014-04-14 17:41:39 +0000
46+++ l10n_fr_intrastat_product/intrastat_product.py 2014-05-07 12:14:44 +0000
47@@ -184,6 +184,7 @@
48 ('date_uniq', 'unique(start_date, company_id, type)', 'A DEB of the same type already exists for this month !'),
49 ]
50
51+<<<<<<< TREE
52 def create_intrastat_product_lines(
53 self, cr, uid, ids, intrastat, invoice, parent_values,
54 context=None):
55@@ -209,13 +210,60 @@
56 uom_model, pce_uom_id = data_obj.get_object_reference(
57 cr, uid, 'product', 'product_uom_unit')
58 assert uom_model == 'product.uom', 'Wrong model uom'
59+=======
60+ def _get_id_from_xmlid(self, cr, uid, module, xml_id, model_name, context=None):
61+ irdata_obj = self.pool.get('ir.model.data')
62+ ir_data_id = irdata_obj._get_id(cr, uid, module, xml_id)
63+ if ir_data_id:
64+ res_id = irdata_obj.read(cr, uid, ir_data_id, ['res_id'], context=context)['res_id']
65+ else:
66+ raise osv.except_osv(_('Error :'), 'Hara kiri %s in _get_id_from_xmlid' % xml_id)
67+ return res_id
68+
69+ def create_intrastat_product_lines(self, cr, uid, ids, intrastat, parent_obj, parent_values, context=None):
70+ #print "create_intrastat_product_line ids=", ids
71+
72+ if len(ids) != 1: raise osv.except_osv(_('Error :'), 'Hara kiri in build_intrastat_product_line')
73+ line_obj = self.pool.get('report.intrastat.product.line')
74+
75+ weight_uom_categ_id = self._get_id_from_xmlid(cr, uid, 'product', 'product_uom_categ_kgm', 'product.uom.categ', context=context)
76+
77+ kg_uom_id = self._get_id_from_xmlid(cr, uid, 'product', 'product_uom_kgm', 'product.uom', context=context)
78+
79+ pce_uom_categ_id = self._get_id_from_xmlid(cr, uid, 'product', 'product_uom_categ_unit', 'product.uom.categ', context=context)
80+
81+ pce_uom_id = self._get_id_from_xmlid(cr, uid, 'product', 'product_uom_unit', 'product.uom', context=context)
82+
83+ if parent_obj._name == 'account.invoice':
84+ src = 'invoice'
85+ browse_on = parent_obj.invoice_line
86+ parent_name = parent_obj.number
87+ product_line_ref_field = 'invoice_id'
88+ elif parent_obj._name == 'stock.picking':
89+ src = 'picking'
90+ browse_on = parent_obj.move_lines
91+ parent_name = parent_obj.name
92+ product_line_ref_field = 'picking_id'
93+ else: raise osv.except_osv(_('Error :'), 'The function build_intrastat_product_lines() should have parent_obj as invoice or picking')
94+>>>>>>> MERGE-SOURCE
95
96 lines_to_create = []
97+<<<<<<< TREE
98 total_invoice_cur_accessory_cost = 0.0
99 total_invoice_cur_product_value = 0.0
100 for line in invoice.invoice_line:
101 line_qty = line.quantity
102 source_uom = line.uos_id
103+=======
104+ for line in browse_on:
105+ if src == 'invoice':
106+ line_qty = line.quantity
107+ source_uom = line.uos_id
108+ elif src == 'picking':
109+ line_qty = line.product_qty
110+ source_uom = line.product_uom
111+ # We don't do anything when there is no product_id... this may be a problem...
112+>>>>>>> MERGE-SOURCE
113
114 # We don't do anything when there is no product_id...
115 # this may be a problem... but i think a raise would be too violent
116@@ -227,6 +275,7 @@
117
118 if not line_qty:
119 continue
120+<<<<<<< TREE
121
122 # If type = "service" and is_accessory_cost=True, then we keep
123 # the line (it will be skipped later on)
124@@ -247,6 +296,33 @@
125 amount_product_value_inv_cur_to_write = line.price_subtotal
126 total_invoice_cur_product_value += line.price_subtotal
127 invoice_currency_id_to_write = invoice.currency_id.id
128+=======
129+
130+ if src == 'invoice':
131+ skip_this_line = False
132+ for line_tax in line.invoice_line_tax_id:
133+ if line_tax.exclude_from_intrastat_if_present:
134+ skip_this_line = True
135+ if skip_this_line:
136+ continue
137+ amount_invoice_currency_to_write = line.price_subtotal
138+ invoice_currency_id_to_write = parent_obj.currency_id.id
139+ if parent_obj.currency_id.code <> 'EUR':
140+ context['date'] = parent_obj.date_invoice
141+# TODO : add invoice_currency, also in add loop, WARN picking
142+ amount_company_currency_to_write = self.pool.get('res.currency').compute(cr, uid, parent_obj.currency_id.id, intrastat.company_id.currency_id.id, line.price_subtotal, context=context)
143+ else:
144+ amount_company_currency_to_write = line.price_subtotal
145+ elif src == 'picking':
146+ invoice_currency_id_to_write = False
147+ amount_invoice_currency_to_write = False
148+ unit_stat_price = self.pool.get('product.pricelist').price_get(cr, uid, [intrastat.company_id.statistical_pricelist_id.id], line.product_id.id, 1.0)[intrastat.company_id.statistical_pricelist_id.id]
149+ if not unit_stat_price:
150+ raise osv.except_osv(_('Error :'), _("The Pricelist for statistical value '%s' that is set for the company '%s' gives a price of 0 for the product '%s'.") %(intrastat.company_id.statistical_pricelist_id.name, intrastat.company_id.name, line.product_id.name))
151+ else:
152+ amount_company_currency_to_write = unit_stat_price * line_qty
153+ #print "amount_company_currency_to_write =", amount_company_currency_to_write
154+>>>>>>> MERGE-SOURCE
155
156 if not parent_values['is_fiscal_only']:
157
158@@ -255,6 +331,7 @@
159 else:
160 source_uom_id_to_write = source_uom.id
161
162+<<<<<<< TREE
163 if source_uom.id == kg_uom_id:
164 weight_to_write = line_qty
165 elif source_uom.category_id.id == weight_uom_categ_id:
166@@ -276,6 +353,29 @@
167 else:
168 raise orm.except_orm(_('Error :'), _("Conversion from unit of measure '%s' to 'Kg' is not implemented yet.") % (source_uom.name))
169
170+=======
171+ if source_uom.id == kg_uom_id:
172+ weight_to_write = line_qty
173+ elif source_uom.category_id.id == weight_uom_categ_id:
174+ dest_uom_kg = self.pool.get('product.uom').browse(cr, uid,
175+ kg_uom_id, context=context)
176+ weight_to_write = self.pool.get('product.uom')._compute_qty_obj(cr, uid,
177+ source_uom, line_qty, dest_uom_kg, context=context)
178+ elif source_uom.category_id.id == pce_uom_categ_id:
179+ if not line.product_id.weight_net:
180+ raise osv.except_osv(_('Error :'), _("Missing net weight on product '%s'.") %(line.product_id.name))
181+ if source_uom.id == pce_uom_id:
182+ weight_to_write = line.product_id.weight_net * line_qty
183+ else:
184+ dest_uom_pce = self.pool.get('product.uom').browse(cr, uid,
185+ pce_uom_id, context=context)
186+ # Here, I suppose that, on the product, the weight is per PCE and not per uom_id
187+ weight_to_write = line.product_id.weight_net * self.pool.get('product.uom')._compute_qty_obj(cr, uid, source_uom, line_qty, dest_uom_pce, context=context)
188+
189+ else:
190+ raise osv.except_osv(_('Error :'), _("Conversion from unit of measure '%s' to 'Kg' is not implemented yet.") %(source_uom.name))
191+
192+>>>>>>> MERGE-SOURCE
193 product_intrastat_code = line.product_id.intrastat_id
194 if not product_intrastat_code:
195 # If the H.S. code is not set on the product, we check if it's set
196@@ -295,6 +395,7 @@
197 quantity_to_write = False
198 else:
199 intrastat_uom_id_to_write = product_intrastat_code.intrastat_uom_id.id
200+<<<<<<< TREE
201 if intrastat_uom_id_to_write == source_uom_id_to_write:
202 quantity_to_write = line_qty
203 elif source_uom.category_id == product_intrastat_code.intrastat_uom_id.category_id:
204@@ -303,6 +404,16 @@
205 product_intrastat_code.intrastat_uom_id, context=context)
206 else:
207 raise orm.except_orm(_('Error :'), _("On invoice '%s', the line with product '%s' has a unit of measure (%s) which can't be converted to UoM of it's intrastat code (%s).") % (invoice.number, line.product_id.name, source_uom_id_to_write, intrastat_uom_id_to_write))
208+=======
209+ if intrastat_uom_id_to_write == source_uom_id_to_write:
210+ quantity_to_write = line_qty
211+ elif source_uom.category_id == product_intrastat_code.intrastat_uom_id.category_id:
212+ quantity_to_write = self.pool.get('product.uom')._compute_qty_obj(cr,
213+ uid, source_uom, line_qty,
214+ product_intrastat_code.intrastat_uom_id, context=context)
215+ else:
216+ raise osv.except_osv(_('Error :'), _("On %s '%s', the line with product '%s' has a unit of measure (%s) which can't be converted to UoM of it's intrastat code (%s).") %(src, parent_name, line.product_id.name, source_uom_id_to_write, intrastat_uom_id_to_write))
217+>>>>>>> MERGE-SOURCE
218
219 # The origin country should only be declated on Import
220 if intrastat.type == 'export':
221@@ -310,6 +421,7 @@
222 elif line.product_id.country_id:
223 # If we have the country of origin on the product -> take it
224 product_country_origin_id_to_write = line.product_id.country_id.id
225+<<<<<<< TREE
226 else:
227 # If we don't, look on the product supplier info
228 origin_partner_id = parent_values.get('origin_partner_id', False)
229@@ -332,6 +444,31 @@
230 raise orm.except_orm(_('Error :'),
231 _("Missing country of origin on product '%s' (it's not possible to get the country of origin from the 'supplier information' in this case because we don't know the supplier of this product for the invoice '%s').")
232 % (line.product_id.name, invoice.number))
233+=======
234+ else:
235+ # If we don't, look on the product supplier info
236+ # We only have parent_values['origin_partner_id'] when src = invoice
237+ origin_partner_id = parent_values.get('origin_partner_id', False)
238+ if origin_partner_id:
239+ supplieri_obj = self.pool.get('product.supplierinfo')
240+ supplier_ids = supplieri_obj.search(cr, uid, [
241+ ('name', '=', origin_partner_id),
242+ ('product_id', '=', line.product_id.id),
243+ ('origin_country_id', '!=', 'null')
244+ ], context=context)
245+ if not supplier_ids:
246+ raise osv.except_osv(_('Error :'),
247+ _("Missing country of origin on product '%s' or on it's supplier information for partner '%s'.")
248+ %(line.product_id.name, parent_values.get('origin_partner_name', 'none')))
249+ else:
250+ product_country_origin_id_to_write = supplieri_obj.read(cr, uid,
251+ supplier_ids[0], ['origin_country_id'],
252+ context=context)['origin_country_id'][0]
253+ else:
254+ raise osv.except_osv(_('Error :'),
255+ _("Missing country of origin on product '%s' (it's not possible to get the country of origin from the 'supplier information' in this case because we don't know the supplier of this product for the %s '%s').")
256+ %(line.product_id.name, src, parent_name))
257+>>>>>>> MERGE-SOURCE
258
259 else:
260 weight_to_write = False
261@@ -356,7 +493,11 @@
262 line_to_create['weight'] += weight_to_write
263 line_to_create['amount_product_value_inv_cur'] += amount_product_value_inv_cur_to_write
264 break
265+<<<<<<< TREE
266 if create_new_line:
267+=======
268+ if create_new_line == True:
269+>>>>>>> MERGE-SOURCE
270 lines_to_create.append({
271 'parent_id': ids[0],
272 'invoice_id': invoice.id,
273@@ -378,6 +519,7 @@
274 'amount_product_value_inv_cur': amount_product_value_inv_cur_to_write,
275 'is_fiscal_only': parent_values['is_fiscal_only'],
276 })
277+<<<<<<< TREE
278 # End of the loop on invoice lines
279
280 # Why do I manage the Partner VAT number only here and not earlier
281@@ -406,8 +548,39 @@
282 parent_values['partner_vat_to_write'] = invoice.partner_id.vat
283 else:
284 parent_values['partner_vat_to_write'] = False
285+=======
286+ # End of the loop on invoice/picking lines
287+
288+ # Why do I manage the Partner VAT number only here and not earlier in the code ?
289+ # Because, if I sell to a physical person in the EU with VAT, then
290+ # the corresponding partner will not have a VAT number, and the entry
291+ # will be skipped because line_tax.exclude_from_intrastat_if_present is always True
292+ # So we should not block with a raise before the end of the loop on the
293+ # invoice/picking lines
294+ if lines_to_create:
295+ if parent_values['is_vat_required']:
296+ if src <> 'invoice':
297+ raise osv.except_osv(_('Error :'), "We can't have such an intrastat type in a repair picking.")
298+ # If I have invoice.intrastat_country_id and the invoice address
299+ # is outside the EU, then I look for the fiscal rep of the partner
300+ if parent_obj.intrastat_country_id and not parent_obj.address_invoice_id.country_id.intrastat:
301+ if not parent_obj.partner_id.intrastat_fiscal_representative:
302+ raise osv.except_osv(_('Error :'), _("Missing fiscal representative for partner '%s'. It is required for invoice '%s' which has an invoice address outside the EU but the goods were delivered to or received from inside the EU.") % (parent_obj.partner_id.name, parent_obj.number))
303+ else:
304+ parent_values['partner_vat_to_write'] = parent_obj.partner_id.intrastat_fiscal_representative.vat
305+ # Otherwise, I just read the vat number on the partner of the invoice
306+ else:
307+
308+ if not parent_obj.partner_id.vat:
309+ raise osv.except_osv(_('Error :'), _("Missing VAT number on partner '%s'.") %parent_obj.partner_id.name)
310+ else:
311+ parent_values['partner_vat_to_write'] = parent_obj.partner_id.vat
312+ else:
313+ parent_values['partner_vat_to_write'] = False
314+>>>>>>> MERGE-SOURCE
315
316 for line_to_create in lines_to_create:
317+<<<<<<< TREE
318 line_to_create['partner_vat'] = parent_values['partner_vat_to_write']
319
320 if not total_invoice_cur_accessory_cost:
321@@ -437,8 +610,17 @@
322 # p20 of the BOD : lines with value rounded to 0 mustn't be declared
323 continue
324 for value in ['quantity', 'weight']: # These 2 fields are char
325+=======
326+ line_to_create['partner_vat'] = parent_values['partner_vat_to_write']
327+ line_to_create['amount_company_currency'] = int(round(line_to_create['amount_company_currency']))
328+ if line_to_create['amount_company_currency'] == 0:
329+ # p20 of the BOD : lines with value rounded to 0 mustn't be declared
330+ continue
331+ for value in ['quantity', 'weight']: # These 2 fields are char
332+>>>>>>> MERGE-SOURCE
333 if line_to_create[value]:
334 line_to_create[value] = str(int(round(line_to_create[value], 0)))
335+ line_to_create['amount_invoice_currency'] = int(round(line_to_create['amount_invoice_currency']))
336 line_obj.create(cr, uid, line_to_create, context=context)
337
338 return True
339@@ -488,10 +670,25 @@
340 intrastat = self.browse(cr, uid, ids[0], context=context)
341 self.pool.get('report.intrastat.common')._check_generate_lines(cr, uid, intrastat, context=context)
342 line_obj = self.pool.get('report.intrastat.product.line')
343+<<<<<<< TREE
344 line_remove_ids = line_obj.search(cr, uid, [('parent_id', '=', ids[0]), ('invoice_id', '!=', False)], context=context)
345+=======
346+ line_remove_ids = line_obj.search(cr, uid, [('parent_id', '=', ids[0]), (field, '!=', False)], context=context)
347+ #print "line_remove_ids = ", line_remove_ids
348+>>>>>>> MERGE-SOURCE
349 if line_remove_ids:
350 line_obj.unlink(cr, uid, line_remove_ids, context=context)
351
352+<<<<<<< TREE
353+=======
354+
355+ def generate_product_lines_from_invoice(self, cr, uid, ids, context=None):
356+ #print "generate lines, ids=", ids
357+ intrastat = self.browse(cr, uid, ids[0], context=context)
358+ self.pool.get('report.intrastat.common')._check_generate_lines(cr, uid, intrastat, context=context)
359+ self.remove_intrastat_product_lines(cr, uid, ids, 'invoice_id', context=context)
360+
361+>>>>>>> MERGE-SOURCE
362 invoice_obj = self.pool.get('account.invoice')
363 invoice_type = False
364 if intrastat.type == 'import':
365@@ -557,23 +754,122 @@
366 else:
367 parent_values['intrastat_type_id_to_write'] = invoice.intrastat_type_id.id
368
369+<<<<<<< TREE
370 if invoice.intrastat_country_id and not invoice.partner_id.country_id.intrastat and invoice.partner_id.intrastat_fiscal_representative:
371+=======
372+ if invoice.intrastat_country_id and not invoice.address_invoice_id.country_id.intrastat and invoice.partner_id.intrastat_fiscal_representative:
373+>>>>>>> MERGE-SOURCE
374 # fiscal rep
375 parent_values['partner_id_to_write'] = invoice.partner_id.intrastat_fiscal_representative.id
376 else:
377 parent_values['partner_id_to_write'] = invoice.partner_id.id
378
379+<<<<<<< TREE
380 # Get partner on which we will check the 'country of origin' on product_supplierinfo
381 parent_values['origin_partner_id'] = invoice.partner_id.id
382 parent_values['origin_partner_name'] = invoice.partner_id.name
383
384 parent_values = self.compute_invoice_values(cr, uid, intrastat, invoice, parent_values, context=context)
385
386+=======
387+ # Get partner on which we will check the 'country of origin' on product_supplierinfo
388+ parent_values['origin_partner_id'] = invoice.partner_id.id
389+ parent_values['origin_partner_name'] = invoice.partner_id.name
390+
391+ parent_values = self.common_compute_invoice_picking(cr, uid, intrastat, invoice, parent_values, context=context)
392+
393+>>>>>>> MERGE-SOURCE
394 self.create_intrastat_product_lines(cr, uid, ids, intrastat, invoice, parent_values, context=context)
395
396 return True
397
398
399+<<<<<<< TREE
400+=======
401+
402+ def generate_product_lines_from_picking(self, cr, uid, ids, context=None):
403+ '''Function used to have the DEB lines corresponding to repairs'''
404+ #print "generate_product_lines_from_picking ids=", ids
405+ intrastat = self.browse(cr, uid, ids[0], context=context)
406+ self.pool.get('report.intrastat.common')._check_generate_lines(cr, uid, intrastat, context=context)
407+ # not needed when type = export and oblig_level = simplified, cf p26 du BOD
408+ if intrastat.type == 'export' and intrastat.obligation_level == 'simplified':
409+ raise osv.except_osv(_('Error :'), _("You don't need to get lines from picking for an export DEB in 'Simplified' obligation level."))
410+
411+ # Remove existing lines
412+ self.remove_intrastat_product_lines(cr, uid, ids, 'picking_id', context=context)
413+
414+ # Check pricelist for stat value
415+ if not intrastat.company_id.statistical_pricelist_id:
416+ raise osv.except_osv(_('Error :'), _("You must select a 'Pricelist for statistical value' for the company %s.") %intrastat.company_id.name)
417+ elif intrastat.company_id.statistical_pricelist_id.currency_id.code <> 'EUR':
418+ raise osv.except_osv(_('Error :'), _("The 'Pricelist for statistical value' that you selected (%s) for the company '%s' is in %s currency and should be in EUR.") %(intrastat.company_id.statistical_pricelist_id.name, intrastat.company_id.name, intrastat.company_id.statistical_pricelist_id.currency_id.code))
419+
420+ pick_obj = self.pool.get('stock.picking')
421+ pick_type = False
422+ exclude_field = False
423+ if intrastat.type == 'import':
424+ pick_type = 'in'
425+ exclude_field = 'purchase_id'
426+ if intrastat.type == 'export':
427+ pick_type = 'out'
428+ exclude_field = 'sale_id'
429+ # TODO : add criteria on company !!!
430+ picking_ids = pick_obj.search(cr, uid, [
431+ ('type', '=', pick_type),
432+ ('date_done', '<=', intrastat.end_date),
433+ ('date_done', '>=', intrastat.start_date),
434+ ('invoice_state', '=', 'none'),
435+ (exclude_field, '=', False),
436+ ('state', 'not in', ('draft', 'waiting', 'confirmed', 'assigned', 'cancel'))
437+ ], order='date_done', context=context)
438+ #print "picking_ids =", picking_ids
439+ for picking in pick_obj.browse(cr, uid, picking_ids, context=context):
440+ parent_values = {}
441+ #print "PICKING =", picking.name
442+ if not picking.address_id:
443+ continue
444+
445+ if not picking.address_id.country_id:
446+ raise osv.except_osv(_('Error :'), _("Missing country on partner address '%s' used on picking '%s'.") %(picking.address_id.name, picking.name))
447+ elif not picking.address_id.country_id.intrastat:
448+ continue
449+ else:
450+ parent_values['partner_country_id_to_write'] = picking.address_id.country_id.id
451+
452+
453+ if not picking.address_id.partner_id:
454+ raise osv.except_osv(_('Error :'), _("Partner address '%s' used on picking '%s' is not linked to a partner !") %(move_line.address_id.name, picking.name))
455+ else:
456+ parent_values['partner_id_to_write'] = picking.address_id.partner_id.id
457+
458+ # TODO : check = 29 /19 ???
459+ if not picking.intrastat_type_id:
460+ if picking.type == 'out':
461+ if intrastat.company_id.default_intrastat_type_out_picking:
462+ parent_values['intrastat_type_id_to_write'] = intrastat.company_id.default_intrastat_type_out_picking.id
463+ else:
464+ raise osv.except_osv(_('Error :'), _("The intrastat type hasn't been set on picking '%s' and the 'default intrastat type for outgoing products' is missing for the company '%s'.") %(picking.name, intrastat.company_id.name))
465+ elif picking.type == 'in':
466+ if intrastat.company_id.default_intrastat_type_in_picking:
467+ parent_values['intrastat_type_id_to_write'] = intrastat.company_id.default_intrastat_type_in_picking.id
468+ else:
469+ raise osv.except_osv(_('Error :'), _("The intrastat type hasn't been set on picking '%s' and the 'default intrastat type for incoming products' is missing for the company '%s'.") %(picking.name, intrastat.company_id.name))
470+ else: raise osv.except_osv(_('Error :'), "Hara kiri... we can't arrive here")
471+ else:
472+ parent_values['intrastat_type_id_to_write'] = picking.intrastat_type_id.id
473+
474+
475+ parent_values = self.common_compute_invoice_picking(cr, uid, intrastat, picking, parent_values, context=context)
476+
477+ self.create_intrastat_product_lines(cr, uid, ids, intrastat, picking, parent_values, context=context)
478+
479+ return True
480+
481+
482+
483+
484+>>>>>>> MERGE-SOURCE
485 def done(self, cr, uid, ids, context=None):
486 assert len(ids) == 1, "Only one ID accepted"
487 self.write(cr, uid, ids[0], {'state': 'done'}, context=context)
488@@ -587,6 +883,12 @@
489
490 def generate_xml(self, cr, uid, ids, context=None):
491 '''Generate the INSTAT XML file export.'''
492+<<<<<<< TREE
493+=======
494+ #print "generate_xml ids=", ids
495+ from lxml import etree
496+ import deb_xsd
497+>>>>>>> MERGE-SOURCE
498 intrastat = self.browse(cr, uid, ids[0], context=context)
499 start_date_str = intrastat.start_date
500 end_date_str = intrastat.end_date
501@@ -653,8 +955,13 @@
502 # THEN, the fields which vary from a line to the next
503 line = 0
504 for pline in intrastat.intrastat_line_ids:
505+<<<<<<< TREE
506 line += 1 # increment line number
507 #print "line =", line
508+=======
509+ line += 1 #increment line number
510+ #print "line =", line
511+>>>>>>> MERGE-SOURCE
512 try: intrastat_type = self.pool.get('report.intrastat.type').read(cr, uid, pline.intrastat_type_id.id, ['is_fiscal_only'], context=context)
513 except: raise orm.except_orm(_('Error :'), "Missing Intrastat type id on line %d." %line)
514 item = etree.SubElement(declaration, 'Item')
515
516=== modified file 'l10n_fr_intrastat_product/intrastat_type.py'
517--- l10n_fr_intrastat_product/intrastat_type.py 2014-04-14 22:11:40 +0000
518+++ l10n_fr_intrastat_product/intrastat_type.py 2014-05-07 12:14:44 +0000
519@@ -57,10 +57,33 @@
520
521 def _compute_all(self, cr, uid, ids, name, arg, context=None):
522 result = {}
523+<<<<<<< TREE
524 for intr_type in self.read(
525 cr, uid, ids, ['id', 'procedure_code'], context=context):
526 result[intr_type['id']] = self._compute_readonly_fields(
527 cr, uid, intr_type['procedure_code'], context=context)
528+=======
529+ for intr_type in self.read(cr, uid, ids, ['id', 'procedure_code'], context=context):
530+ result[intr_type['id']] = {}
531+ if intr_type['procedure_code'] in ('19', '29'):
532+ result[intr_type['id']]['fiscal_value_multiplier'] = 0
533+ elif intr_type['procedure_code'] == '25':
534+ result[intr_type['id']]['fiscal_value_multiplier'] = -1
535+ else:
536+ result[intr_type['id']]['fiscal_value_multiplier'] = 1
537+ if intr_type['procedure_code'] in fiscal_only_tuple:
538+ result[intr_type['id']]['is_fiscal_only'] = True
539+ else:
540+ result[intr_type['id']]['is_fiscal_only'] = False
541+ if intr_type['procedure_code'] in ('11', '19', '29'):
542+ result[intr_type['id']]['is_vat_required'] = False
543+ else:
544+ result[intr_type['id']]['is_vat_required'] = True
545+ if intr_type['procedure_code'] in ('11', '19'):
546+ result[intr_type['id']]['intrastat_product_type'] = 'import'
547+ else:
548+ result[intr_type['id']]['intrastat_product_type'] = 'export'
549+>>>>>>> MERGE-SOURCE
550 return result
551
552 _columns = {
553
554=== modified file 'l10n_fr_intrastat_product/product.py'
555--- l10n_fr_intrastat_product/product.py 2014-04-14 17:41:39 +0000
556+++ l10n_fr_intrastat_product/product.py 2014-05-07 12:14:44 +0000
557@@ -30,6 +30,7 @@
558 _description = "Intrastat code"
559 _order = "name"
560 _columns = {
561+<<<<<<< TREE
562 'name': fields.char(
563 'H.S. code', size=16, required=True,
564 help="Full lenght H.S. code"),
565@@ -47,6 +48,12 @@
566 help="Select the unit of measure if one is required for "
567 "this particular intrastat code (other than the weight in Kg). "
568 "If no particular unit of measure is required, leave empty."),
569+=======
570+ 'name': fields.char('H.S. code', size=16, required=True, help="Full lenght H.S. code"),
571+ 'description': fields.char('Description', size=255, help='Short text description of the H.S. category'),
572+ 'intrastat_code': fields.char('Intrastat code for DEB', size=9, required=True, help="H.S. code used for the DEB in France. Must be part of the 'Nomenclature combinée' (NC) with 8 digits with sometimes a 9th digit for the 'Nomenclature Générale des Produits' (NGP)."),
573+ 'intrastat_uom_id': fields.many2one('product.uom', 'UoM for intrastat product report', help="Select the unit of measure if one is required for this particular intrastat code (other than the weight in Kg). If no particular unit of measure is required, leave empty."),
574+>>>>>>> MERGE-SOURCE
575 }
576
577 def name_get(self, cr, uid, ids, context=None):
578@@ -103,6 +110,7 @@
579 class product_template(orm.Model):
580 _inherit = "product.template"
581 _columns = {
582+<<<<<<< TREE
583 'intrastat_id': fields.many2one(
584 'report.intrastat.code', 'Intrastat code',
585 help="Code from the Harmonised System. Nomenclature is "
586@@ -123,6 +131,19 @@
587
588
589 class product_category(orm.Model):
590+=======
591+ 'intrastat_id': fields.many2one('report.intrastat.code', 'Intrastat code', help="Code from the Harmonised System. Nomenclature is available from the World Customs Organisation, see http://www.wcoomd.org/. Some countries have made their own extensions to this nomenclature."),
592+ 'country_id' : fields.many2one('res.country', 'Country of origin',
593+ help="Country of origin of the product i.e. product 'made in ____'. If you have different countries of origin depending on the supplier from which you purchased the product, leave this field empty and use the equivalent field on the 'product supplier info' form."),
594+ # This field should be called origin_country_id, but it's named country_id to keep "compatibility with OpenERP users that used the "report_intrastat" module
595+
596+ }
597+
598+product_template()
599+
600+
601+class product_category(osv.osv):
602+>>>>>>> MERGE-SOURCE
603 _inherit = "product.category"
604 _columns = {
605 'intrastat_id': fields.many2one(
606@@ -132,6 +153,7 @@
607 "related product category."),
608 }
609
610+<<<<<<< TREE
611
612 class product_supplierinfo(orm.Model):
613 _inherit = "product.supplierinfo"
614@@ -176,3 +198,31 @@
615 "error msg in raise",
616 ['origin_country_id', 'name', 'product_id']
617 )]
618+=======
619+product_category()
620+
621+
622+class product_supplierinfo(osv.osv):
623+ _inherit = "product.supplierinfo"
624+ _columns = {
625+ 'origin_country_id' : fields.many2one('res.country', 'Country of origin',
626+ help="Country of origin of the product (i.e. product 'made in ____') when purchased from this supplier. This field is used only when the equivalent field on the product form is empty."),
627+ }
628+
629+ def _same_supplier_same_origin(self, cr, uid, ids):
630+ """Products from the same supplier should have the same origin"""
631+ for supplierinfo in self.browse(cr, uid, ids):
632+ country_origin_id = supplierinfo.origin_country_id.id
633+ # Search for same supplier and same product
634+ same_product_same_supplier_ids = self.search(cr, uid, [('product_id', '=', supplierinfo.product_id.id), ('name', '=', supplierinfo.name.id)])
635+ # 'name' on product_supplierinfo is a many2one to res.partner
636+ for supplieri in self.browse(cr, uid, same_product_same_supplier_ids):
637+ if country_origin_id != supplieri.origin_country_id.id:
638+ raise orm.except_orm(_('Error !'), _("For a particular product, all supplier info entries with the same supplier should have the same country of origin. But, for product '%s' with supplier '%s', there is one entry with country of origin '%s' and another entry with country of origin '%s'.") % (supplieri.product_id.name, supplieri.name.name, supplierinfo.origin_country_id.name, supplieri.origin_country_id.name))
639+ return True
640+
641+ _constraints = [
642+ (_same_supplier_same_origin, "error msg in raise", ['origin_country_id', 'name', 'product_id'])]
643+
644+product_supplierinfo()
645+>>>>>>> MERGE-SOURCE
646
647=== modified file 'l10n_fr_intrastat_product/product_view.xml'
648--- l10n_fr_intrastat_product/product_view.xml 2014-04-14 21:42:39 +0000
649+++ l10n_fr_intrastat_product/product_view.xml 2014-05-07 12:14:44 +0000
650@@ -47,6 +47,19 @@
651 </field>
652 </record>
653
654+<!-- Add field on product.supplierinfo -->
655+<record id="fr_intrastat_product_supplierinfo_form" model="ir.ui.view">
656+ <field name="name">fr.intrastat.product.product.supplierinfo.form</field>
657+ <field name="model">product.supplierinfo</field>
658+ <field name="type">form</field>
659+ <field name="inherit_id" ref="product.product_supplierinfo_form_view"/>
660+ <field name="arch" type="xml">
661+ <field name="product_code" position="after">
662+ <field name="origin_country_id" />
663+ </field>
664+ </field>
665+</record>
666+
667 <!-- Add intrastat_id on Product category -->
668 <record id="fr_intrastat_product_category_form" model="ir.ui.view">
669 <field name="name">fr.intrastat.product.category.form</field>
670
671=== modified file 'l10n_fr_intrastat_product/purchase.py'
672--- l10n_fr_intrastat_product/purchase.py 2014-04-14 17:41:39 +0000
673+++ l10n_fr_intrastat_product/purchase.py 2014-05-07 12:14:44 +0000
674@@ -26,6 +26,7 @@
675 class purchase_order(orm.Model):
676 _inherit = "purchase.order"
677
678+<<<<<<< TREE
679 def action_invoice_create(self, cr, uid, ids, context=None):
680 '''Copy country of partner_id =("origin country") and '''
681 '''arrival department on invoice'''
682@@ -42,4 +43,17 @@
683 purchase.picking_ids[0].intrastat_department
684 self.pool['account.invoice'].write(
685 cr, uid, rel_invoice.id, dico_write, context=context)
686+=======
687+ def action_invoice_create(self, cr, uid, ids, *args):
688+ '''Copy country of partner_address_id =("origin country") and arrival department on invoice'''
689+ res = super(purchase_order,self).action_invoice_create(cr, uid, ids, *args)
690+ for purchase in self.browse(cr, uid, ids):
691+ dico_write = {}
692+ if purchase.partner_address_id and purchase.partner_address_id.country_id:
693+ dico_write['intrastat_country_id'] = purchase.partner_address_id.country_id.id
694+ if purchase.picking_ids:
695+ dico_write['intrastat_department'] = purchase.picking_ids[0].intrastat_department
696+ # invoice_id many2one -> invoice_ids many2many on v6 -> same code as sale.py
697+ self.pool.get('account.invoice').write(cr, uid, purchase.invoice_id.id, dico_write)
698+>>>>>>> MERGE-SOURCE
699 return res
700
701=== modified file 'l10n_fr_intrastat_product/sale.py'
702--- l10n_fr_intrastat_product/sale.py 2014-04-14 17:41:39 +0000
703+++ l10n_fr_intrastat_product/sale.py 2014-05-07 12:14:44 +0000
704@@ -28,6 +28,7 @@
705
706 def _prepare_invoice(self, cr, uid, order, lines, context=None):
707 '''Copy destination country and departure department on invoice'''
708+<<<<<<< TREE
709 invoice_vals = super(sale_order, self)._prepare_invoice(
710 cr, uid, order, lines, context=context)
711 if order.partner_shipping_id and order.partner_shipping_id.country_id:
712@@ -37,3 +38,18 @@
713 invoice_vals['intrastat_department'] = \
714 order.picking_ids[0].intrastat_department
715 return invoice_vals
716+=======
717+ res = super(sale_order,self).action_invoice_create(cr, uid, ids, grouped, states)
718+ for sale in self.browse(cr, uid, ids):
719+ for rel_invoice in sale.invoice_ids:
720+ dico_write = {}
721+ if sale.partner_shipping_id and sale.partner_shipping_id.country_id:
722+ dico_write['intrastat_country_id'] = sale.partner_shipping_id.country_id.id
723+ if sale.picking_ids:
724+ dico_write['intrastat_department'] = sale.picking_ids[0].intrastat_department
725+ self.pool.get('account.invoice').write(cr, uid, rel_invoice.id, dico_write)
726+ return res
727+
728+sale_order()
729+
730+>>>>>>> MERGE-SOURCE
731
732=== modified file 'l10n_fr_intrastat_product/stock.py'
733--- l10n_fr_intrastat_product/stock.py 2014-04-14 17:41:39 +0000
734+++ l10n_fr_intrastat_product/stock.py 2014-05-07 12:14:44 +0000
735@@ -72,11 +72,20 @@
736 continue
737 else:
738 break
739+<<<<<<< TREE
740+=======
741+ #print "_compute_department result=", result
742+>>>>>>> MERGE-SOURCE
743 return result
744
745 def _get_picking_from_move_lines(self, cr, uid, ids, context=None):
746+<<<<<<< TREE
747 return self.pool['stock.picking'].search(
748 cr, uid, [('move_lines', 'in', ids)], context=context)
749+=======
750+ #print "invalid function dpt ids=", ids
751+ return self.pool.get('stock.picking').search(cr, uid, [('move_lines', 'in', ids)], context=context)
752+>>>>>>> MERGE-SOURCE
753
754 _columns = {
755 'intrastat_transport': fields.selection([
756
757=== modified file 'l10n_fr_intrastat_service/intrastat_service.py'
758--- l10n_fr_intrastat_service/intrastat_service.py 2014-04-14 17:41:39 +0000
759+++ l10n_fr_intrastat_service/intrastat_service.py 2014-05-07 12:14:44 +0000
760@@ -164,6 +164,10 @@
761 )]
762
763 def generate_service_lines(self, cr, uid, ids, context=None):
764+<<<<<<< TREE
765+=======
766+ #print "generate lines, ids=", ids
767+>>>>>>> MERGE-SOURCE
768 intrastat = self.browse(cr, uid, ids[0], context=context)
769 line_obj = self.pool['report.intrastat.service.line']
770 invoice_obj = self.pool['account.invoice']
771@@ -183,6 +187,7 @@
772 ('state', 'in', ('open', 'paid')),
773 ('company_id', '=', intrastat.company_id.id)
774 ], order='date_invoice', context=context)
775+<<<<<<< TREE
776 #print "invoice_ids=", invoice_ids
777 for invoice in invoice_obj.browse(
778 cr, uid, invoice_ids, context=context):
779@@ -202,6 +207,19 @@
780 amount_invoice_cur_regular_service = 0.0
781 amount_invoice_cur_accessory_cost = 0.0
782 regular_product_in_invoice = False
783+=======
784+ #print "invoice_ids=", invoice_ids
785+ for invoice in invoice_obj.browse(cr, uid, invoice_ids, context=context):
786+
787+ if not invoice.address_invoice_id.country_id:
788+ raise osv.except_osv(_('Error :'), _("Missing country on partner address '%s' of partner '%s'.") %(invoice.address_invoice_id.name, invoice.address_invoice_id.partner_id.name))
789+ elif not invoice.address_invoice_id.country_id.intrastat:
790+ continue
791+
792+ amount_invoice_currency_to_write = 0.0
793+ amount_company_currency_to_write = 0.0
794+ context['date'] = invoice.date_invoice
795+>>>>>>> MERGE-SOURCE
796
797 for line in invoice.invoice_line:
798 if not line.product_id:
799@@ -285,6 +303,18 @@
800 else:
801 partner_vat_to_write = invoice.partner_id.vat
802
803+ # Why do I check that the Partner has a VAT number only here and not earlier ?
804+ # Because, if I sell to a physical person in the EU with VAT, then
805+ # the corresponding partner will not have a VAT number, and the entry
806+ # will be skipped because line_tax.exclude_from_intrastat_if_present is always
807+ # True and amount_company_currency_to_write = 0
808+ # So we should not block with a raise before the end of the loop on the
809+ # invoice lines and the "if amount_company_currency_to_write:"
810+ if not invoice.partner_id.vat:
811+ raise osv.except_osv(_('Error :'), _("Missing VAT number on partner '%s'.") %invoice.partner_id.name)
812+ else:
813+ partner_vat_to_write = invoice.partner_id.vat
814+
815 line_obj.create(cr, uid, {
816 'parent_id': ids[0],
817 'invoice_id': invoice.id,
818@@ -308,8 +338,14 @@
819 return True
820
821 def generate_xml(self, cr, uid, ids, context=None):
822+<<<<<<< TREE
823 #print "generate xml ids=", ids
824 common_obj = self.pool['report.intrastat.common']
825+=======
826+ #print "generate xml ids=", ids
827+ import des_xsd
828+ from lxml import etree
829+>>>>>>> MERGE-SOURCE
830 intrastat = self.browse(cr, uid, ids[0], context=context)
831 start_date_str = intrastat.start_date
832 start_date_datetime = datetime.strptime(
833@@ -344,6 +380,7 @@
834 # We take amount_company_currency, to get amounts in EUR
835 valeur.text = str(sline.amount_company_currency)
836 partner_des = etree.SubElement(ligne_des, 'partner_des')
837+<<<<<<< TREE
838 try:
839 partner_des.text = sline.partner_vat.replace(' ', '')
840 except:
841@@ -354,6 +391,12 @@
842 xml_string = etree.tostring(
843 root, pretty_print=True, encoding='UTF-8', xml_declaration=True)
844 #print "xml_string", xml_string
845+=======
846+ try: partner_des.text = sline.partner_vat.replace(' ', '')
847+ except: raise osv.except_osv(_('Error :'), _("Missing VAT number on partner '%s'.") %sline.partner_id.name)
848+ xml_string = etree.tostring(root, pretty_print=True, encoding='UTF-8', xml_declaration=True)
849+ #print "xml_string", xml_string
850+>>>>>>> MERGE-SOURCE
851
852 # We now validate the XML file against the official XSD
853 common_obj._check_xml_schema(

Subscribers

People subscribed via source and target branches