Merge lp:~camptocamp/openerp-product-attributes/port-add-product_multi_company_7.0-bis-jge into lp:~product-core-editors/openerp-product-attributes/7.0

Proposed by Joël Grand-Guillaume @ camptocamp
Status: Superseded
Proposed branch: lp:~camptocamp/openerp-product-attributes/port-add-product_multi_company_7.0-bis-jge
Merge into: lp:~product-core-editors/openerp-product-attributes/7.0
Diff against target: 1626 lines (+1238/-196)
21 files modified
base_custom_attributes/custom_attributes.py (+18/-3)
base_custom_attributes/custom_attributes_view.xml (+7/-4)
base_custom_attributes/security/ir.model.access.csv (+3/-0)
product_multi_company/i18n/en_US.po (+0/-32)
product_multi_company/i18n/es.po (+0/-36)
product_multi_company/i18n/fr.po (+0/-33)
product_multi_company/i18n/product_multi_company.pot (+0/-32)
product_price_history/__init__.py (+4/-4)
product_price_history/__openerp__.py (+55/-15)
product_price_history/demo/product_price_history_purchase_demo.yml (+189/-0)
product_price_history/i18n/product_price_history.pot (+210/-0)
product_price_history/product_price_history.py (+216/-37)
product_price_history/product_price_history_view.xml (+90/-0)
product_price_history/security/ir.model.access.csv (+7/-0)
product_price_history/security/product_price_history_security.xml (+13/-0)
product_price_history/test/avg_price_computation_mutlicompanies_multicurrencies.yml (+186/-0)
product_price_history/test/price_controlling_multicompany.yml (+55/-0)
product_price_history/test/price_historization.yml (+55/-0)
product_price_history/wizard/__init__.py (+24/-0)
product_price_history/wizard/historic_prices.py (+70/-0)
product_price_history/wizard/historic_prices_view.xml (+36/-0)
To merge this branch: bzr merge lp:~camptocamp/openerp-product-attributes/port-add-product_multi_company_7.0-bis-jge
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp code review Approve
Pedro Manuel Baeza code review and test Approve
Yannick Vaucher @ Camptocamp Needs Fixing
Maxime Chambreuil (http://www.savoirfairelinux.com) code review Pending
Review via email: mp+192872@code.launchpad.net

This proposal supersedes a proposal from 2013-10-16.

This proposal has been superseded by a proposal from 2013-12-04.

Description of the change

Hi,

I propose here a brand new version of product_multi_company to manage prices (standard_price and list_price) by company.

It uses another table to store and historize the prices instead of using ir.property. You can also easily override the field to historize in other module to add your own.

I provided here a whole set of tests and demo data to ensure no regression and show how to setup OpenERP in a complex multi-company, multi-currency context. With this module, you can have a same shared product between company, with each of them their own average price computed. You can even have the standard_price recorded in USD for company 1 and CHF for company 2 for example.

See description of the module for more details.

Note that this module replace the old one. I prefered to update this module rather than making another one (with another name). So, If you think it's better to call it differently, please just say it !

Thanks for the review,

Joël

To post a comment you must log in.
Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote : Posted in a previous version of this proposal

Thanks Joël.

I would put this module in the Multi-company project:
https://launchpad.net/multi-company

Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal

You're right Maxime, I agree with you. Since this module was originally put here by you, I don't wanted to mode it from here. But if you're alright, let's move it !

Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal

Just resumbit on the proper branch after using bzr-replay

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote : Posted in a previous version of this proposal

Hi, Joel, thank you very much for the module. Indeed, it seems to be quite interesting, but I see here two concepts put together in the same module:

- On one hand, you have prices historization, what is a very good feature, but nothing to do with multi-company. Besides, this feature can be also interesting for single-company.
- On the other hand, multi-company feature of this module is about prices, but not products in general, so I would rename the module to product_price_multi_company or even better, expand the features to allow a product to be visible/selectable by companies with a one2many to select allowed companies, and let the name product_multi_company.

I know that I'm asking too much, but if you want, we can work together to make these changes and get two very useful modules.

Regards.

Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal

Hi Pedro,

Thanks for your remarks ! This module bing 2 main behaviors: Having price by company (like ir.property, but faster) + historization... So difficult to chose...

For historization:

I agree with your remarks. I was wondering about changing the name of this module because of the historization concept, very useful for others needs than multi-company. The thing is here the way it's implemented. To have this historization (that work on single company), you'll also need the ir.rule on price_type to make it correct in multi-company context. As well the table price_history adds the company_id. In case you're in a single company, nothing to do, it just work out of the box but just provide historization. In a multi-company context, it adds historization + different price per company (in different currency if needed).

For allowing a product to be visible/selectable by companies:

I think IMO that this is another need. By default, you define ir.rule to share product or not between company. If a product has a company_id (with default ir.rule), he's only part of that company. If is has not, it is shared for all company. Providing a o2m to deal with that at product level seems interesting, but not required and can easily be added in another module what do you think ?

Conclusion/Suggestions:

- I suggest another module to implement the "product to be visible/selectable by companies with a one2many" and that also adapt the default ir.rule provided by OpenERP on product.product

- I suggest to rename this module: product_price_historization_by_company and re-change" the destination branch for the original one : https://launchpad.net/openerp-product-attributes.

Other opinions ?

Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote : Posted in a previous version of this proposal

lgtm

review: Approve (code review)
Revision history for this message
Ronald Portier (Therp) (rportier1962) wrote : Posted in a previous version of this proposal

Looks very promising!

One remark:

please rename 'test/average_price_computation_mutlicompany_currency.yml': s/mutli/multi/

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote : Posted in a previous version of this proposal

I have added the other product_multi_company module to my agenda!

But for this module, do you agree to rename and reallocate it in the proper place?

Regards.

Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal

Hi,

I changed the name of the test file according to your remarks. I'm also push this MP back to openerp-product-attributes project.

Regards,

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Need po files

Otherwise lgtm

review: Needs Fixing
Revision history for this message
Romain Deheele - Camptocamp (romaindeheele) wrote :

Hi Joel,

Are you aware about :
lp:~camptocamp/openerp-product-attributes/7.0-add-product_multi_company_new-jge
and two last commits?

Romain

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Romain

I setted
https://code.launchpad.net/~camptocamp/openerp-product-attributes/7.0-add-product_multi_company_new-jge
as Abandonned branch

Can you check and add your fixes again?

Revision history for this message
Romain Deheele - Camptocamp (romaindeheele) wrote :

I add my fixes,

Romain

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Hi, Joël and Romain,

Thank you very much for the effort you are making to get this module in the best way. I have tested it and view the code, and these are my remarks:

- We agreed about renaming to product_price_historization_by_company or it can be only product_price_historization, are we?
- You can put in the description that is multi-company aware and avoid it on the module name.
- Put product_multi_company_purchase_demo.yml on test folder and add it to tests on manifest file.
- Create at least the pot translation template file.
- Rename 'price.history' model to 'product.price.history' to be consistent.
- In security/ir.model.access.csv, there are references to groups installed by "mrp", "sale" or "hr"modules, but these modules are not declared as dependences. BTW, it doesn't make any sense to have it, because you already have enough permissions with groups like base.group_sale_manager or base.group_user.
- It would be very interesting to have any screen to query past prices.

Regards.

review: Needs Fixing (code review and test)
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Just for the records of the MP

On Thu, Oct 31, 2013 at 5:37 PM, Pedro Manuel Baeza Romero <
<email address hidden>> wrote:

> Well, product_price_history then ;)
>
> However, I swear that I have seen this term a lot of times on software.
>
> Regards.
>
>
> 2013/10/31 Ray Carnes <email address hidden>
>
>> Also in Australia, Canada (English speaking part) and the USA (and the
>> other 57 countries where English is the official
>> language), people would also see this as an ugly non-word.
>>
>> (No offence intended).
>>
>> Ray.
>>
>> -----Original Message-----
>> From: Openerp-community [mailto:openerp-community-bounces+rcarnes=
>> <email address hidden>] On Behalf Of
>> Martin Collins
>> Sent: Thursday, October 31, 2013 9:28 AM
>> To: <email address hidden>
>> Subject: Re: [Openerp-community] [Merge]
>> lp:~camptocamp/openerp-product-attributes/port-add-product_multi_company_7.0-bis-jge
>> into lp:openerp-product-attributes
>>
>> On 2013-10-31 09:33, Pedro Manuel Baeza wrote:
>> >
>> > - We agreed about renaming to product_price_historization_by_company
>>
>> To an Englishman like me 'historization' is a very ugly non-word. How
>> about just 'history'.
>>
>> Martin
>>
>

Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

Hi there,

So, I made the requested changes :

 * Rename module
 * Add .pot file
 * Include right management changes
 * Create a demo folder for demo files
 * Add to view to display product historic prices (one in reporting, one from product)

Everything tested and all green.

Can you update your review based on those modifications please ?

Thanks !

Regards,

Joël

224. By Joël Grand-Guillaume @ camptocamp

[REN] Rename module and model to product_price_history
[ADD] View from product form to display historical prices
[ADD] View to reporting to display the product list at a given date for prices analysis
[FIX] Adapt tests and security

225. By Joël Grand-Guillaume @ camptocamp

[ADD] .pot file for translation

226. By Joël Grand-Guillaume @ camptocamp

[DEL] .pyc file.. GRrrr.

227. By Joël Grand-Guillaume @ camptocamp

[MRG] Last fix from Romain suggested in MP

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Hi, Joël

Thanks again for your extensive work. The module works like a charm. I have seen one minor thing, but I approve it anyway:

- In the module description, the lines of the bulleted list are split in the middle, not respecting the indentation (maybe you have to put two spaces to align to the beginning of the text?).

Regards.

review: Approve (code review and test)
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

Thanks for pointing that out, it's fixed now !

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Made some changes, approve.

review: Approve (code review)
228. By Joël Grand-Guillaume @ camptocamp

[DOC] Make a nice description of the module.

229. By Joël Grand-Guillaume @ camptocamp

[IMP] Add company_id on price.type object to allow manager to verify that the setup is correct regarding price.type in a multi-company context

230. By Joël Grand-Guillaume @ camptocamp

[MRG] From trunk

231. By Joël Grand-Guillaume @ camptocamp

[FIX] Security rule on price.type

232. By Joël Grand-Guillaume @ camptocamp

[FIX] When prices are read from a function field, OpenERP replace the current uid. That lead to reading the price of the company of the admin user instead of the current one. This fix that by retrieving the real user from context in that case

233. By Guewen Baconnier @ Camptocamp

[MRG] from lp:~camptocamp/openerp-product-attributes/7.0-attribute-set-create-1256023

234. By Joël Grand-Guillaume @ camptocamp

[MRG] [IMP] in CRUD operation, we need to check the proper company_id with wich we work. ir.cron and function field may replace the uid used, so f..

235. By Joël Grand-Guillaume @ camptocamp

[MRG] [IMP] Change the variable name of date historic given through context to use 'to_date' as it is used in stock reporting => this allow to have the...

236. By Joël Grand-Guillaume @ camptocamp

[IMP] Refactor the log_price method to let it be used in other modulesmore easily

Unmerged revisions

236. By Joël Grand-Guillaume @ camptocamp

[IMP] Refactor the log_price method to let it be used in other modulesmore easily

235. By Joël Grand-Guillaume @ camptocamp

[MRG] [IMP] Change the variable name of date historic given through context to use 'to_date' as it is used in stock reporting => this allow to have the...

234. By Joël Grand-Guillaume @ camptocamp

[MRG] [IMP] in CRUD operation, we need to check the proper company_id with wich we work. ir.cron and function field may replace the uid used, so f..

233. By Guewen Baconnier @ Camptocamp

[MRG] from lp:~camptocamp/openerp-product-attributes/7.0-attribute-set-create-1256023

232. By Joël Grand-Guillaume @ camptocamp

[FIX] When prices are read from a function field, OpenERP replace the current uid. That lead to reading the price of the company of the admin user instead of the current one. This fix that by retrieving the real user from context in that case

231. By Joël Grand-Guillaume @ camptocamp

[FIX] Security rule on price.type

230. By Joël Grand-Guillaume @ camptocamp

[MRG] From trunk

229. By Joël Grand-Guillaume @ camptocamp

[IMP] Add company_id on price.type object to allow manager to verify that the setup is correct regarding price.type in a multi-company context

228. By Joël Grand-Guillaume @ camptocamp

[DOC] Make a nice description of the module.

227. By Joël Grand-Guillaume @ camptocamp

[MRG] Last fix from Romain suggested in MP

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'base_custom_attributes/custom_attributes.py'
--- base_custom_attributes/custom_attributes.py 2013-11-13 08:38:19 +0000
+++ base_custom_attributes/custom_attributes.py 2013-12-04 10:24:54 +0000
@@ -246,6 +246,21 @@
246 }246 }
247247
248 def create(self, cr, uid, vals, context=None):248 def create(self, cr, uid, vals, context=None):
249 if vals.get('field_id'):
250 field_obj = self.pool.get('ir.model.fields')
251 field = field_obj.browse(cr, uid, vals['field_id'], context=context)
252 if vals.get('serialized'):
253 raise orm.except_orm(
254 _('Error'),
255 _("Can't create a serialized attribute on "
256 "an existing ir.model.fields (%s)") % field.name)
257 if field.state != 'manual':
258 # the ir.model.fields already exists and we want to map
259 # an attribute on it. We can't change the field so we
260 # won't add the ttype, relation and so on.
261 return super(attribute_attribute, self).create(cr, uid, vals,
262 context=context)
263
249 if vals.get('relation_model_id'):264 if vals.get('relation_model_id'):
250 relation = self.pool.get('ir.model').read(265 relation = self.pool.get('ir.model').read(
251 cr, uid, [vals.get('relation_model_id')], ['model'])[0]['model']266 cr, uid, [vals.get('relation_model_id')], ['model'])[0]['model']
@@ -352,9 +367,9 @@
352 }367 }
353368
354 def create(self, cr, uid, vals, context=None):369 def create(self, cr, uid, vals, context=None):
355 for attribute in vals['attribute_ids']:370 for attribute in vals.get('attribute_ids', []):
356 if vals.get('attribute_set_id') and attribute[2] and \371 if (vals.get('attribute_set_id') and attribute[2] and
357 not attribute[2].get('attribute_set_id'):372 not attribute[2].get('attribute_set_id')):
358 attribute[2]['attribute_set_id'] = vals['attribute_set_id']373 attribute[2]['attribute_set_id'] = vals['attribute_set_id']
359 return super(attribute_group, self).create(cr, uid, vals, context)374 return super(attribute_group, self).create(cr, uid, vals, context)
360375
361376
=== modified file 'base_custom_attributes/custom_attributes_view.xml'
--- base_custom_attributes/custom_attributes_view.xml 2013-11-12 08:02:42 +0000
+++ base_custom_attributes/custom_attributes_view.xml 2013-12-04 10:24:54 +0000
@@ -286,11 +286,14 @@
286 <field name="name">attribute.option.wizard</field>286 <field name="name">attribute.option.wizard</field>
287 <field name="model">attribute.option.wizard</field>287 <field name="model">attribute.option.wizard</field>
288 <field name="arch" type="xml">288 <field name="arch" type="xml">
289 <form string="Options Wizard" col="6">289 <form string="Options Wizard" version="7.0">
290 <field name="attribute_id" invisible="1" colspan="2"/>290 <field name="attribute_id" invisible="1"/>
291 <separator string="options_placeholder"/>291 <separator string="options_placeholder"/>
292 <button special="cancel" string="Cancel" icon="gtk-cancel"/>292 <footer>
293 <button name="validate" string="Validate" type="object" icon="gtk-convert"/>293 <button name="validate" string="Validate" type="object" icon="gtk-convert" class="oe_highlight"/>
294 or
295 <button string="Cancel" class="oe_link" special="cancel"/>
296 </footer>
294 </form>297 </form>
295 </field>298 </field>
296 </record>299 </record>
297300
=== modified file 'base_custom_attributes/security/ir.model.access.csv'
--- base_custom_attributes/security/ir.model.access.csv 2013-07-23 14:39:16 +0000
+++ base_custom_attributes/security/ir.model.access.csv 2013-12-04 10:24:54 +0000
@@ -1,12 +1,15 @@
1id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink1id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2access_base_custom_attributes_attribute_set_salemanager,base_custom_attributes_attribute_set,base_custom_attributes.model_attribute_set,base.group_sale_manager,1,1,1,1
2access_base_custom_attributes_attribute_group_salemanager,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_sale_manager,1,1,1,13access_base_custom_attributes_attribute_group_salemanager,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_sale_manager,1,1,1,1
3access_base_custom_attributes_attribute_attribute_salemanager,base_custom_attributes_product_attribute,base_custom_attributes.model_attribute_attribute,base.group_sale_manager,1,1,1,14access_base_custom_attributes_attribute_attribute_salemanager,base_custom_attributes_product_attribute,base_custom_attributes.model_attribute_attribute,base.group_sale_manager,1,1,1,1
4access_base_custom_attributes_attribute_option_salemanager,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_sale_manager,1,1,1,15access_base_custom_attributes_attribute_option_salemanager,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_sale_manager,1,1,1,1
5access_base_custom_attributes_attribute_location_salemanager,base_custom_attributes_attribute_location,base_custom_attributes.model_attribute_location,base.group_sale_manager,1,1,1,16access_base_custom_attributes_attribute_location_salemanager,base_custom_attributes_attribute_location,base_custom_attributes.model_attribute_location,base.group_sale_manager,1,1,1,1
7access_base_custom_attributes_attribute_set_manager,base_custom_attributes_attribute_set,base_custom_attributes.model_attribute_set,base.group_no_one,1,1,1,1
6access_base_custom_attributes_attribute_group_manager,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_no_one,1,1,1,18access_base_custom_attributes_attribute_group_manager,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_no_one,1,1,1,1
7access_base_custom_attributes_attribute_attribute_manager,base_custom_attributes_attribute_attribute,base_custom_attributes.model_attribute_attribute,base.group_no_one,1,1,1,19access_base_custom_attributes_attribute_attribute_manager,base_custom_attributes_attribute_attribute,base_custom_attributes.model_attribute_attribute,base.group_no_one,1,1,1,1
8access_base_custom_attributes_attribute_option_manager,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_no_one,1,1,1,110access_base_custom_attributes_attribute_option_manager,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_no_one,1,1,1,1
9access_base_custom_attributes_attribute_location_manager,base_custom_attributes_attribute_location,base_custom_attributes.model_attribute_location,base.group_no_one,1,1,1,111access_base_custom_attributes_attribute_location_manager,base_custom_attributes_attribute_location,base_custom_attributes.model_attribute_location,base.group_no_one,1,1,1,1
12access_base_custom_attributes_attribute_set_user,base_custom_attributes_attribute_set,base_custom_attributes.model_attribute_set,base.group_user,1,0,0,0
10access_base_custom_attributes_attribute_group_user,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_user,1,0,0,013access_base_custom_attributes_attribute_group_user,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_user,1,0,0,0
11access_base_custom_attributes_attribute_attribute_user,base_custom_attributes_attribute_attribute,base_custom_attributes.model_attribute_attribute,base.group_user,1,0,0,014access_base_custom_attributes_attribute_attribute_user,base_custom_attributes_attribute_attribute,base_custom_attributes.model_attribute_attribute,base.group_user,1,0,0,0
12access_base_custom_attributes_attribute_option_user,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_user,1,0,0,015access_base_custom_attributes_attribute_option_user,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_user,1,0,0,0
1316
=== removed directory 'product_multi_company/i18n'
=== removed file 'product_multi_company/i18n/en_US.po'
--- product_multi_company/i18n/en_US.po 2010-12-29 07:42:35 +0000
+++ product_multi_company/i18n/en_US.po 1970-01-01 00:00:00 +0000
@@ -1,32 +0,0 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * product_multi_company
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
8"Report-Msgid-Bugs-To: support@openerp.com\n"
9"POT-Creation-Date: 2010-12-28 12:10:13+0000\n"
10"PO-Revision-Date: 2010-12-28 12:10:13+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: product_multi_company
19#: model:ir.model,name:product_multi_company.model_product_template
20msgid "Product Template"
21msgstr ""
22
23#. module: product_multi_company
24#: constraint:product.template:0
25msgid "Error: The default UOM and the purchase UOM must be in the same category."
26msgstr ""
27
28#. module: product_multi_company
29#: model:ir.model,name:product_multi_company.model_pricelist_partnerinfo
30msgid "pricelist.partnerinfo"
31msgstr ""
32
330
=== removed file 'product_multi_company/i18n/es.po'
--- product_multi_company/i18n/es.po 2012-12-05 05:42:11 +0000
+++ product_multi_company/i18n/es.po 1970-01-01 00:00:00 +0000
@@ -1,36 +0,0 @@
1# Spanish translation for openobject-addons
2# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
3# This file is distributed under the same license as the openobject-addons package.
4# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
5#
6msgid ""
7msgstr ""
8"Project-Id-Version: openobject-addons\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2010-12-28 12:10+0000\n"
11"PO-Revision-Date: 2011-08-27 14:01+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Spanish <es@li.org>\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
17"X-Launchpad-Export-Date: 2012-12-05 05:41+0000\n"
18"X-Generator: Launchpad (build 16335)\n"
19
20#. module: product_multi_company
21#: model:ir.model,name:product_multi_company.model_product_template
22msgid "Product Template"
23msgstr "Plantilla de producto"
24
25#. module: product_multi_company
26#: constraint:product.template:0
27msgid ""
28"Error: The default UOM and the purchase UOM must be in the same category."
29msgstr ""
30"Error: La UdM por defecto y la UdM de compra deben estar en la misma "
31"categoría."
32
33#. module: product_multi_company
34#: model:ir.model,name:product_multi_company.model_pricelist_partnerinfo
35msgid "pricelist.partnerinfo"
36msgstr "listaprecios.infoempresa"
370
=== removed file 'product_multi_company/i18n/fr.po'
--- product_multi_company/i18n/fr.po 2012-12-05 05:42:11 +0000
+++ product_multi_company/i18n/fr.po 1970-01-01 00:00:00 +0000
@@ -1,33 +0,0 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * product_multi_company
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
8"Report-Msgid-Bugs-To: support@openerp.com\n"
9"POT-Creation-Date: 2010-12-28 12:10+0000\n"
10"PO-Revision-Date: 2011-02-15 17:25+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: 8bit\n"
16"X-Launchpad-Export-Date: 2012-12-05 05:41+0000\n"
17"X-Generator: Launchpad (build 16335)\n"
18
19#. module: product_multi_company
20#: model:ir.model,name:product_multi_company.model_product_template
21msgid "Product Template"
22msgstr ""
23
24#. module: product_multi_company
25#: constraint:product.template:0
26msgid ""
27"Error: The default UOM and the purchase UOM must be in the same category."
28msgstr ""
29
30#. module: product_multi_company
31#: model:ir.model,name:product_multi_company.model_pricelist_partnerinfo
32msgid "pricelist.partnerinfo"
33msgstr ""
340
=== removed file 'product_multi_company/i18n/product_multi_company.pot'
--- product_multi_company/i18n/product_multi_company.pot 2010-12-29 07:42:35 +0000
+++ product_multi_company/i18n/product_multi_company.pot 1970-01-01 00:00:00 +0000
@@ -1,32 +0,0 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * product_multi_company
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 6.0.0-rc1\n"
8"Report-Msgid-Bugs-To: support@openerp.com\n"
9"POT-Creation-Date: 2010-12-28 12:10:13+0000\n"
10"PO-Revision-Date: 2010-12-28 12:10:13+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: product_multi_company
19#: model:ir.model,name:product_multi_company.model_product_template
20msgid "Product Template"
21msgstr ""
22
23#. module: product_multi_company
24#: constraint:product.template:0
25msgid "Error: The default UOM and the purchase UOM must be in the same category."
26msgstr ""
27
28#. module: product_multi_company
29#: model:ir.model,name:product_multi_company.model_pricelist_partnerinfo
30msgid "pricelist.partnerinfo"
31msgstr ""
32
330
=== renamed directory 'product_multi_company' => 'product_price_history'
=== modified file 'product_price_history/__init__.py'
--- product_multi_company/__init__.py 2010-12-29 07:42:35 +0000
+++ product_price_history/__init__.py 2013-12-04 10:24:54 +0000
@@ -2,7 +2,8 @@
2##############################################################################2##############################################################################
3# 3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).5# Copyright 2013 Camptocamp SA
6# Author: Joel Grand-Guillaume
6#7#
7# This program is free software: you can redistribute it and/or modify8# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as9# it under the terms of the GNU Affero General Public License as
@@ -19,6 +20,5 @@
19#20#
20##############################################################################21##############################################################################
2122
22import product_multi_company
23
24# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
25\ No newline at end of file23\ No newline at end of file
24from . import product_price_history
25from . import wizard
26\ No newline at end of file26\ No newline at end of file
2727
=== modified file 'product_price_history/__openerp__.py'
--- product_multi_company/__openerp__.py 2013-01-21 06:49:06 +0000
+++ product_price_history/__openerp__.py 2013-12-04 10:24:54 +0000
@@ -1,8 +1,9 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3# 3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).5# Copyright 2013 Camptocamp SA
6# Author: Joel Grand-Guillaume
6#7#
7# This program is free software: you can redistribute it and/or modify8# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as9# it under the terms of the GNU Affero General Public License as
@@ -15,25 +16,64 @@
15# GNU Affero General Public License for more details.16# GNU Affero General Public License for more details.
16#17#
17# You should have received a copy of the GNU Affero General Public License18# 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/>. 19# along with this program. If not, see <http://www.gnu.org/licenses/>
19#20#
20##############################################################################21##############################################################################
2122
22{23{
23 "name" : "Product multi company ",24 "name" : "Product Price History",
24 "version" : "1.1",25 "version" : "1.2",
25 "author" : "OpenERP SA",26 "author" : "Camptocamp",
26 "category" : "Generic Modules/Inventory Control",27 "category" : "Generic Modules/Inventory Control",
27 "depends" : [ "product"],28 "depends" : ["product",
28 "init_xml" : [],29 "purchase",
29 "demo_xml" : [],30 ],
30 "description": """31 "description": """
31 This module updates the definitions of standard price, public price and seller price with property fields.32Product Price History
32 """,33=====================
33 'update_xml': [],34
34 'test':[],35This module allows you to:
35 'installable': False,36
37* Record various prices of a same product for different companies. This
38 way, every company can have its own costs (average or standard) and
39 sale prices.
40* Historize the prices in a way that you'll then be able to retrieve the
41 cost (or sale) price at a given date.
42
43Note that to benefit those values in stock report (or any other view that is based on SQL),
44you'll have to adapt it to include this new historized table. Especially true for stock
45valuation.
46
47This module also contains demo data and various tests to ensure it works well. It shows
48how to configure OpenERP properly when you have various company, each of them having
49their product setup in average price and using different currencies. The goal is to share
50the products between all companies, keeping the right price for each of them.
51
52Technically, this module updates the definition of field standard_price, list_price
53of the product and will make them stored in an external table. We override the read,
54write and create methods to achieve that and don't used ir.property for performance
55and historization purpose.
56
57You may want to also use the module analytic_multicurrency from `bzr branch lp:account-analytic/7.0`
58in order to have a proper computation in analytic line as well (standard_price will be converted
59in company currency with this module when computing cost of analytic line).
60""",
61 'demo': [
62 'demo/product_price_history_purchase_demo.yml',
63 ],
64 'data': [
65 'product_price_history_view.xml',
66 'wizard/historic_prices_view.xml',
67 'security/ir.model.access.csv',
68 'security/product_price_history_security.xml',
69 ],
70 'test': [
71 'test/price_controlling_multicompany.yml',
72 'test/avg_price_computation_mutlicompanies_multicurrencies.yml',
73 'test/price_historization.yml',
74 ],
75 'installable': True,
36 'active': False,76 'active': False,
37}77}
3878
39# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
40\ No newline at end of file79\ No newline at end of file
80# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
4181
=== added directory 'product_price_history/demo'
=== added file 'product_price_history/demo/product_price_history_purchase_demo.yml'
--- product_price_history/demo/product_price_history_purchase_demo.yml 1970-01-01 00:00:00 +0000
+++ product_price_history/demo/product_price_history_purchase_demo.yml 2013-12-04 10:24:54 +0000
@@ -0,0 +1,189 @@
1-
2 Create a Partner for second company and second company user
3-
4 !record {model: res.partner, id: res_partner_company_01}:
5 name: Second Company Partner test
6-
7 !record {model: res.partner, id: res_partner_user_second_company_01}:
8 name: Second Company User Partner test
9-
10 Create a second company hanlded in CHF
11-
12 !record {model: res.company, id: res_company_01}:
13 name: Second Company test
14 partner_id: res_partner_company_01
15 currency_id: base.CHF
16-
17 Create a user for second company
18-
19 !record {model: res.users, id: res_users_second_company_01}:
20 login: user second company
21 password: user second company
22 partner_id: res_partner_user_second_company_01
23 company_id: res_company_01
24 company_ids: [res_company_01,base.main_company]
25 groups_id:
26 - base.group_user
27 - base.group_sale_manager
28 - purchase.group_purchase_manager
29 - stock.group_stock_user
30-
31 Create a second set of price type in USD for the second company
32-
33 !record {model: product.price.type, id: list_price_second_cmp}:
34 name: Public Price USD
35 field: list_price
36 currency_id: base.USD
37 company_id: res_company_01
38-
39 !record {model: product.price.type, id: standard_price_second_cmp}:
40 name: Cost Price USD
41 field: standard_price
42 currency_id: base.USD
43 company_id: res_company_01
44-
45 Ensure the price type of first company is in EUR
46-
47 !record {model: product.price.type, id: product.list_price}:
48 name: Public Price EUR
49 field: list_price
50 currency_id: base.EUR
51 company_id: base.main_company
52-
53 !record {model: product.price.type, id: product.standard_price}:
54 name: Cost Price EUR
55 field: standard_price
56 currency_id: base.EUR
57 company_id: base.main_company
58-
59 Set the admin user to first company
60-
61 !record {model: res.users, id: base.user_root}:
62 company_id: base.main_company
63-
64 Set the currency rate of CHF, EUR and USD (reference EUR)
65-
66 !record {model: res.currency.rate, id: base.rateCHF}:
67 rate: 1.3086
68 currency_id: base.CHF
69 name: !eval time.strftime('%Y-%m-%d')
70-
71 !record {model: res.currency.rate, id: base.rateUSD}:
72 rate: 1.2086
73 currency_id: base.USD
74 name: !eval time.strftime('%Y-%m-%d')
75-
76 !record {model: res.currency.rate, id: base.rateEUR}:
77 rate: 1.0
78 currency_id: base.EUR
79 name: !eval time.strftime('%Y-%m-%d')
80-
81 Ensure the first Company and pricelists are in EUR (rate 1.0)
82-
83 !record {model: res.company, id: base.main_company}:
84 currency_id: base.EUR
85-
86 !record {model: product.pricelist, id: purchase.list0}:
87 name: Purchase Pricelist EUR
88 currency_id: base.EUR
89 company_id: base.main_company
90-
91 !record {model: product.pricelist, id: product.list0}:
92 name: Public Pricelist EUR
93 currency_id: base.EUR
94 company_id: base.main_company
95-
96 Create a sale pricelist in CHF for second company (also in CHF)
97-
98 !record {model: product.pricelist, id: product_pricelist_salechf}:
99 name: Public Pricelist CHF
100 type: sale
101 company_id: res_company_01
102 currency_id: base.CHF
103-
104 !record {model: product.pricelist.version, id: product_pricelist_version_salechf}:
105 pricelist_id: product_pricelist_salechf
106 name: Default Public Pricelist Version
107-
108 !record {model: product.pricelist.item, id: product_pricelist_item_salechf}:
109 price_version_id: product_pricelist_version_salechf
110 base: !eval ref('list_price_second_cmp')
111 name: Default Public Pricelist Line
112-
113 Create a purchase pricelist in CHF for second company (also in CHF)
114-
115 !record {model: product.pricelist, id: product_pricelist_purchchf}:
116 name: Purchase Pricelist CHF
117 type: purchase
118 company_id: res_company_01
119 currency_id: base.CHF
120-
121 !record {model: product.pricelist.version, id: product_pricelist_version_purchchf}:
122 pricelist_id: product_pricelist_purchchf
123 name: Default Purchase Pricelist Version
124-
125 !record {model: product.pricelist.item, id: product_pricelist_item_puchchf}:
126 price_version_id: product_pricelist_version_purchchf
127 base: !eval ref('standard_price_second_cmp')
128 name: Default Purchase Pricelist Line
129-
130 Create a stock location for first and second company
131-
132 !record {model: stock.location, id: location_stock_01}:
133 name: Stock first company EUR
134 usage: internal
135 company_id: base.main_company
136-
137 !record {model: stock.location, id: location_stock_02}:
138 name: Stock second company CHF
139 usage: internal
140 company_id: res_company_01
141-
142 Create a warehouse for first and second company
143-
144 !record {model: stock.warehouse, id: wh_stock_01}:
145 name: Warehouse for first company EUR
146 lot_output_id: location_stock_01
147 lot_stock_id: location_stock_01
148 lot_input_id: location_stock_01
149 company_id: base.main_company
150-
151 !record {model: stock.warehouse, id: wh_stock_02}:
152 name: Warehouse for second company CHF
153 lot_output_id: location_stock_02
154 lot_stock_id: location_stock_02
155 lot_input_id: location_stock_02
156 company_id: res_company_01
157-
158 Create a Supplier for PO
159-
160 !record {model: res.partner, id: res_partner_supplier_01}:
161 name: Supplier 1
162 supplier: 1
163-
164 Create a wine product J owned by both company
165-
166 !record {model: product.product, id: product_product_j_avg_01}:
167 categ_id: product.product_category_1
168 cost_method: average
169 name: Wine J
170 type: product
171 uom_id: product.product_uom_unit
172 uom_po_id: product.product_uom_unit
173 company_id: False
174-
175 Create a wine product K owned by both company
176-
177 !record {model: product.product, id: product_product_k_avg_01}:
178 categ_id: product.product_category_1
179 cost_method: average
180 name: Wine K
181 type: product
182 uom_id: product.product_uom_unit
183 uom_po_id: product.product_uom_unit
184 company_id: False
185-
186 Setup the multi company rules for product, share them between company
187-
188 !record {model: ir.rule, id: product.product_comp_rule}:
189 domain_force: "[(1,'=',1)]"
0190
=== added directory 'product_price_history/i18n'
=== added file 'product_price_history/i18n/product_price_history.pot'
--- product_price_history/i18n/product_price_history.pot 1970-01-01 00:00:00 +0000
+++ product_price_history/i18n/product_price_history.pot 2013-12-04 10:24:54 +0000
@@ -0,0 +1,210 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * product_price_history
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2013-11-05 11:39+0000\n"
10"PO-Revision-Date: 2013-11-05 11:39+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: product_price_history
19#: model:stock.location,name:product_price_history.location_stock_02
20msgid "Stock second company CHF"
21msgstr ""
22
23#. module: product_price_history
24#: view:product.price.history:0
25msgid "Group By..."
26msgstr ""
27
28#. module: product_price_history
29#: model:product.pricelist,name:product_price_history.product_pricelist_purchchf
30msgid "Purchase Pricelist CHF"
31msgstr ""
32
33#. module: product_price_history
34#: model:ir.model.fields,field_description:product_price_history.field_product_price_history_product_id
35#: view:product.price.history:0
36#: field:product.price.history,product_id:0
37msgid "Product"
38msgstr ""
39
40#. module: product_price_history
41#: model:product.price.type,name:product_price_history.standard_price_second_cmp
42msgid "Cost Price USD"
43msgstr ""
44
45#. module: product_price_history
46#: view:historic.prices:0
47msgid "Compute prices"
48msgstr ""
49
50#. module: product_price_history
51#: model:ir.model.fields,field_description:product_price_history.field_product_price_history_company_id
52#: model:ir.model.fields,field_description:product_price_history.field_product_price_type_company_id
53#: view:product.price.history:0
54#: field:product.price.history,company_id:0
55#: field:product.price.type,company_id:0
56msgid "Company"
57msgstr ""
58
59#. module: product_price_history
60#: code:addons/product_price_history/wizard/historic_prices.py:63
61#, python-format
62msgid "Historical Prices"
63msgstr ""
64
65#. module: product_price_history
66#: model:ir.model.fields,field_description:product_price_history.field_product_price_history_name
67#: field:product.price.history,name:0
68msgid "Field name"
69msgstr ""
70
71#. module: product_price_history
72#: model:product.pricelist.version,name:product_price_history.product_pricelist_version_salechf
73msgid "Default Public Pricelist Version"
74msgstr ""
75
76#. module: product_price_history
77#: model:ir.actions.act_window,name:product_price_history.action_product_historic_prices_view
78#: model:ir.ui.menu,name:product_price_history.menu_action_product_historic_prices_tree
79msgid "Product Historical Prices"
80msgstr ""
81
82#. module: product_price_history
83#: field:historic.prices,to_date:0
84#: model:ir.model.fields,field_description:product_price_history.field_historic_prices_to_date
85#: model:ir.model.fields,field_description:product_price_history.field_product_price_history_datetime
86#: view:product.price.history:0
87#: field:product.price.history,datetime:0
88msgid "Date"
89msgstr ""
90
91#. module: product_price_history
92#: model:ir.actions.act_window,name:product_price_history.act_product_prices_history_open
93#: model:ir.actions.act_window,name:product_price_history.action_price_history
94#: model:ir.ui.menu,name:product_price_history.menu_product_price_history_action_form
95msgid "Prices History"
96msgstr ""
97
98#. module: product_price_history
99#: model:product.pricelist.version,name:product_price_history.product_pricelist_version_purchchf
100msgid "Default Purchase Pricelist Version"
101msgstr ""
102
103#. module: product_price_history
104#: view:product.price.history:0
105msgid "Search Prices History"
106msgstr ""
107
108#. module: product_price_history
109#: view:product.price.history:0
110msgid "Name"
111msgstr ""
112
113#. module: product_price_history
114#: view:historic.prices:0
115msgid "Historical prices"
116msgstr ""
117
118#. module: product_price_history
119#: model:res.company,overdue_msg:product_price_history.res_company_01
120msgid "Dear Sir/Madam,\n"
121"\n"
122"Our records indicate that some payments on your account are still due. Please find details below.\n"
123"If the amount has already been paid, please disregard this notice. Otherwise, please forward us the total amount stated below.\n"
124"If you have any queries regarding your account, Please contact us.\n"
125"\n"
126"Thank you in advance for your cooperation.\n"
127"Best Regards,"
128msgstr ""
129
130#. module: product_price_history
131#: model:ir.model,name:product_price_history.model_product_price_history
132msgid "product.price.history"
133msgstr ""
134
135#. module: product_price_history
136#: view:product.price.history:0
137msgid "Price field"
138msgstr ""
139
140#. module: product_price_history
141#: model:ir.model.fields,field_description:product_price_history.field_product_price_history_amount
142#: field:product.price.history,amount:0
143msgid "Amount"
144msgstr ""
145
146#. module: product_price_history
147#: model:product.price.type,name:product_price_history.list_price_second_cmp
148msgid "Public Price USD"
149msgstr ""
150
151#. module: product_price_history
152#: model:stock.location,name:product_price_history.location_stock_01
153msgid "Stock first company EUR"
154msgstr ""
155
156#. module: product_price_history
157#: model:product.pricelist,name:product_price_history.product_pricelist_salechf
158msgid "Public Pricelist CHF"
159msgstr ""
160
161#. module: product_price_history
162#: model:product.template,name:product_price_history.product_product_k_avg_01_product_template
163msgid "Wine K"
164msgstr ""
165
166#. module: product_price_history
167#: model:product.template,name:product_price_history.product_product_j_avg_01_product_template
168msgid "Wine J"
169msgstr ""
170
171#. module: product_price_history
172#: model:ir.model,name:product_price_history.model_product_template
173msgid "Product Template"
174msgstr ""
175
176#. module: product_price_history
177#: view:product.price.history:0
178msgid "Historic Prices"
179msgstr ""
180
181#. module: product_price_history
182#: help:historic.prices,to_date:0
183msgid "Date at which the analysis need to be done. Note that the date is understood as this day at midnight, so you may want to specify the day after ! No date is the last value."
184msgstr ""
185
186#. module: product_price_history
187#: view:product.product:0
188msgid "Product Historic Prices"
189msgstr ""
190
191#. module: product_price_history
192#: model:ir.model,name:product_price_history.model_historic_prices
193msgid "Product historical prices"
194msgstr ""
195
196#. module: product_price_history
197#: view:historic.prices:0
198msgid "Cancel"
199msgstr ""
200
201#. module: product_price_history
202#: view:historic.prices:0
203msgid "or"
204msgstr ""
205
206#. module: product_price_history
207#: model:ir.model,name:product_price_history.model_product_price_type
208msgid "Price Type"
209msgstr ""
210
0211
=== renamed file 'product_multi_company/product_multi_company.py' => 'product_price_history/product_price_history.py'
--- product_multi_company/product_multi_company.py 2010-12-29 08:08:51 +0000
+++ product_price_history/product_price_history.py 2013-12-04 10:24:54 +0000
@@ -1,8 +1,9 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3# 3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).5# Copyright 2013 Camptocamp SA
6# Author: Joel Grand-Guillaume
6#7#
7# This program is free software: you can redistribute it and/or modify8# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as9# it under the terms of the GNU Affero General Public License as
@@ -15,45 +16,223 @@
15# GNU Affero General Public License for more details.16# GNU Affero General Public License for more details.
16#17#
17# You should have received a copy of the GNU Affero General Public License18# 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/>. 19# along with this program. If not, see <http://www.gnu.org/licenses/>
19#20#
20##############################################################################21##############################################################################
2122
22from osv import osv, fields23import logging
2324import time
24class product_template(osv.osv):25from openerp.osv import orm, fields
26import openerp.addons.decimal_precision as dp
27from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
28
29# All field name of product that will be historize
30PRODUCT_FIELD_HISTORIZE = ['standard_price', 'list_price']
31
32_logger = logging.getLogger(__name__)
33
34class product_price_history(orm.Model):
35 # TODO : Create good index for select
36
37 _name = 'product.price.history'
38 _order = 'datetime, company_id asc'
39
40 _columns = {
41 'name': fields.char('Field name', size=32, required=True),
42 'company_id': fields.many2one('res.company', 'Company',
43 required=True),
44 'product_id': fields.many2one('product.template', 'Product',
45 required=True),
46 'datetime': fields.datetime('Date'),
47 'amount': fields.float('Amount',
48 digits_compute=dp.get_precision('Product Price')),
49 }
50
51 def _get_default_company(self, cr, uid, context=None):
52 company = self.pool.get('res.company')
53 return company._company_default_get(cr, uid,
54 'product.template',
55 context=context)
56
57 def _get_default_date(self, cr, uid, context=None):
58 if context is None:
59 context = {}
60 if context.get('to_date'):
61 result = context.get('to_date')
62 else:
63 result = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
64 return result
65
66 _defaults = {
67 'company_id': _get_default_company,
68 'datetime': _get_default_date,
69 }
70
71 def _get_historic_price(self, cr, uid, ids, company_id,
72 datetime=False, field_name=None,
73 context=None):
74 """ Use SQL for performance. Return a dict like:
75 {product_id:{'standard_price': Value, 'list_price': Value}}
76 If no value found, return 0.0 for each field and products.
77 """
78 res = {}
79 if not ids:
80 return res
81 if field_name is None:
82 field_name = PRODUCT_FIELD_HISTORIZE
83 if not datetime:
84 datetime = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
85 sql_wh_clause = """SELECT DISTINCT ON (product_id, name)
86 datetime, product_id, name, amount
87 FROM product_price_history
88 WHERE product_id IN %s
89 AND datetime <= %s
90 AND company_id = %s
91 AND name IN %s
92 ORDER BY product_id, name, datetime DESC"""
93 cr.execute(sql_wh_clause, (tuple(ids), datetime,
94 company_id, tuple(field_name)))
95 for id in ids:
96 res[id] = dict.fromkeys(field_name, 0.0)
97 result = cr.dictfetchall()
98 for line in result:
99 data = {line['name']: line['amount']}
100 res[line['product_id']].update(data)
101 _logger.debug("Result of price history is : %s, company_id: %s", res, company_id)
102 return res
103
104
105class product_template(orm.Model):
106
25 _inherit = "product.template"107 _inherit = "product.template"
26 _description = "Product Template"108
27 _columns={109 def _log_all_price_changes(self, cr, uid, product, values, context=None):
28 'list_price': fields.property('product.template',110 """
29 type='float',111 For each field to historize, call the _log_price_change method
30 string='Public Price',112 @param: values dict of vals used by write and create od product
31 method=True,113 @param: int product ID
32 view_load=True,114 """
33 required=True,115 for field_name in PRODUCT_FIELD_HISTORIZE:
34 help="Base price for computing the customer price. Sometimes called the catalog price."),116 if values.get(field_name):
35 'standard_price': fields.property('product.template',117 amount = values[field_name]
36 type='float',118 self._log_price_change(cr, uid, product, field_name,
37 string='Standard Price',119 amount, context=context)
38 method=True,120 return True
39 view_load=True,121
40 required=True,122 def _log_price_change(self, cr, uid, product, field_name, amount, context=None):
41 help="Product's cost for accounting stock valuation. It is the base price for the supplier price."),123 """
42 }124 On change of price create a price_history
43product_template()125 :param int product value of new product or product_id
44126 """
45class pricelist_partnerinfo(osv.osv):127 price_history = self.pool.get('product.price.history')
46 _inherit = 'pricelist.partnerinfo' 128 data = {
47 _description = "Pricelist Partner"129 'product_id': product,
130 'amount': amount,
131 'name': field_name,
132 'company_id': self._get_transaction_company_id(cr, uid,
133 context=context)
134 }
135 return price_history.create(cr, uid, data, context=context)
136
137 def _get_transaction_company_id(self, cr, uid, context=None):
138 """As it may happend that OpenERP force the uid to 1 to bypass
139 rule (in function field), we may sometimes read the price of the company
140 of user id 1 instead of the good one. Because we found the real uid and company_id
141 in the context in that case, I return this one. It also allow other module to
142 give the proper company_id in the context (like it's done in product_standard_margin
143 for example. If company_id not in context, take the one from uid."""
144 res = uid
145 if context == None:
146 context = {}
147 if context.get('company_id'):
148 res = context.get('company_id')
149 else:
150 user_obj = self.pool.get('res.users')
151 res = user_obj.browse(cr, uid, uid,
152 context=context).company_id.id
153 return res
154
155 def create(self, cr, uid, values, context=None):
156 """Add the historization at product creation."""
157 res = super(product_template, self).create(cr, uid, values,
158 context=context)
159 self._log_all_price_changes(cr, uid, res, values, context=context)
160 return res
161
162 def read(self, cr, uid, ids, fields=None, context=None,
163 load='_classic_read'):
164 """Override the read to take price values from the related
165 price history table."""
166 if context is None:
167 context = {}
168 if fields:
169 fields.append('id')
170 results = super(product_template, self).read(
171 cr, uid, ids, fields=fields, context=context, load=load)
172 # Note if fields is empty => read all, so look at history table
173 if not fields or any([f in PRODUCT_FIELD_HISTORIZE for f in fields]):
174 date_crit = False
175 price_history = self.pool.get('product.price.history')
176 company_id = self._get_transaction_company_id(cr, uid, context=context)
177 if context.get('to_date'):
178 date_crit = context['to_date']
179 # if fields is empty we read all price fields
180 if not fields:
181 price_fields = PRODUCT_FIELD_HISTORIZE
182 # Otherwise we filter on price fields asked in read
183 else:
184 price_fields = [f for f in PRODUCT_FIELD_HISTORIZE if f in fields]
185 prod_prices = price_history._get_historic_price(cr, uid, ids,
186 company_id,
187 datetime=date_crit,
188 field_name=price_fields,
189 context=context)
190 for result in results:
191 dict_value = prod_prices[result['id']]
192 result.update(dict_value)
193 return results
194
195 def write(self, cr, uid, ids, values, context=None):
196 """Create an entry in the history table for every modified price
197 of every products with current datetime (or given one in context)"""
198 if any([f in PRODUCT_FIELD_HISTORIZE for f in values]):
199 for product in self.browse(cr, uid, ids, context=context):
200 self._log_all_price_changes(cr, uid, product.id, values,
201 context=context)
202 return super(product_template, self).write(cr, uid, ids, values,
203 context=context)
204
205 def unlink(self, cr, uid, ids, context=None):
206 price_history = self.pool.get('product.price.history')
207 history_ids = price_history.search(cr, uid,
208 [('product_id', 'in', ids)],
209 context=context)
210 price_history.unlink(cr, uid, history_ids, context=context)
211 res = super(product_template, self).unlink(cr, uid, ids,
212 context=context)
213 return res
214
215
216class price_type(orm.Model):
217 """
218 The price type is used to points which field in the product form
219 is a price and in which currency is this price expressed.
220 Here, we add the company field to allow having various price type for
221 various company, may be even in different currency.
222 """
223
224 _inherit = "product.price.type"
225
48 _columns = {226 _columns = {
49 'price': fields.property('pricelist.partnerinfo',227 'company_id': fields.many2one('res.company', 'Company',
50 type='float',228 required=True),
51 string='Seller Price',
52 method=True,
53 view_load=True,
54 required=True,
55 help="This price will be considered as a price for the supplier UoM if any or the default Unit of Measure of the product otherwise"),
56 }229 }
57pricelist_partnerinfo()
58230
59# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:231 def _get_default_company(self, cr, uid, context=None):
232 company = self.pool.get('res.company')
233 return company._company_default_get(cr, uid,
234 'product.price.type',
235 context=context)
236 _defaults = {
237 'company_id': _get_default_company,
238 }
60239
=== added file 'product_price_history/product_price_history_view.xml'
--- product_price_history/product_price_history_view.xml 1970-01-01 00:00:00 +0000
+++ product_price_history/product_price_history_view.xml 2013-12-04 10:24:54 +0000
@@ -0,0 +1,90 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <record id="product_price_type_view" model="ir.ui.view">
6 <field name="name">product.price.type.form</field>
7 <field name="model">product.price.type</field>
8 <field name="inherit_id" ref="product.product_price_type_view"/>
9 <field name="arch" type="xml">
10 <field name="currency_id" groups="base.group_multi_currency" position="after">
11 <field name="company_id" groups="base.group_multi_company"/>
12 </field>
13 </field>
14 </record>
15
16 <record id="view_product_price_history" model="ir.ui.view">
17 <field name="name">product.product.price.history.tree</field>
18 <field name="model">product.product</field>
19 <field name="arch" type="xml">
20 <tree string="Product Historic Prices" create="false">
21 <field name="default_code"/>
22 <field name="name"/>
23 <field name="categ_id" invisible="1"/>
24 <field name="variants" groups="product.group_product_variant"/>
25 <field name="type"/>
26 <field name="state" groups="base.group_extended"/>
27 <field name="list_price"/>
28 <field name="standard_price"/>
29 <field name="company_id" groups="base.group_multi_company" invisible="1"/>
30 </tree>
31 </field>
32 </record>
33
34 <record id="view_product_price_history_from_product" model="ir.ui.view">
35 <field name="name">product.price.history.tree</field>
36 <field name="model">product.price.history</field>
37 <field name="arch" type="xml">
38 <tree string="Historic Prices" create="false">
39 <field name="datetime"/>
40 <field name="name"/>
41 <field name="company_id" groups="base.group_multi_company" invisible="1"/>
42 <field name="product_id"/>
43 <field name="amount"/>
44 </tree>
45 </field>
46 </record>
47
48 <record id="view_product_price_history_filter" model="ir.ui.view">
49 <field name="name">product.price.history.filter</field>
50 <field name="model">product.price.history</field>
51 <field name="arch" type="xml">
52 <search string="Search Prices History">
53 <field name="name" string="Price field"/>
54 <field name="product_id"/>
55 <field name="company_id" groups="base.group_multi_company"/>
56 <group expand="0" string="Group By...">
57 <filter string="Date" icon="terp-go-month" domain="[]" context="{'group_by':'datetime'}"/>
58 <filter string="Product" domain="[]" context="{'group_by':'product_id'}"/>
59 <filter string="Name" domain="[]" context="{'group_by':'name'}"/>
60 <filter string="Company" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
61 </group>
62 </search>
63
64 </field>
65 </record>
66
67 <record id="action_price_history" model="ir.actions.act_window">
68 <field name="name">Prices History</field>
69 <field name="type">ir.actions.act_window</field>
70 <field name="res_model">product.price.history</field>
71 <field name="view_type">form</field>
72 <field name="view_id" ref="view_product_price_history_from_product"/>
73 <field name="search_view_id" ref="view_product_price_history_filter"/>
74 </record>
75
76 <act_window
77 context="{'search_default_product_id': [active_id], 'default_product_id': active_id}"
78 id="act_product_prices_history_open"
79 name="Prices History"
80 res_model="product.price.history"
81 src_model="product.product"/>
82
83 <menuitem action="action_price_history"
84 groups="base.group_no_one"
85 id="menu_product_price_history_action_form"
86 parent="product.prod_config_main" sequence="2"/>
87
88
89 </data>
90</openerp>
091
=== added directory 'product_price_history/security'
=== added file 'product_price_history/security/ir.model.access.csv'
--- product_price_history/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ product_price_history/security/ir.model.access.csv 2013-12-04 10:24:54 +0000
@@ -0,0 +1,7 @@
1"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
2"access_product_price_history_group_user","product_price_history user","model_product_price_history","base.group_user",1,0,0,0
3"access_product_price_history_group_sale_manager","product_price_history sale manager","model_product_price_history","base.group_sale_manager",1,1,1,1
4"access_product_price_history_stock_manager","product_price_history stock manager","model_product_price_history","stock.group_stock_manager",1,1,1,1
5"access_product_price_history_stock_user","product_price_history stock user","model_product_price_history","stock.group_stock_user",1,1,0,0
6"access_product_price_history_purchase_user","product_price_history purchase user","model_product_price_history","purchase.group_purchase_user",1,0,0,0
7"access_product_price_history_purchase_manager","product_price_history purchase manager","model_product_price_history","purchase.group_purchase_manager",1,1,1,1
08
=== added file 'product_price_history/security/product_price_history_security.xml'
--- product_price_history/security/product_price_history_security.xml 1970-01-01 00:00:00 +0000
+++ product_price_history/security/product_price_history_security.xml 2013-12-04 10:24:54 +0000
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3<data noupdate="1">
4
5 <record id="product_price_type_comp_rule" model="ir.rule">
6 <field name="name" >Product Price type multi-company</field>
7 <field name="model_id" ref="model_product_price_type"/>
8 <field name="global" eval="True"/>
9 <field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
10 </record>
11
12</data>
13</openerp>
014
=== added directory 'product_price_history/test'
=== added file 'product_price_history/test/avg_price_computation_mutlicompanies_multicurrencies.yml'
--- product_price_history/test/avg_price_computation_mutlicompanies_multicurrencies.yml 1970-01-01 00:00:00 +0000
+++ product_price_history/test/avg_price_computation_mutlicompanies_multicurrencies.yml 2013-12-04 10:24:54 +0000
@@ -0,0 +1,186 @@
1-
2 Test the following with user admin from first company (EUR)
3-
4 !context
5 uid: 'base.user_root'
6-
7 Create a purchase order for first company EUR
8-
9 !record {model: purchase.order, id: purchase_order_lcost_01}:
10 partner_id: res_partner_supplier_01
11 invoice_method: order
12 location_id: location_stock_01
13 pricelist_id: purchase.list0
14 company_id: base.main_company
15 order_line:
16 - product_id: product_product_j_avg_01
17 price_unit: 100
18 product_qty: 15.0
19-
20 I confirm the order where invoice control is 'Bases on order'.
21-
22 !workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_lcost_01}
23-
24 Reception is ready to process, make it and check moves value
25-
26 !python {model: stock.partial.picking}: |
27 pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_lcost_01")).picking_ids
28 partial_id = self.create(cr, uid, {},context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]})
29 self.do_partial(cr, uid, [partial_id])
30 picking = self.pool.get('stock.picking').browse(cr, uid, [pick_ids[0].id])[0]
31 for move in picking.move_lines:
32 if move.product_id.name == 'Wine J':
33 assert move.price_unit == 100.0,"Technical field price_unit of Wine J stock move should record the purchase price"
34-
35 I check that purchase order is shipped.
36-
37 !python {model: purchase.order}: |
38 assert self.browse(cr, uid, ref("purchase_order_lcost_01")).shipped == True,"Purchase order should be delivered"
39-
40 I check that avg price of products is computed correctly
41-
42 !python {model: product.product}: |
43 xchg_rate_chf = 1.0
44 # computed as : (100 * 15 / 15) * Exchnge rate of 1.3086
45 value_a = round(100.0 * xchg_rate_chf, 2)
46 assert self.browse(cr, uid, ref("product_product_j_avg_01")).standard_price == value_a,"Avg price for product Wine J for first company is wrongly computed"
47-
48 Create a second purchase order for first company EUR
49-
50 !record {model: purchase.order, id: purchase_order_lcost_01bis}:
51 partner_id: res_partner_supplier_01
52 invoice_method: order
53 location_id: location_stock_01
54 pricelist_id: purchase.list0
55 company_id: base.main_company
56 order_line:
57 - product_id: product_product_j_avg_01
58 price_unit: 200
59 product_qty: 15.0
60-
61 I confirm the order where invoice control is 'Bases on order'.
62-
63 !workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_lcost_01bis}
64-
65 Reception is ready for process, make it and check moves value
66-
67 !python {model: stock.partial.picking}: |
68 pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_lcost_01bis")).picking_ids
69 partial_id = self.create(cr, uid, {},context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]})
70 self.do_partial(cr, uid, [partial_id])
71 picking = self.pool.get('stock.picking').browse(cr, uid, [pick_ids[0].id])[0]
72 for move in picking.move_lines:
73 if move.product_id.name == 'Wine J':
74 assert move.price_unit == 200.0,"Technical field price_unit of Wine J stock move should record the purchase price"
75-
76 I check that purchase order is shipped.
77-
78 !python {model: purchase.order}: |
79 assert self.browse(cr, uid, ref("purchase_order_lcost_01bis")).shipped == True,"Purchase order should be delivered"
80-
81 I check that avg price of products is computed correctly
82-
83 !python {model: product.product}: |
84 xchg_rate_chf = 1.0
85 # Value in stock in EUR
86 value_a = round(100.0 * xchg_rate_chf, 2)
87 # computed as : (value_a * 15 + (200 * xchg_rate_chf) * 15) / 30
88 value_abis = round((value_a * 15 + (200 * xchg_rate_chf) * 15) / 30, 2)
89 assert self.browse(cr, uid, ref("product_product_j_avg_01")).standard_price == value_abis,"Avg price for product Wine J for first company is wrongly computed"
90-
91 Test the following with user admin from second company (CHF)
92-
93 !context
94 uid: 'res_users_second_company_01'
95-
96 Create a purchase order for second company CHF
97-
98 !record {model: purchase.order, id: purchase_order_lcost_02}:
99 partner_id: res_partner_supplier_01
100 invoice_method: manual
101 location_id: location_stock_02
102 pricelist_id: product_pricelist_purchchf
103 company_id: res_company_01
104 order_line:
105 - product_id: product_product_j_avg_01
106 price_unit: 50
107 product_qty: 15.0
108-
109 I confirm the order where invoice control is 'Bases on order'.
110-
111 !workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_lcost_02}
112-
113 Reception is ready for process, make it and check moves value
114-
115 !python {model: stock.partial.picking}: |
116 pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_lcost_02")).picking_ids
117 partial_id = self.create(cr, uid, {},context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]})
118 self.do_partial(cr, uid, [partial_id])
119 picking = self.pool.get('stock.picking').browse(cr, uid, [pick_ids[0].id])[0]
120 for move in picking.move_lines:
121 if move.product_id.name == 'Wine J':
122 assert move.price_unit == 50.0,"Technical field price_unit of Wine J stock move should record the purchase price"
123-
124 I check that purchase order is shipped.
125-
126 !python {model: purchase.order}: |
127 assert self.browse(cr, uid, ref("purchase_order_lcost_02")).shipped == True,"Purchase order should be delivered"
128-
129 I check that avg price of products is computed correctly
130-
131 !python {model: product.product}: |
132 # value in USD stored
133 value_a = round(50 * (1.2086 / 1.3086), 2)
134 assert self.browse(cr, uid, ref("product_product_j_avg_01")).standard_price == value_a,"Avg price for product Wine J for second company is wrongly computed"
135-
136 Create a second purchase order for second company CHF
137-
138 !record {model: purchase.order, id: purchase_order_lcost_02bis}:
139 partner_id: res_partner_supplier_01
140 invoice_method: manual
141 location_id: location_stock_02
142 pricelist_id: product_pricelist_purchchf
143 company_id: res_company_01
144 order_line:
145 - product_id: product_product_j_avg_01
146 price_unit: 100
147 product_qty: 15.0
148-
149 I confirm the order where invoice control is 'Bases on order'.
150-
151 !workflow {model: purchase.order, action: purchase_confirm, ref: purchase_order_lcost_02bis}
152-
153 Reception is ready for process, make it and check moves value
154-
155 !python {model: stock.partial.picking}: |
156 pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_lcost_02bis")).picking_ids
157 partial_id = self.create(cr, uid, {},context={'active_model': 'stock.picking','active_ids': [pick_ids[0].id]})
158 self.do_partial(cr, uid, [partial_id])
159 picking = self.pool.get('stock.picking').browse(cr, uid, [pick_ids[0].id])[0]
160 for move in picking.move_lines:
161 if move.product_id.name == 'Wine J':
162 assert move.price_unit == 100.0,"Technical field price_unit of Wine J stock move should record the purchase price"
163-
164 I check that purchase order is shipped.
165-
166 !python {model: purchase.order}: |
167 assert self.browse(cr, uid, ref("purchase_order_lcost_02bis")).shipped == True,"Purchase order should be delivered"
168-
169 I check that avg price of products is computed correctly
170-
171 !python {model: product.product}: |
172 # Value in stock in USD for first entry (compute as to_currency / from_currency)
173 value_a = round(50 * (1.2086 / 1.3086), 2)
174 # Value in stock in USD for second entry (compute as to_currency / from_currency)
175 value_b = round(100 * (1.2086 / 1.3086), 2)
176 # computed as : (value_a * 15 + value_b * 15) / 30
177 value_abis = round((value_a * 15 + value_b * 15) / 30, 2)
178 assert self.browse(cr, uid, ref("product_product_j_avg_01")).standard_price == value_abis,"Avg price for product Wine J for second company is wrongly computed"
179-
180 I Check that I get all entries in the price history table
181-
182 !python {model: product.price.history}: |
183 num_j = self.search(cr, uid, [('product_id','=',ref("product_product_j_avg_01")),('name','=','standard_price')])
184 # 4 PO, 4 updates of standard_price
185 right_number_j = 4
186 assert len(num_j) == right_number_j,"The number of value in the price history table is correct for product J"
0187
=== added file 'product_price_history/test/price_controlling_multicompany.yml'
--- product_price_history/test/price_controlling_multicompany.yml 1970-01-01 00:00:00 +0000
+++ product_price_history/test/price_controlling_multicompany.yml 2013-12-04 10:24:54 +0000
@@ -0,0 +1,55 @@
1-
2 Test the following with user admin from first company (EUR)
3-
4 !context
5 uid: 'base.user_root'
6-
7 Create a wine A product owned by both company and set price for first company (EUR)
8-
9 !record {model: product.product, id: product_product_a_avg_01}:
10 categ_id: product.product_category_1
11 name: Wine A
12 cost_method: standard
13 uom_id: product.product_uom_unit
14 uom_po_id: product.product_uom_unit
15 company_id: 0
16 standard_price: 50.0
17 list_price: 75.0
18-
19 Test the prices are those set for the first company (EUR)
20-
21 !python {model: product.product}: |
22 product = self.browse(cr, uid, ref('product_product_a_avg_01'))
23 assert product.standard_price == 50.0, "The standard_price has not been recorded correctly for first company"
24 assert product.list_price == 75.0, "The list_price has not been recorded correctly for first company"
25-
26 Test the following with user second_user from second company (CHF)
27-
28 !context
29 uid: 'res_users_second_company_01'
30-
31 Modify product A owned by both company and set price in USD for second company (CHF)
32-
33 !python {model: product.product}: |
34 self.write(cr, uid, ref('product_product_a_avg_01'), {'standard_price':70,'list_price':90})
35-
36 Test the USD prices are those set for the second company (CHF)
37-
38 !python {model: product.product}: |
39 product = self.browse(cr, uid, ref('product_product_a_avg_01'))
40 assert product.standard_price == 70.0, "The standard_price has not been recorded correctly for first company"
41 assert product.list_price == 90.0, "The list_price has not been recorded correctly for first company"
42-
43 Test the following with user admin from first company (EUR)
44-
45 !context
46 uid: 'base.user_root'
47-
48 Test the prices are still the same for first company (EUR)
49-
50 !python {model: product.product}: |
51 product = self.browse(cr, uid, ref('product_product_a_avg_01'))
52 assert product.standard_price == 50.0, "The standard_price has not been recorded correctly for first company"
53 assert product.list_price == 75.0, "The list_price has not been recorded correctly for first company"
54
55
056
=== added file 'product_price_history/test/price_historization.yml'
--- product_price_history/test/price_historization.yml 1970-01-01 00:00:00 +0000
+++ product_price_history/test/price_historization.yml 2013-12-04 10:24:54 +0000
@@ -0,0 +1,55 @@
1-
2 Test the following with user admin from first company (EUR)
3-
4 !context
5 uid: 'base.user_root'
6-
7 Modify product K at first day of year and set price in EUR for first company (EUR)
8-
9 !python {model: product.product}: |
10 import time
11 ctx = context
12 ctx.update({'to_date':time.strftime('%Y-01-01 %H:%M:%S')})
13 print ctx
14 self.write(cr, uid, ref('product_product_k_avg_01'), {'standard_price':70,'list_price':90}, context=ctx)
15-
16 Test the EUR prices are those just set on the first day of year
17-
18 !python {model: product.product}: |
19 import time
20 ctx = context
21 ctx.update({'to_date':time.strftime('%Y-01-01 %H:%M:%S')})
22 product = self.browse(cr, uid, ref('product_product_k_avg_01'), context=ctx)
23 assert product.standard_price == 70.0, "The standard_price has not been recorded correctly for first company"
24 assert product.list_price == 90.0, "The list_price has not been recorded correctly for first company"
25-
26 Modify product K at 3rd day of year and set price in EUR for first company (EUR)
27-
28 !python {model: product.product}: |
29 import time
30 ctx = context
31 ctx.update({'to_date':time.strftime('%Y-01-03 %H:%M:%S')})
32 print ctx
33 self.write(cr, uid, ref('product_product_k_avg_01'), {'standard_price':80,'list_price':100}, context=ctx)
34-
35 Test the EUR prices 2nd day of year
36-
37 !python {model: product.product}: |
38 import time
39 ctx = context
40 ctx.update({'to_date':time.strftime('%Y-01-02 %H:%M:%S')})
41 print ctx
42 product = self.browse(cr, uid, ref('product_product_k_avg_01'),context=ctx)
43 assert product.standard_price == 70.0, "The standard_price has not been retrieved correctly for first company"
44 assert product.list_price == 90.0, "The list_price has not been retrieved correctly for first company"
45-
46 Test the EUR prices 3rd day of year
47-
48 !python {model: product.product}: |
49 import time
50 ctx = context
51 ctx.update({'to_date':time.strftime('%Y-01-03 %H:%M:%S')})
52 print ctx
53 product = self.browse(cr, uid, ref('product_product_k_avg_01'),context=ctx)
54 assert product.standard_price == 80.0, "The standard_price has not been retrieved correctly for first company"
55 assert product.list_price == 100.0, "The list_price has not been retrieved correctly for first company"
056
=== added directory 'product_price_history/wizard'
=== added file 'product_price_history/wizard/__init__.py'
--- product_price_history/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ product_price_history/wizard/__init__.py 2013-12-04 10:24:54 +0000
@@ -0,0 +1,24 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright 2013 Camptocamp SA
6# Author: Joel Grand-Guillaume
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from . import historic_prices
24
025
=== added file 'product_price_history/wizard/historic_prices.py'
--- product_price_history/wizard/historic_prices.py 1970-01-01 00:00:00 +0000
+++ product_price_history/wizard/historic_prices.py 2013-12-04 10:24:54 +0000
@@ -0,0 +1,70 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Alexandre Fayolle, Joel Grand-Guillaume
5# Copyright 2012 Camptocamp SA
6#
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.
11#
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.
16#
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/>.
19#
20##############################################################################
21from openerp.osv import orm, fields
22from openerp.tools.translate import _
23import time
24
25
26class historic_prices(orm.TransientModel):
27 _name = 'historic.prices'
28 _description = 'Product historical prices'
29
30 _columns = {
31 'to_date': fields.date(
32 'Date',
33 help='Date at which the analysis need to be done. '
34 'Note that the date is understood as this day at midnight, so you may want to '
35 'specify the day after ! No date is the last value.'),
36 }
37
38 def action_open_window(self, cr, uid, ids, context=None):
39 """
40 Open the historical prices view
41 """
42 if context is None:
43 context = {}
44 user_obj = self.pool.get('res.users')
45 wiz = self.read(cr, uid, ids, [], context=context)[0]
46 ctx = context.copy()
47 if wiz.get('to_date'):
48 ctx.update(
49 to_date=wiz.get('to_date')
50 )
51 data_pool = self.pool.get('ir.model.data')
52 filter_ids = data_pool.get_object_reference(cr, uid, 'product',
53 'product_search_form_view')
54 product_view_id = data_pool.get_object_reference(cr, uid,
55 'product_price_history',
56 'view_product_price_history')
57 if filter_ids:
58 filter_id = filter_ids[1]
59 else:
60 filter_id = 0
61 return {
62 'type': 'ir.actions.act_window',
63 'name': _('Historical Prices'),
64 'context': ctx,
65 'view_type': 'form',
66 'view_mode': 'tree',
67 'res_model': 'product.product',
68 'view_id': product_view_id[1],
69 'search_view_id': filter_id,
70 }
071
=== added file 'product_price_history/wizard/historic_prices_view.xml'
--- product_price_history/wizard/historic_prices_view.xml 1970-01-01 00:00:00 +0000
+++ product_price_history/wizard/historic_prices_view.xml 2013-12-04 10:24:54 +0000
@@ -0,0 +1,36 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <record id="view_historical_prices" model="ir.ui.view">
5 <field name="name">historic.prices.form</field>
6 <field name="model">historic.prices</field>
7 <field name="arch" type="xml">
8 <form string="Historical prices" version="7.0">
9 <group>
10 <field name="to_date"/>
11 </group>
12 <footer>
13 <button name="action_open_window" string="Compute prices" type="object" icon="gtk-execute" class="oe_highlight"/>
14 or
15 <button string="Cancel" class="oe_link" special="cancel" />
16 </footer>
17 </form>
18 </field>
19 </record>
20
21 <record id="action_product_historic_prices_view" model="ir.actions.act_window">
22 <field name="name">Product Historical Prices</field>
23 <field name="res_model">historic.prices</field>
24 <field name="view_type">form</field>
25 <field name="view_mode">tree,form</field>
26 <field name="view_id" ref="view_historical_prices"/>
27 <field name="target">new</field>
28 </record>
29
30 <menuitem action="action_product_historic_prices_view"
31 id="menu_action_product_historic_prices_tree"
32 parent="stock.next_id_61" />
33
34
35 </data>
36</openerp>

Subscribers

People subscribed via source and target branches