Merge lp:~jgrandguillaume-c2c/openobject-addons/multi-company-cost-price into lp:openobject-addons

Proposed by Joël Grand-Guillaume @ camptocamp
Status: Merged
Merged at revision: 3001
Proposed branch: lp:~jgrandguillaume-c2c/openobject-addons/multi-company-cost-price
Merge into: lp:openobject-addons
Diff against target: 1134 lines (+381/-161)
23 files modified
account/account_analytic_line.py (+64/-5)
account/project/project.py (+3/-7)
account/project/project_view.xml (+18/-8)
account_analytic_analysis/account_analytic_analysis.py (+22/-37)
analytic/project.py (+85/-61)
analytic_user_function/analytic_user_function.py (+10/-4)
hr_expense/hr_expense.py (+8/-2)
hr_expense/hr_expense_view.xml (+2/-2)
hr_timesheet/hr_timesheet.py (+3/-1)
hr_timesheet_invoice/hr_timesheet_invoice.py (+7/-6)
hr_timesheet_invoice/hr_timesheet_invoice_view.xml (+13/-1)
multi_company/__init__.py (+0/-1)
multi_company/__terp__.py (+1/-1)
product/__init__.py (+1/-1)
product/__terp__.py (+1/-0)
product/company.py (+53/-0)
product/company_view.xml (+18/-0)
product/pricelist.py (+1/-0)
product/product_data.xml (+8/-1)
project_timesheet/project_timesheet.py (+12/-3)
stock/stock.py (+34/-9)
stock/wizard/wizard_partial_move.py (+8/-5)
stock/wizard/wizard_partial_picking.py (+9/-6)
To merge this branch: bzr merge lp:~jgrandguillaume-c2c/openobject-addons/multi-company-cost-price
Reviewer Review Type Date Requested Status
Xavier (Open ERP) (community) Needs Fixing
Joël Grand-Guillaume @ camptocamp (community) Needs Resubmitting
Fabien (Open ERP) Disapprove
Stephane Wirtel (OpenERP) Pending
Grzegorz Grzelak (OpenGLOBE.pl) Pending
Christophe CHAUVET Pending
Raphaël Valyi - http://www.akretion.com Pending
Review via email: mp+17887@code.launchpad.net

This proposal supersedes a proposal from 2010-01-11.

To post a comment you must log in.
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal

Hi !

This is the merge proposal from Camptocamp to improve multi-company into OpenERP regarding to product costs in manufacturing industry and in services company.

What has been done here:

 * Add price type on company as a property (with default value based on standard price)

 * Stock accounting
  * Use the price type currency and field for cost valuation
  * Into stock move for standard price
  * Into stock move for average price

 * Analytic accounting
  * Use the price type currency and field for cost valuation (including timesheet)
  * Add multi-currency on analytic lines (similar to financial accounting)
  * Allow to share the same product between company employees, with different cost for each one
  * Correct all "costs" indicators into analytic account to base them on the right currency (owner's company)

 * By default, nothing change for single company implementation (base the cost valuation on standard price)

As a result, we can now really share the same product between companies that doesn't have the same currency and/or same cost price.
We can also manage one field per company on the product form to store the cost for a given price type (and so for a given company).

Refer to the blueprint for more details:

https://blueprints.launchpad.net/openobject-addons/+spec/multi-cost-price-and-product-currency

Thanks in advance for your review.

Regards,

Joël

Revision history for this message
Raphaël Valyi - http://www.akretion.com (rvalyi) wrote : Posted in a previous version of this proposal

Hello, one thing that I can't understand is why you add a field in product and views called "standard_price_usd" by default?
Is that a typo?
If not, I think we shouldn't favor some country price by default, especially if there is just one like that. I agree that often you would need such field, but then I think you should rather add it at integration time, else is seems to me a bit arbitrary.
If that's a typo, please make sure you don't have such typo in your merge proposal.

Revision history for this message
Raphaël Valyi - http://www.akretion.com (rvalyi) : Posted in a previous version of this proposal
review: Needs Fixing
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal

Hi !

I agree with you Raphaël. I understood that the multi_company module is only an example of multi-company config... So I add an example here to allow people understand how it should work.

Otherwise, the rest is clean. If you think I'm wrong with that, I'll remove it from multi_company module and suggest the merge again.

Personally, I think it's good to have an example, but it's ok for me to remove it.

Let me know,

Regards,

Joël

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

Hi !

This is the merge proposal from Camptocamp to improve multi-company into OpenERP regarding to product costs in manufacturing industry and in services company.

What has been done here:

 * Add price type on company as a property (with default value based on standard price)

 * Stock accounting
  * Use the price type currency and field for cost valuation
  * Into stock move for standard price
  * Into stock move for average price

 * Analytic accounting
  * Use the price type currency and field for cost valuation (including timesheet)
  * Add multi-currency on analytic lines (similar to financial accounting)
  * Allow to share the same product between company employees, with different cost for each one
  * Correct all "costs" indicators into analytic account to base them on the right currency (owner's company)

 * By default, nothing change for single company implementation (base the cost valuation on standard price)

 * Factorise part of function field into analytic accounting

As a result, we can now really share the same product between companies that doesn't have the same currency and/or same cost price.
We can also manage one field per company on the product form to store the cost for a given price type (and so for a given company).

Refer to the blueprint for more details:

https://blueprints.launchpad.net/openobject-addons/+spec/multi-cost-price-and-product-currency

Thanks in advance for your review.

Regards,

Joël

P.S. The field standard_price_usd is an example, committed into an sample module to show how to configure this use case... It's not a typo errors...

Revision history for this message
Fabien (Open ERP) (fp-tinyerp) wrote :

It covers interesting needs but can not be merged as it. Lot's of things have to be rewritten to be more generic.

review: Disapprove
Revision history for this message
Fabien (Open ERP) (fp-tinyerp) wrote :

For example, this is not acceptable in the official, generic, version:

888 +class product_product(osv.osv):
889 + _inherit = "product.product"
891 + _columns = {
892 + 'standard_price_usd': fields.float('Cost Price USD', required=True, digits=(16, int(config['price_accuracy'])),
893 + help="Product's cost in USDfor accounting stock valuation."),
894 + }
896 +product_product()

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

Hi,

First, thanks for reviewing :)

Please, Raphaal already told me this the first time, but this module is (in my own understanding) a demo on how to setup multi-company !

That's why I write it the "standard_price_usd" in the code, to illustrate how we can handle this problematic !! I put it in the multi_company module as Syleam and you did to put some demo data for multi company, I followed you !!!

Please, have a look closer, I'm ready to invest more time on that. It's a need my customer strongly want. We need a solution.

Could we discuss the features in their-self ? Not the demo stuff, I remove them in the minute if you want !

Let me know your advices, and I will correct what's need to be done. This way everyone win : My customer, me and OpenERP !

Thanks,

Kind regards,

Joël

Revision history for this message
Stephane Wirtel (OpenERP) (stephane-openerp) wrote :

Can you remove this point from your code and add a new comment with your example in this bug report.

Thanks

2551. By Joël Grand-Guillaume @ camptocamp

[DEL] Remove the demo data in multi-company module as asked by Fabien

2552. By Joël Grand-Guillaume @ camptocamp

[DEL] Remove the multi-company view from multi-company

2553. By Joël Grand-Guillaume @ camptocamp

[MRG] Merge the last trunk in order to ease the merge from Tiny

2554. By Joël Grand-Guillaume @ camptocamp

[REF] Refactoring : moving the project.py from account to analytic module as it was done by Tiny

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

Hi,

Well it's done ! I just remove every example fields from demo data in multicompany module. I also merge the last trunk of the day for you, so it's easier for you to apply it.

If you don't agree with one of my new features, let me know. I really invest lots of time to design those new features with my customer. I'm expecting you to consider it seriouly : if you think to refuse it again, let me know how I could help to integrate it in the core.

I mean, this is my goal, I don't want a half solution. I want this in the core of OpenERP, whatever I have to change, as long as the needed feature are implemented.

Thanks for your time and consideration,

Joël

review: Needs Resubmitting
Revision history for this message
Fabien (Open ERP) (fp-tinyerp) wrote :

I checked the logic and it seems good. If someone can check the code and if it's right, you can merge.

Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

Fabien considers the business logic good so I have no issue with that, but on the style/tech front I have a few from a quick overview of the branch:

Inconsistency
=============

stock/wizard/wizard_partial_move.py and stock/wizard/wizard_partial_picking.py seem to have been modified in similar but not identical ways: in both cases `amount_unit` is computed through `product.price_get(pricetype.field, context)[product.id]` but while the latter uses `amount_unit` on the next line, the former uses `product.amount_unit` and never calls `amount_unit`. This might be a bug in either of them.

(I also note a high level of redundancy between these wizards (at least on this specific method), they might benefit from from de-duplication in the future, to avoid that kind of potential issues)

Commented code
==============

In a few places, you commented existing code or committed commented code. Please remove these instances, removed code can be found via the VCS's history, and I don't quite see the justification for added already commented code (if it's work in progress its place is in a non-merged branch, if it's something to add/complete, it should be in a bug on the tracker):

* hr_timesheet_invoice/hr_timesheet_invoice.py at revid:<email address hidden> (commented existing code)
* account_analytic_analysis/account_analytic_analysis.py at revid:<email address hidden> (added a commented method)

Style
=====

At revid:<email address hidden>, in account_analytic_analysis/account_analytic_analysis.py you perform a test using dict.has_key. In this case, please either use `'key' in dict` (`has_key` is deprecated using Python2.6 -3, and doesn't exist anymore in Python 3). Furthermore this specific instance would probably be simpler by using `dict.setdefault` or a `collections.defaultdict` instance.

As a side note, in a few places you edited code using old-style difference operators (<>). If you can (not in this branch, but in the future) don't hesitate swapping them for "modern" difference operators (!=).

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

Hi,

Thanks for those constructive comments !! I'll make those changes ASAP.

Little remark : those wizard are really fat, and I know that.. But I can't refactor everything at once right :) ?

I really appreciate you consider my work. I'll remember it !

Have a nice week-end,

Regards,

Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

> Little remark : those wizard are really fat, and I know that.. But I can't refactor everything at once right :) ?

Yeah, it was more of a tentative note for me (or anybody who reads this thing)

> I really appreciate you consider my work. I'll remember it !

Pleasure.

2555. By Joël Grand-Guillaume @ camptocamp

[FIX] According to Xavier (OpenERP) to fit OpenERP requierements : remove commented code, use != instead of <>, fix picking wizard.

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

Hi Xavier,

I change everything according to your comments. I hope this is fine for you now.

Summary:

- Change the stocks wizards (both with amount_unit)
- Remove commented code (hope I don't miss some...)
- Change <> for !=

Note, I don't find the ".has_key" you talked about. So, in case of trouble with this, feel free to rewrite that point for the merge.

Thanks in advance for merging this !

Regards,

Joël

Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

Merged, the _check_currency validator threw some error when trying to install all the demo data, but if there's a bug in that it'll probably be sniffed out during usage.

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

Hi,

Thanks a lot for that !

Best regards,

Joël

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'account/account_analytic_line.py'
--- account/account_analytic_line.py 2010-01-12 09:18:39 +0000
+++ account/account_analytic_line.py 2010-02-15 10:42:23 +0000
@@ -25,10 +25,46 @@
25from osv import osv25from osv import osv
26from tools.translate import _26from tools.translate import _
27import tools27import tools
28from tools import config
2829
29class account_analytic_line(osv.osv):30class account_analytic_line(osv.osv):
30 _name = 'account.analytic.line'31 _name = 'account.analytic.line'
31 _description = 'Analytic lines'32 _description = 'Analytic lines'
33
34 def _amount_currency(self, cr, uid, ids, field_name, arg, context={}):
35 result = {}
36 for rec in self.browse(cr, uid, ids, context):
37 cmp_cur_id=rec.company_id.currency_id.id
38 aa_cur_id=rec.account_id.currency_id.id
39 # Always provide the amount in currency
40 if cmp_cur_id != aa_cur_id:
41 cur_obj = self.pool.get('res.currency')
42 ctx = {}
43 if rec.date and rec.amount:
44 ctx['date'] = rec.date
45 result[rec.id] = cur_obj.compute(cr, uid, rec.company_id.currency_id.id,
46 rec.account_id.currency_id.id, rec.amount,
47 context=ctx)
48 else:
49 result[rec.id]=rec.amount
50 return result
51
52 def _get_account_currency(self, cr, uid, ids, field_name, arg, context={}):
53 result = {}
54 for rec in self.browse(cr, uid, ids, context):
55 # Always provide second currency
56 result[rec.id] = (rec.account_id.currency_id.id,rec.account_id.currency_id.code)
57 return result
58
59 def _get_account_line(self, cr, uid, ids, context={}):
60 aac_ids = {}
61 for acc in self.pool.get('account.analytic.account').browse(cr, uid, ids):
62 aac_ids[acc.id] = True
63 aal_ids = []
64 if aac_ids:
65 aal_ids = self.pool.get('account.analytic.line').search(cr, uid, [('account_id','in',aac_ids.keys())], context=context)
66 return aal_ids
67
32 _columns = {68 _columns = {
33 'name' : fields.char('Description', size=256, required=True),69 'name' : fields.char('Description', size=256, required=True),
34 'date' : fields.date('Date', required=True),70 'date' : fields.date('Date', required=True),
@@ -42,14 +78,27 @@
42 'journal_id' : fields.many2one('account.analytic.journal', 'Analytic Journal', required=True, ondelete='cascade', select=True),78 'journal_id' : fields.many2one('account.analytic.journal', 'Analytic Journal', required=True, ondelete='cascade', select=True),
43 'code' : fields.char('Code', size=8),79 'code' : fields.char('Code', size=8),
44 'user_id' : fields.many2one('res.users', 'User',),80 'user_id' : fields.many2one('res.users', 'User',),
81 'currency_id': fields.function(_get_account_currency, method=True, type='many2one', relation='res.currency', string='Account currency',
82 store={
83 'account.analytic.account': (_get_account_line, ['company_id'], 50),
84 'account.analytic.line': (lambda self,cr,uid,ids,c={}: ids, ['amount','unit_amount'],10),
85 },
86 help="The related account currency if not equal to the company one."),
87 'company_id': fields.many2one('res.company','Company',required=True),
88 'amount_currency': fields.function(_amount_currency, method=True, digits=(16, int(config['price_accuracy'])), string='Amount currency',
89 store={
90 'account.analytic.account': (_get_account_line, ['company_id'], 50),
91 'account.analytic.line': (lambda self,cr,uid,ids,c={}: ids, ['amount','unit_amount'],10),
92 },
93 help="The amount expressed in the related account currency if not equal to the company one."),
45 'ref': fields.char('Reference', size=32),94 'ref': fields.char('Reference', size=32),
46 }95 }
47 _defaults = {96 _defaults = {
48 'date': lambda *a: time.strftime('%Y-%m-%d'),97 'date': lambda *a: time.strftime('%Y-%m-%d'),
98 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.analytic.line', c),
49 }99 }
50 _order = 'date'100 _order = 'date'
51 101
52
53 def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):102 def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
54 if context is None:103 if context is None:
55 context = {}104 context = {}
@@ -73,11 +122,15 @@
73# (_check_company, 'You can not create analytic line that is not in the same company than the account line', ['account_id'])122# (_check_company, 'You can not create analytic line that is not in the same company than the account line', ['account_id'])
74 ]123 ]
75 124
76 def on_change_unit_amount(self, cr, uid, id, prod_id, unit_amount,125 # Compute the cost based on the price type define into company
126 # property_valuation_price_type property
127 def on_change_unit_amount(self, cr, uid, id, prod_id, unit_amount,company_id,
77 unit=False, context=None):128 unit=False, context=None):
129 if context==None:
130 context={}
78 uom_obj = self.pool.get('product.uom')131 uom_obj = self.pool.get('product.uom')
79 product_obj = self.pool.get('product.product')132 product_obj = self.pool.get('product.product')
80# if unit_amount and prod_id:133 company_obj=self.pool.get('res.company')
81 if prod_id:134 if prod_id:
82 prod = product_obj.browse(cr, uid, prod_id)135 prod = product_obj.browse(cr, uid, prod_id)
83 a = prod.product_tmpl_id.property_account_expense.id136 a = prod.product_tmpl_id.property_account_expense.id
@@ -88,8 +141,14 @@
88 _('There is no expense account defined ' \141 _('There is no expense account defined ' \
89 'for this product: "%s" (id:%d)') % \142 'for this product: "%s" (id:%d)') % \
90 (prod.name, prod.id,))143 (prod.name, prod.id,))
91 amount = unit_amount * uom_obj._compute_price(cr, uid,144 if not company_id:
92 prod.uom_id.id, prod.standard_price, unit)145 company_id=company_obj._company_default_get(cr, uid, 'account.analytic.line', context)
146
147 # Compute based on pricetype
148 pricetype=self.pool.get('product.price.type').browse(cr,uid,company_obj.browse(cr,uid,company_id).property_valuation_price_type.id)
149 amount_unit=prod.price_get(pricetype.field, context)[prod.id]
150
151 amount=amount_unit*unit_amount or 1.0
93 return {'value': {152 return {'value': {
94 'amount': - round(amount, 2),153 'amount': - round(amount, 2),
95 'general_account_id': a,154 'general_account_id': a,
96155
=== modified file 'account/project/project.py'
--- account/project/project.py 2010-02-05 15:09:27 +0000
+++ account/project/project.py 2010-02-15 10:42:23 +0000
@@ -1,8 +1,8 @@
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 (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6#6#
7# This program is free software: you can redistribute it and/or modify7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as8# it under the terms of the GNU Affero General Public License as
@@ -15,7 +15,7 @@
15# GNU Affero General Public License for more details.15# GNU Affero General Public License for more details.
16#16#
17# You should have received a copy of the GNU Affero General Public License17# 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/>.18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#19#
20##############################################################################20##############################################################################
2121
@@ -25,10 +25,6 @@
25from osv import fields25from osv import fields
26from osv import osv26from osv import osv
2727
28#
29# Object definition
30#
31
32class account_analytic_journal(osv.osv):28class account_analytic_journal(osv.osv):
33 _name = 'account.analytic.journal'29 _name = 'account.analytic.journal'
34 _columns = {30 _columns = {
3531
=== modified file 'account/project/project_view.xml'
--- account/project/project_view.xml 2010-01-19 07:35:47 +0000
+++ account/project/project_view.xml 2010-02-15 10:42:23 +0000
@@ -69,6 +69,7 @@
69 <field name="parent_id" on_change="on_change_parent(parent_id)"/>69 <field name="parent_id" on_change="on_change_parent(parent_id)"/>
70 <field name="company_id" select="2" widget="selection"/>70 <field name="company_id" select="2" widget="selection"/>
71 <field name="type" select="2"/>71 <field name="type" select="2"/>
72 <field name="company_currency_id" select="2"/>
72 </group>73 </group>
73 <notebook colspan="4">74 <notebook colspan="4">
74 <page string="Account Data">75 <page string="Account Data">
@@ -147,6 +148,9 @@
147 <field name="move_id" select="2"/>148 <field name="move_id" select="2"/>
148 <field name="unit_amount" select="2"/>149 <field name="unit_amount" select="2"/>
149 <field name="ref" select="2"/>150 <field name="ref" select="2"/>
151 <field name="currency_id" select="2"/>
152 <field name="amount_currency" select="2"/>
153 <field name="company_id" select="2"/>
150 <newline/>154 <newline/>
151 <field name="product_id" select="2"/>155 <field name="product_id" select="2"/>
152 <field name="product_uom_id" select="2"/>156 <field name="product_uom_id" select="2"/>
@@ -159,16 +163,19 @@
159 <field name="type">tree</field>163 <field name="type">tree</field>
160 <field name="arch" type="xml">164 <field name="arch" type="xml">
161 <tree editable="top" string="Analytic Entries">165 <tree editable="top" string="Analytic Entries">
162 <field name="date"/>166 <field name="date" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
163 <field name="name"/>167 <field name="name"/>
164 <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, product_uom_id)" sum="Total quantity"/>168 <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)" sum="Total quantity"/>
165 <field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, product_uom_id)"/>169 <field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
166 <field domain="[('type','=','normal')]" name="account_id"/>170 <field domain="[('type','=','normal')]" name="account_id"/>
167 <field invisible="True" name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, product_uom_id)"/>171 <field invisible="True" name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
168 <field name="amount" sum="Total amount"/>172 <field name="amount" sum="Total amount"/>
169 <field name="general_account_id"/>173 <field name="general_account_id"/>
170 <field name="journal_id"/>174 <field name="journal_id"/>
171 <field name="ref"/>175 <field name="ref"/>
176 <field name="currency_id" />
177 <field name="amount_currency" />
178 <field name="company_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
172 </tree>179 </tree>
173 </field>180 </field>
174 </record>181 </record>
@@ -225,13 +232,16 @@
225 <form string="Project line">232 <form string="Project line">
226 <field name="name"/>233 <field name="name"/>
227 <field name="account_id"/>234 <field name="account_id"/>
228 <field name="date"/>235 <field name="date" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
229 <field name="journal_id"/>236 <field name="journal_id"/>
230 <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, product_uom_id)"/>237 <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
231 <field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, product_uom_id)"/>238 <field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
232 <field name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, product_uom_id)"/>239 <field name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
233 <field invisible="True" name="general_account_id"/>240 <field invisible="True" name="general_account_id"/>
234 <field name="amount"/>241 <field name="amount"/>
242 <field name="currency_id" />
243 <field name="amount_currency" />
244 <field name="company_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)"/>
235 </form>245 </form>
236 </field>246 </field>
237 </record>247 </record>
238248
=== modified file 'account_analytic_analysis/account_analytic_analysis.py'
--- account_analytic_analysis/account_analytic_analysis.py 2010-02-01 08:29:39 +0000
+++ account_analytic_analysis/account_analytic_analysis.py 2010-02-15 10:42:23 +0000
@@ -34,7 +34,8 @@
34 res = {}34 res = {}
35 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])35 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
36 if ids2:36 if ids2:
37 cr.execute("select account_analytic_line.account_id, COALESCE(sum(amount),0.0) \37 acc_set = ",".join(map(str, ids2))
38 cr.execute("select account_analytic_line.account_id, COALESCE(sum(amount_currency),0.0) \
38 from account_analytic_line \39 from account_analytic_line \
39 join account_analytic_journal \40 join account_analytic_journal \
40 on account_analytic_line.journal_id = account_analytic_journal.id \41 on account_analytic_line.journal_id = account_analytic_journal.id \
@@ -43,15 +44,8 @@
43 group by account_analytic_line.account_id" ,(ids2,))44 group by account_analytic_line.account_id" ,(ids2,))
44 for account_id, sum in cr.fetchall():45 for account_id, sum in cr.fetchall():
45 res[account_id] = round(sum,2)46 res[account_id] = round(sum,2)
46 for obj_id in ids:47
47 res.setdefault(obj_id, 0.0)48 return self._compute_currency_for_level_tree(cr, uid, ids, ids2, res, acc_set, context)
48 for child_id in self.search(cr, uid,
49 [('parent_id', 'child_of', [obj_id])]):
50 if child_id != obj_id:
51 res[obj_id] += res.get(child_id, 0.0)
52 for id in ids:
53 res[id] = round(res.get(id, 0.0),2)
54 return res
5549
56 def _ca_to_invoice_calc(self, cr, uid, ids, name, arg, context={}):50 def _ca_to_invoice_calc(self, cr, uid, ids, name, arg, context={}):
57 res = {}51 res = {}
@@ -59,6 +53,10 @@
59 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])53 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
60 if ids2:54 if ids2:
61 # Amount uninvoiced hours to invoice at sale price55 # Amount uninvoiced hours to invoice at sale price
56 # Warnning
57 # This computation doesn't take care of pricelist !
58 # Just consider list_price
59 acc_set = ",".join(map(str, ids2))
62 cr.execute("""SELECT account_analytic_account.id, \60 cr.execute("""SELECT account_analytic_account.id, \
63 COALESCE(sum (product_template.list_price * \61 COALESCE(sum (product_template.list_price * \
64 account_analytic_line.unit_amount * \62 account_analytic_line.unit_amount * \
@@ -83,17 +81,6 @@
83 for account_id, sum in cr.fetchall():81 for account_id, sum in cr.fetchall():
84 res[account_id] = round(sum,2)82 res[account_id] = round(sum,2)
8583
86 # Expense amount and purchase invoice
87 #acc_set = ",".join(map(str, ids2))
88 #cr.execute ("select account_analytic_line.account_id, sum(amount) \
89 # from account_analytic_line \
90 # join account_analytic_journal \
91 # on account_analytic_line.journal_id = account_analytic_journal.id \
92 # where account_analytic_line.account_id IN (%s) \
93 # and account_analytic_journal.type = 'purchase' \
94 # GROUP BY account_analytic_line.account_id;"%acc_set)
95 #for account_id, sum in cr.fetchall():
96 # res2[account_id] = round(sum,2)
97 for obj_id in ids:84 for obj_id in ids:
98 res.setdefault(obj_id, 0.0)85 res.setdefault(obj_id, 0.0)
99 res2.setdefault(obj_id, 0.0)86 res2.setdefault(obj_id, 0.0)
@@ -160,7 +147,9 @@
160 res = {}147 res = {}
161 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])148 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
162 if ids2:149 if ids2:
163 cr.execute("""select account_analytic_line.account_id,COALESCE(sum(amount),0.0) \150 acc_set = ",".join(map(str, ids2))
151 cr.execute("""select account_analytic_line.account_id,COALESCE(sum(amount_currency),0.0) \
152
164 from account_analytic_line \153 from account_analytic_line \
165 join account_analytic_journal \154 join account_analytic_journal \
166 on account_analytic_line.journal_id = account_analytic_journal.id \155 on account_analytic_line.journal_id = account_analytic_journal.id \
@@ -169,20 +158,16 @@
169 GROUP BY account_analytic_line.account_id""",(ids2,))158 GROUP BY account_analytic_line.account_id""",(ids2,))
170 for account_id, sum in cr.fetchall():159 for account_id, sum in cr.fetchall():
171 res[account_id] = round(sum,2)160 res[account_id] = round(sum,2)
172 for obj_id in ids:161 return self._compute_currency_for_level_tree(cr, uid, ids, ids2, res, acc_set, context)
173 res.setdefault(obj_id, 0.0)162
174 for child_id in self.search(cr, uid,163 # TODO Take care of pricelist and purchase !
175 [('parent_id', 'child_of', [obj_id])]):
176 if child_id != obj_id:
177 res[obj_id] += res.get(child_id, 0.0)
178 for id in ids:
179 res[id] = round(res.get(id, 0.0),2)
180 return res
181
182 def _ca_theorical_calc(self, cr, uid, ids, name, arg, context={}):164 def _ca_theorical_calc(self, cr, uid, ids, name, arg, context={}):
183 res = {}165 res = {}
184 res2 = {}166 res2 = {}
185 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])167 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
168 # Warnning
169 # This computation doesn't take care of pricelist !
170 # Just consider list_price
186 if ids2:171 if ids2:
187 cr.execute("""select account_analytic_line.account_id as account_id, \172 cr.execute("""select account_analytic_line.account_id as account_id, \
188 COALESCE(sum((account_analytic_line.unit_amount * pt.list_price) \173 COALESCE(sum((account_analytic_line.unit_amount * pt.list_price) \
@@ -205,7 +190,7 @@
205 GROUP BY account_analytic_line.account_id""",(ids2,))190 GROUP BY account_analytic_line.account_id""",(ids2,))
206 for account_id, sum in cr.fetchall():191 for account_id, sum in cr.fetchall():
207 res2[account_id] = round(sum,2)192 res2[account_id] = round(sum,2)
208193
209 for obj_id in ids:194 for obj_id in ids:
210 res.setdefault(obj_id, 0.0)195 res.setdefault(obj_id, 0.0)
211 res2.setdefault(obj_id, 0.0)196 res2.setdefault(obj_id, 0.0)
@@ -214,7 +199,7 @@
214 if child_id != obj_id:199 if child_id != obj_id:
215 res[obj_id] += res.get(child_id, 0.0)200 res[obj_id] += res.get(child_id, 0.0)
216 res[obj_id] += res2.get(child_id, 0.0)201 res[obj_id] += res2.get(child_id, 0.0)
217202
218 # sum both result on account_id203 # sum both result on account_id
219 for id in ids:204 for id in ids:
220 res[id] = round(res.get(id, 0.0),2) + round(res2.get(id, 0.0),2)205 res[id] = round(res.get(id, 0.0),2) + round(res2.get(id, 0.0),2)
@@ -289,7 +274,7 @@
289 def _remaining_hours_calc(self, cr, uid, ids, name, arg, context={}):274 def _remaining_hours_calc(self, cr, uid, ids, name, arg, context={}):
290 res = {}275 res = {}
291 for account in self.browse(cr, uid, ids):276 for account in self.browse(cr, uid, ids):
292 if account.quantity_max <> 0:277 if account.quantity_max != 0:
293 res[account.id] = account.quantity_max - account.hours_quantity278 res[account.id] = account.quantity_max - account.hours_quantity
294 else:279 else:
295 res[account.id]=0.0280 res[account.id]=0.0
@@ -323,7 +308,7 @@
323 for account in self.browse(cr, uid, ids):308 for account in self.browse(cr, uid, ids):
324 if account.ca_invoiced == 0:309 if account.ca_invoiced == 0:
325 res[account.id]=0.0310 res[account.id]=0.0
326 elif account.total_cost <> 0.0:311 elif account.total_cost != 0.0:
327 res[account.id] = -(account.real_margin / account.total_cost) * 100312 res[account.id] = -(account.real_margin / account.total_cost) * 100
328 else:313 else:
329 res[account.id] = 0.0314 res[account.id] = 0.0
@@ -334,7 +319,7 @@
334 def _remaining_ca_calc(self, cr, uid, ids, name, arg, context={}):319 def _remaining_ca_calc(self, cr, uid, ids, name, arg, context={}):
335 res = {}320 res = {}
336 for account in self.browse(cr, uid, ids):321 for account in self.browse(cr, uid, ids):
337 if account.amount_max <> 0:322 if account.amount_max != 0:
338 res[account.id] = account.amount_max - account.ca_invoiced323 res[account.id] = account.amount_max - account.ca_invoiced
339 else:324 else:
340 res[account.id]=0.0325 res[account.id]=0.0
341326
=== modified file 'analytic/project.py'
--- analytic/project.py 2010-02-05 15:09:27 +0000
+++ analytic/project.py 2010-02-15 10:42:24 +0000
@@ -33,65 +33,19 @@
33 _name = 'account.analytic.account'33 _name = 'account.analytic.account'
34 _description = 'Analytic Accounts'34 _description = 'Analytic Accounts'
3535
36 def _credit_calc(self, cr, uid, ids, name, arg, context={}):36 def _compute_currency_for_level_tree(self, cr, uid, ids, ids2, res, acc_set, context={}):
3737 # Handle multi-currency on each level of analytic account
38 where_date = ''38 # This is a refactoring of _balance_calc computation
39 if context.get('from_date',False):39 cr.execute("SELECT a.id, r.currency_id FROM account_analytic_account a INNER JOIN res_company r ON (a.company_id = r.id) where a.id in (%s)" % acc_set)
40 where_date += " AND l.date >= '" + context['from_date'] + "'"
41 if context.get('to_date',False):
42 where_date += " AND l.date <= '" + context['to_date'] + "'"
43
44 cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount<0 and a.id =ANY(%s) GROUP BY a.id",(ids,))
45 r = dict(cr.fetchall())
46 for i in ids:
47 r.setdefault(i,0.0)
48 return r
49
50 def _debit_calc(self, cr, uid, ids, name, arg, context={}):
51
52 where_date = ''
53 if context.get('from_date',False):
54 where_date += " AND l.date >= '" + context['from_date'] + "'"
55 if context.get('to_date',False):
56 where_date += " AND l.date <= '" + context['to_date'] + "'"
57
58 cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount>0 and a.id =ANY(%s) GROUP BY a.id" ,(ids,))
59 r= dict(cr.fetchall())
60 for i in ids:
61 r.setdefault(i,0.0)
62 return r
63
64 def _balance_calc(self, cr, uid, ids, name, arg, context={}):
65 res = {}
66 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
67 for i in ids:
68 res.setdefault(i,0.0)
69 if not ids2:
70 return res
71
72 where_date = ''
73 if context.get('from_date',False):
74 where_date += " AND l.date >= '" + context['from_date'] + "'"
75 if context.get('to_date',False):
76 where_date += " AND l.date <= '" + context['to_date'] + "'"
77
78 cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE a.id =ANY(%s) GROUP BY a.id",(ids2,))
79
80 for account_id, sum in cr.fetchall():
81 res[account_id] = sum
82
83 cr.execute("SELECT a.id, r.currency_id FROM account_analytic_account a INNER JOIN res_company r ON (a.company_id = r.id) where a.id =ANY(%s)",(ids2,))
84
85 currency= dict(cr.fetchall())40 currency= dict(cr.fetchall())
86
87 res_currency= self.pool.get('res.currency')41 res_currency= self.pool.get('res.currency')
88 for id in ids:42 for id in ids:
89 if id not in ids2:43 if id not in ids2:
90 continue44 continue
91 for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):45 for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):
92 if child <> id:46 if child != id:
93 res.setdefault(id, 0.0)47 res.setdefault(id, 0.0)
94 if currency[child]<>currency[id]:48 if currency[child]!=currency[id]:
95 res[id] += res_currency.compute(cr, uid, currency[child], currency[id], res.get(child, 0.0), context=context)49 res[id] += res_currency.compute(cr, uid, currency[child], currency[id], res.get(child, 0.0), context=context)
96 else:50 else:
97 res[id] += res.get(child, 0.0)51 res[id] += res.get(child, 0.0)
@@ -104,24 +58,88 @@
10458
105 return dict([(i, res[i]) for i in ids ])59 return dict([(i, res[i]) for i in ids ])
10660
61
62 def _credit_calc(self, cr, uid, ids, name, arg, context={}):
63 res = {}
64 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
65 acc_set = ",".join(map(str, ids2))
66
67 for i in ids:
68 res.setdefault(i,0.0)
69
70 if not ids2:
71 return res
72
73 where_date = ''
74 if context.get('from_date',False):
75 where_date += " AND l.date >= '" + context['from_date'] + "'"
76 if context.get('to_date',False):
77 where_date += " AND l.date <= '" + context['to_date'] + "'"
78 cr.execute("SELECT a.id, COALESCE(SUM(l.amount_currency),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount_currency<0 and a.id =ANY(%s) GROUP BY a.id",(ids2,))
79 r = dict(cr.fetchall())
80 return self._compute_currency_for_level_tree(cr, uid, ids, ids2, r, acc_set, context)
81
82 def _debit_calc(self, cr, uid, ids, name, arg, context={}):
83 res = {}
84 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
85 acc_set = ",".join(map(str, ids2))
86
87 for i in ids:
88 res.setdefault(i,0.0)
89
90 if not ids2:
91 return res
92
93 where_date = ''
94 if context.get('from_date',False):
95 where_date += " AND l.date >= '" + context['from_date'] + "'"
96 if context.get('to_date',False):
97 where_date += " AND l.date <= '" + context['to_date'] + "'"
98 cr.execute("SELECT a.id, COALESCE(SUM(l.amount_currency),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount_currency>0 and a.id =ANY(%s) GROUP BY a.id" ,(ids2,))
99 r= dict(cr.fetchall())
100 return self._compute_currency_for_level_tree(cr, uid, ids, ids2, r, acc_set, context)
101
102 def _balance_calc(self, cr, uid, ids, name, arg, context={}):
103 res = {}
104 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
105 acc_set = ",".join(map(str, ids2))
106
107 for i in ids:
108 res.setdefault(i,0.0)
109
110 if not ids2:
111 return res
112
113 where_date = ''
114 if context.get('from_date',False):
115 where_date += " AND l.date >= '" + context['from_date'] + "'"
116 if context.get('to_date',False):
117 where_date += " AND l.date <= '" + context['to_date'] + "'"
118 cr.execute("SELECT a.id, COALESCE(SUM(l.amount_currency),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE a.id =ANY(%s) GROUP BY a.id",(ids2,))
119
120 for account_id, sum in cr.fetchall():
121 res[account_id] = sum
122
123 return self._compute_currency_for_level_tree(cr, uid, ids, ids2, res, acc_set, context)
124
107 def _quantity_calc(self, cr, uid, ids, name, arg, context={}):125 def _quantity_calc(self, cr, uid, ids, name, arg, context={}):
108 #XXX must convert into one uom126 #XXX must convert into one uom
109 res = {}127 res = {}
110 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])128 ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)])
111 acc_set = ",".join(map(str, ids2))129 acc_set = ",".join(map(str, ids2))
112130
113 for i in ids:131 for i in ids:
114 res.setdefault(i,0.0)132 res.setdefault(i,0.0)
115133
116 if not acc_set:134 if not ids2:
117 return res135 return res
118136
119 where_date = ''137 where_date = ''
120 if context.get('from_date',False):138 if context.get('from_date',False):
121 where_date += " AND l.date >= '" + context['from_date'] + "'"139 where_date += " AND l.date >= '" + context['from_date'] + "'"
122 if context.get('to_date',False):140 if context.get('to_date',False):
123 where_date += " AND l.date <= '" + context['to_date'] + "'"141 where_date += " AND l.date <= '" + context['to_date'] + "'"
124142
125 cr.execute('SELECT a.id, COALESCE(SUM(l.unit_amount), 0) \143 cr.execute('SELECT a.id, COALESCE(SUM(l.unit_amount), 0) \
126 FROM account_analytic_account a \144 FROM account_analytic_account a \
127 LEFT JOIN account_analytic_line l ON (a.id = l.account_id ' + where_date + ') \145 LEFT JOIN account_analytic_line l ON (a.id = l.account_id ' + where_date + ') \
@@ -134,7 +152,7 @@
134 if id not in ids2:152 if id not in ids2:
135 continue153 continue
136 for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):154 for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):
137 if child <> id:155 if child != id:
138 res.setdefault(id, 0.0)156 res.setdefault(id, 0.0)
139 res[id] += res.get(child, 0.0)157 res[id] += res.get(child, 0.0)
140 return dict([(i, res[i]) for i in ids])158 return dict([(i, res[i]) for i in ids])
@@ -161,11 +179,15 @@
161 result[rec.id] = (rec.company_id.currency_id.id,rec.company_id.currency_id.code) or False179 result[rec.id] = (rec.company_id.currency_id.id,rec.company_id.currency_id.code) or False
162 return result180 return result
163181
182 def _get_account_currency(self, cr, uid, ids, field_name, arg, context={}):
183 result=self._get_company_currency(cr, uid, ids, field_name, arg, context={})
184 return result
185
164 _columns = {186 _columns = {
165 'name' : fields.char('Account Name', size=128, required=True),187 'name' : fields.char('Account Name', size=128, required=True),
166 'complete_name': fields.function(_complete_name_calc, method=True, type='char', string='Full Account Name'),188 'complete_name': fields.function(_complete_name_calc, method=True, type='char', string='Full Account Name'),
167 'code' : fields.char('Account Code', size=24),189 'code' : fields.char('Account Code', size=24),
168# 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the analytic account without removing it."),190 # 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the analytic account without removing it."),
169 'type': fields.selection([('view','View'), ('normal','Normal')], 'Account Type'),191 'type': fields.selection([('view','View'), ('normal','Normal')], 'Account Type'),
170 'description' : fields.text('Description'),192 'description' : fields.text('Description'),
171 'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2),193 'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2),
@@ -190,6 +212,7 @@
190 \n* And finally when all the transactions are over, it can be in \'Close\' state. \212 \n* And finally when all the transactions are over, it can be in \'Close\' state. \
191 \n* The project can be in either if the states \'Template\' and \'Running\'.\n If it is template then we can make projects based on the template projects. If its in \'Running\' state it is a normal project.\213 \n* The project can be in either if the states \'Template\' and \'Running\'.\n If it is template then we can make projects based on the template projects. If its in \'Running\' state it is a normal project.\
192 \n If it is to be reviewed then the state is \'Pending\'.\n When the project is completed the state is set to \'Done\'.'),214 \n If it is to be reviewed then the state is \'Pending\'.\n When the project is completed the state is set to \'Done\'.'),
215 'currency_id': fields.function(_get_account_currency, method=True, type='many2one', relation='res.currency', string='Account currency', store=True),
193 }216 }
194217
195 def _default_company(self, cr, uid, context={}):218 def _default_company(self, cr, uid, context={}):
@@ -198,14 +221,14 @@
198 return user.company_id.id221 return user.company_id.id
199 return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0]222 return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0]
200 _defaults = {223 _defaults = {
201# 'active' : lambda *a : True,224 'active' : lambda *a : True,
202 'type' : lambda *a : 'normal',225 'type' : lambda *a : 'normal',
203 'company_id': _default_company,226 'company_id': _default_company,
204 'state' : lambda *a : 'open',227 'state' : lambda *a : 'open',
205 'user_id' : lambda self,cr,uid,ctx : uid,228 'user_id' : lambda self,cr,uid,ctx : uid,
206 'partner_id': lambda self,cr, uid, ctx: ctx.get('partner_id', False),229 'partner_id': lambda self,cr, uid, ctx: ctx.get('partner_id', False),
207 'contact_id': lambda self,cr, uid, ctx: ctx.get('contact_id', False),230 'contact_id': lambda self,cr, uid, ctx: ctx.get('contact_id', False),
208 'date_start': lambda *a: time.strftime('%Y-%m-%d')231 'date_start': lambda *a: time.strftime('%Y-%m-%d')
209 }232 }
210233
211 def check_recursion(self, cr, uid, ids, parent=None):234 def check_recursion(self, cr, uid, ids, parent=None):
@@ -260,3 +283,4 @@
260 return self.name_get(cr, uid, account, context=context)283 return self.name_get(cr, uid, account, context=context)
261284
262account_analytic_account()285account_analytic_account()
286
263287
=== modified file 'analytic_user_function/analytic_user_function.py'
--- analytic_user_function/analytic_user_function.py 2010-01-12 09:18:39 +0000
+++ analytic_user_function/analytic_user_function.py 2010-02-15 10:42:25 +0000
@@ -99,8 +99,11 @@
99 _('There is no expense account define ' \99 _('There is no expense account define ' \
100 'for this product: "%s" (id:%d)') % \100 'for this product: "%s" (id:%d)') % \
101 (r.product_id.name, r.product_id.id,))101 (r.product_id.name, r.product_id.id,))
102 amount = unit_amount * self.pool.get('product.uom')._compute_price(cr, uid,102 # Compute based on pricetype
103 r.product_id.uom_id.id, r.product_id.standard_price, False)103 amount_unit=self.on_change_unit_amount(cr, uid, ids,
104 r.product_id.id, unit_amount, r.product_id.uom_id.id)['value']['amount']
105
106 amount = unit_amount * amount_unit
104 res ['value']['amount']= - round(amount, 2)107 res ['value']['amount']= - round(amount, 2)
105 res ['value']['general_account_id']= a108 res ['value']['general_account_id']= a
106 return res109 return res
@@ -132,8 +135,11 @@
132 _('There is no expense account define ' \135 _('There is no expense account define ' \
133 'for this product: "%s" (id:%d)') % \136 'for this product: "%s" (id:%d)') % \
134 (r.product_id.name, r.product_id.id,))137 (r.product_id.name, r.product_id.id,))
135 amount = unit_amount * r.product_id.uom_id._compute_price(cr, uid,138 # Compute based on pricetype
136 r.product_id.uom_id.id, r.product_id.standard_price, False)139 amount_unit=self.on_change_unit_amount(cr, uid, ids,
140 r.product_id.id, unit_amount, r.product_id.uom_id.id)['value']['amount']
141
142 amount = unit_amount * amount_unit
137 res ['value']['amount']= - round(amount, 2)143 res ['value']['amount']= - round(amount, 2)
138 res ['value']['general_account_id']= a144 res ['value']['general_account_id']= a
139 return res145 return res
140146
=== modified file 'hr_expense/hr_expense.py'
--- hr_expense/hr_expense.py 2010-02-01 08:29:39 +0000
+++ hr_expense/hr_expense.py 2010-02-15 10:42:25 +0000
@@ -210,12 +210,18 @@
210 'date_value' : lambda *a: time.strftime('%Y-%m-%d'),210 'date_value' : lambda *a: time.strftime('%Y-%m-%d'),
211 }211 }
212 _order = "sequence"212 _order = "sequence"
213 def onchange_product_id(self, cr, uid, ids, product_id, uom_id, context={}):213 def onchange_product_id(self, cr, uid, ids, product_id, uom_id, employee_id, context={}):
214 v={}214 v={}
215 if product_id:215 if product_id:
216 product=self.pool.get('product.product').browse(cr,uid,product_id, context=context)216 product=self.pool.get('product.product').browse(cr,uid,product_id, context=context)
217 v['name']=product.name217 v['name']=product.name
218 v['unit_amount']=product.standard_price218
219 # Compute based on pricetype of employee company
220 pricetype_id = self.pool.get('hr.employee').browse(cr,uid,employee_id).user_id.company_id.property_valuation_price_type.id
221 pricetype=self.pool.get('product.price.type').browse(cr,uid,pricetype_id)
222 amount_unit=product.price_get(pricetype.field, context)[product.id]
223
224 v['unit_amount']=amount_unit
219 if not uom_id:225 if not uom_id:
220 v['uom_id']=product.uom_id.id226 v['uom_id']=product.uom_id.id
221 return {'value':v}227 return {'value':v}
222228
=== modified file 'hr_expense/hr_expense_view.xml'
--- hr_expense/hr_expense_view.xml 2010-02-01 11:09:48 +0000
+++ hr_expense/hr_expense_view.xml 2010-02-15 10:42:25 +0000
@@ -73,8 +73,8 @@
73 <newline/>73 <newline/>
74 <field colspan="4" name="line_ids" nolabel="1">74 <field colspan="4" name="line_ids" nolabel="1">
75 <form string="Expense Lines">75 <form string="Expense Lines">
76 <field name="product_id" on_change="onchange_product_id(product_id, uom_id)" select="2"/>76 <field name="product_id" on_change="onchange_product_id(product_id, uom_id, parent.employee_id)" select="2"/>
77 <field name="uom_id" on_change="onchange_product_id(product_id, uom_id)" select="2"/>77 <field name="uom_id" on_change="onchange_product_id(product_id, uom_id, parent.employee_id)" select="2"/>
78 <field name="name" select="1"/>78 <field name="name" select="1"/>
79 <field name="date_value" select="1"/>79 <field name="date_value" select="1"/>
80 <field name="unit_quantity" select="2"/>80 <field name="unit_quantity" select="2"/>
8181
=== modified file 'hr_timesheet/hr_timesheet.py'
--- hr_timesheet/hr_timesheet.py 2010-01-12 09:18:39 +0000
+++ hr_timesheet/hr_timesheet.py 2010-02-15 10:42:25 +0000
@@ -57,7 +57,9 @@
57 res = {}57 res = {}
58# if prod_id and unit_amount:58# if prod_id and unit_amount:
59 if prod_id:59 if prod_id:
60 res = self.pool.get('account.analytic.line').on_change_unit_amount(cr, uid, id, prod_id, unit_amount,unit, context)60 # find company
61 company_id=self.pool.get('res.company')._company_default_get(cr, uid, 'account.analytic.line', context)
62 res = self.pool.get('account.analytic.line').on_change_unit_amount(cr, uid, id, prod_id, unit_amount,company_id,unit, context)
61 return res63 return res
6264
63 def _getEmployeeProduct(self, cr, uid, context):65 def _getEmployeeProduct(self, cr, uid, context):
6466
=== modified file 'hr_timesheet_invoice/hr_timesheet_invoice.py'
--- hr_timesheet_invoice/hr_timesheet_invoice.py 2010-01-21 15:13:50 +0000
+++ hr_timesheet_invoice/hr_timesheet_invoice.py 2010-02-15 10:42:25 +0000
@@ -52,6 +52,7 @@
52 res[id] = round(res.get(id, 0.0),2)52 res[id] = round(res.get(id, 0.0),2)
53 return res53 return res
5454
55
55 _inherit = "account.analytic.account"56 _inherit = "account.analytic.account"
56 _columns = {57 _columns = {
57 'pricelist_id' : fields.many2one('product.pricelist', 'Sale Pricelist'),58 'pricelist_id' : fields.many2one('product.pricelist', 'Sale Pricelist'),
@@ -77,7 +78,7 @@
77 }78 }
7879
79 def unlink(self, cursor, user, ids, context=None):80 def unlink(self, cursor, user, ids, context=None):
80 self._check(cursor, user, ids)81 # self._check(cursor, user, ids)
81 return super(account_analytic_line,self).unlink(cursor, user, ids,82 return super(account_analytic_line,self).unlink(cursor, user, ids,
82 context=context)83 context=context)
8384
@@ -90,11 +91,11 @@
90 select = ids91 select = ids
91 if isinstance(select, (int, long)):92 if isinstance(select, (int, long)):
92 select = [ids]93 select = [ids]
93 if ( not vals.has_key('invoice_id')) or vals['invoice_id' ] == False:94 if ( not vals.has_key('invoice_id')) or vals['invoice_id' ] == False:
94 for line in self.browse(cr, uid, select):95 for line in self.browse(cr, uid, select):
95 if line.invoice_id:96 if line.invoice_id:
96 raise osv.except_osv(_('Error !'),97 raise osv.except_osv(_('Error !'),
97 _('You can not modify an invoiced analytic line!'))98 _('You can not modify an invoiced analytic line!'))
98 return True99 return True
99100
100 def copy(self, cursor, user, obj_id, default=None, context=None):101 def copy(self, cursor, user, obj_id, default=None, context=None):
101102
=== modified file 'hr_timesheet_invoice/hr_timesheet_invoice_view.xml'
--- hr_timesheet_invoice/hr_timesheet_invoice_view.xml 2010-01-09 14:30:02 +0000
+++ hr_timesheet_invoice/hr_timesheet_invoice_view.xml 2010-02-15 10:42:25 +0000
@@ -20,7 +20,19 @@
20 </field>20 </field>
21 </field>21 </field>
22 </record>22 </record>
2323
24 <record id="view_account_analytic_account_form" model="ir.ui.view">
25 <field name="name">account.analytic.account.form</field>
26 <field name="model">account.analytic.account</field>
27 <field name="inherit_id" ref="account.view_account_analytic_account_form"/>
28 <field name="type">form</field>
29 <field name="arch" type="xml">
30 <field name="company_currency_id" select="2" position="replace">
31 <field name="currency_id" select="2"/>
32 </field>
33 </field>
34 </record>
35
24 <record id="hr_timesheet_line_form" model="ir.ui.view">36 <record id="hr_timesheet_line_form" model="ir.ui.view">
25 <field name="name">hr.analytic.timesheet.form</field>37 <field name="name">hr.analytic.timesheet.form</field>
26 <field name="model">hr.analytic.timesheet</field>38 <field name="model">hr.analytic.timesheet</field>
2739
=== modified file 'multi_company/__init__.py'
--- multi_company/__init__.py 2010-01-12 09:18:39 +0000
+++ multi_company/__init__.py 2010-02-15 10:42:25 +0000
@@ -18,6 +18,5 @@
18# along with this program. If not, see <http://www.gnu.org/licenses/>. 18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#19#
20##############################################################################20##############################################################################
21
22# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:21# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
2322
2423
=== modified file 'multi_company/__terp__.py'
--- multi_company/__terp__.py 2010-01-12 09:18:39 +0000
+++ multi_company/__terp__.py 2010-02-15 10:42:25 +0000
@@ -32,7 +32,7 @@
32 'depends': [32 'depends': [
33 'base',33 'base',
34 'sale',34 'sale',
35 'project'35 'project',
36 ],36 ],
37 'init_xml': [],37 'init_xml': [],
38 'update_xml': [38 'update_xml': [
3939
=== modified file 'product/__init__.py'
--- product/__init__.py 2010-01-12 09:18:39 +0000
+++ product/__init__.py 2010-02-15 10:42:25 +0000
@@ -23,6 +23,6 @@
23import report23import report
24import partner24import partner
25import wizard25import wizard
2626import company
27# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:27# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
2828
2929
=== modified file 'product/__terp__.py'
--- product/__terp__.py 2010-01-12 09:18:39 +0000
+++ product/__terp__.py 2010-02-15 10:42:25 +0000
@@ -54,6 +54,7 @@
54 'product_view.xml',54 'product_view.xml',
55 'pricelist_view.xml',55 'pricelist_view.xml',
56 'partner_view.xml',56 'partner_view.xml',
57 'company_view.xml',
57 'product_wizard.xml',58 'product_wizard.xml',
58 'process/product_process.xml'59 'process/product_process.xml'
59 ],60 ],
6061
=== added file 'product/company.py'
--- product/company.py 1970-01-01 00:00:00 +0000
+++ product/company.py 2010-02-15 10:42:26 +0000
@@ -0,0 +1,53 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
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##############################################################################
21
22from osv import fields, osv
23
24
25class res_company(osv.osv):
26 _inherit = 'res.company'
27 _columns = {
28 'property_valuation_price_type': fields.property(
29 'product.price.type',
30 type='many2one',
31 relation='product.price.type',
32 domain=[],
33 string="Valuation Price Type",
34 method=True,
35 view_load=True,
36 help="The price type field in the selected price type will be used, instead of the default one, \
37 for valuation of product in the current company"),
38 }
39
40 def _check_currency(self, cr, uid, ids):
41 for rec in self.browse(cr, uid, ids):
42 if rec.currency_id.id <> rec.property_valuation_price_type.currency_id.id:
43 return False
44 return True
45
46 _constraints = [
47 (_check_currency, 'Error! You can not chooes a pricetype in a different currency than your company (Not supported now).', ['property_valuation_price_type'])
48 ]
49
50res_company()
51
52# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
53
054
=== added file 'product/company_view.xml'
--- product/company_view.xml 1970-01-01 00:00:00 +0000
+++ product/company_view.xml 2010-02-15 10:42:26 +0000
@@ -0,0 +1,18 @@
1<openerp>
2 <data>
3
4
5 <record id="view_company_property_form" model="ir.ui.view">
6 <field name="name">res.company.product.property.form.inherit</field>
7 <field name="model">res.company</field>
8 <field name="type">form</field>
9 <field name="inherit_id" ref="base.view_company_form"/>
10 <field name="arch" type="xml">
11 <field name="currency_id" position="after">
12 <field name="property_valuation_price_type"/>
13 </field>
14 </field>
15 </record>
16
17 </data>
18</openerp>
019
=== modified file 'product/pricelist.py'
--- product/pricelist.py 2010-02-01 08:29:39 +0000
+++ product/pricelist.py 2010-02-15 10:42:26 +0000
@@ -62,6 +62,7 @@
62 "active": lambda *args: True,62 "active": lambda *args: True,
63 "currency_id": _get_currency63 "currency_id": _get_currency
64 }64 }
65
65price_type()66price_type()
6667
67#----------------------------------------------------------68#----------------------------------------------------------
6869
=== modified file 'product/product_data.xml'
--- product/product_data.xml 2009-09-24 10:46:21 +0000
+++ product/product_data.xml 2010-02-15 10:42:26 +0000
@@ -73,7 +73,6 @@
73 73
74 74
75 75
76
77 <!--76 <!--
78 Price list type77 Price list type
79 -->78 -->
@@ -81,6 +80,7 @@
81 <field name="name">Sale Pricelist</field>80 <field name="name">Sale Pricelist</field>
82 <field name="key">sale</field>81 <field name="key">sale</field>
83 </record>82 </record>
83
84 84
85 <!--85 <!--
86 Price list86 Price list
@@ -107,5 +107,12 @@
107 <field name="fields_id" search="[('model','=','res.partner'),('name','=','property_product_pricelist')]"/>107 <field name="fields_id" search="[('model','=','res.partner'),('name','=','property_product_pricelist')]"/>
108 <field eval="'product.pricelist,'+str(ref('list0'))" name="value"/>108 <field eval="'product.pricelist,'+str(ref('list0'))" name="value"/>
109 </record>109 </record>
110
111 <record forcecreate="True" id="property_valuation_price_type" model="ir.property">
112 <field name="name">property_valuation_price_type</field>
113 <field name="fields_id" search="[('model','=','res.company'),('name','=','property_valuation_price_type')]"/>
114 <field eval="'product.price.type,'+str(ref('standard_price'))" name="value"/>
115 </record>
116
110 </data>117 </data>
111</openerp>118</openerp>
112119
=== modified file 'project_timesheet/project_timesheet.py'
--- project_timesheet/project_timesheet.py 2010-01-21 15:13:50 +0000
+++ project_timesheet/project_timesheet.py 2010-02-15 10:42:26 +0000
@@ -77,8 +77,12 @@
77 vals_line['journal_id'] = result['journal_id']77 vals_line['journal_id'] = result['journal_id']
78 vals_line['amount'] = 00.078 vals_line['amount'] = 00.0
79 timeline_id = obj.create(cr, uid, vals_line, {})79 timeline_id = obj.create(cr, uid, vals_line, {})
8080
81 vals_line['amount'] = (-1) * vals['hours']* ( obj.browse(cr,uid,timeline_id).product_id.standard_price or 0.0)81 # Compute based on pricetype
82 amount_unit=obj.on_change_unit_amount(cr, uid, line_id,
83 vals_line['product_id'], vals_line['unit_amount'], unit, context)
84
85 vals_line['amount'] = (-1) * vals['hours']* (unit_amount or 0.0)
82 obj.write(cr, uid,[timeline_id], vals_line, {})86 obj.write(cr, uid,[timeline_id], vals_line, {})
83 vals['hr_analytic_timesheet_id'] = timeline_id87 vals['hr_analytic_timesheet_id'] = timeline_id
84 return super(project_work,self).create(cr, uid, vals, *args, **kwargs)88 return super(project_work,self).create(cr, uid, vals, *args, **kwargs)
@@ -104,7 +108,12 @@
104 vals_line['date'] = vals['date'][:10]108 vals_line['date'] = vals['date'][:10]
105 if 'hours' in vals:109 if 'hours' in vals:
106 vals_line['unit_amount'] = vals['hours']110 vals_line['unit_amount'] = vals['hours']
107 vals_line['amount'] = (-1) * vals['hours'] * (obj.browse(cr,uid,line_id).product_id.standard_price or 0.0)111
112 # Compute based on pricetype
113 amount_unit=obj.on_change_unit_amount(cr, uid, line_id,
114 vals_line['product_id'], vals_line['unit_amount'], unit, context)
115
116 vals_line['amount'] = (-1) * vals['hours'] * (amount_unit or 0.0)
108 obj.write(cr, uid, [line_id], vals_line, {})117 obj.write(cr, uid, [line_id], vals_line, {})
109118
110 return super(project_work,self).write(cr, uid, ids, vals, context)119 return super(project_work,self).write(cr, uid, ids, vals, context)
111120
=== modified file 'stock/stock.py'
--- stock/stock.py 2010-02-09 08:31:46 +0000
+++ stock/stock.py 2010-02-15 10:42:27 +0000
@@ -110,11 +110,15 @@
110 cr.execute('select distinct product_id from stock_move where (location_id=%s) or (location_dest_id=%s)', (id, id))110 cr.execute('select distinct product_id from stock_move where (location_id=%s) or (location_dest_id=%s)', (id, id))
111 result = cr.dictfetchall()111 result = cr.dictfetchall()
112 if result:112 if result:
113 # Choose the right filed standard_price to read
114 # Take the user company
115 price_type_id=self.pool.get('res.users').browse(cr,uid,uid).company_id.property_valuation_price_type.id
116 pricetype=self.pool.get('product.price.type').browse(cr,uid,price_type_id)
113 for r in result:117 for r in result:
114 c = (context or {}).copy()118 c = (context or {}).copy()
115 c['location'] = id119 c['location'] = id
116 product = self.pool.get('product.product').read(cr, uid, r['product_id'], [field_to_read, 'standard_price'], context=c)120 product = self.pool.get('product.product').read(cr, uid, r['product_id'], [field_to_read, pricetype.field], context=c)
117 final_value += (product[field_to_read] * product['standard_price'])121 final_value += (product[field_to_read] * product[pricetype.field])
118 return final_value122 return final_value
119123
120 def _product_value(self, cr, uid, ids, field_names, arg, context={}):124 def _product_value(self, cr, uid, ids, field_names, arg, context={}):
@@ -211,6 +215,10 @@
211 if context is None:215 if context is None:
212 context = {}216 context = {}
213 product_obj = self.pool.get('product.product')217 product_obj = self.pool.get('product.product')
218 # Take the user company and pricetype
219 price_type_id=self.pool.get('res.users').browse(cr,uid,uid).company_id.property_valuation_price_type.id
220 pricetype=self.pool.get('product.price.type').browse(cr,uid,price_type_id)
221
214 if not product_ids:222 if not product_ids:
215 product_ids = product_obj.search(cr, uid, [])223 product_ids = product_obj.search(cr, uid, [])
216224
@@ -241,10 +249,16 @@
241 continue249 continue
242 product = products_by_id[product_id]250 product = products_by_id[product_id]
243 quantity_total += qty[product_id]251 quantity_total += qty[product_id]
244 price = qty[product_id] * product.standard_price252
253 # Compute based on pricetype
254 # Choose the right filed standard_price to read
255 amount_unit=product.price_get(pricetype.field, context)[product.id]
256 price = qty[product_id] * amount_unit
257 # price = qty[product_id] * product.standard_price
258
245 total_price += price259 total_price += price
246 result['product'].append({260 result['product'].append({
247 'price': product.standard_price,261 'price': amount_unit,
248 'prod_name': product.name,262 'prod_name': product.name,
249 'code': product.default_code, # used by lot_overview_all report!263 'code': product.default_code, # used by lot_overview_all report!
250 'variants': product.variants or '',264 'variants': product.variants or '',
@@ -645,7 +659,11 @@
645 def _get_price_unit_invoice(self, cursor, user, move_line, type):659 def _get_price_unit_invoice(self, cursor, user, move_line, type):
646 '''Return the price unit for the move line'''660 '''Return the price unit for the move line'''
647 if type in ('in_invoice', 'in_refund'):661 if type in ('in_invoice', 'in_refund'):
648 return move_line.product_id.standard_price662 # Take the user company and pricetype
663 price_type_id=self.pool.get('res.users').browse(cr,users,users).company_id.property_valuation_price_type.id
664 pricetype=self.pool.get('product.price.type').browse(cr,uid,price_type_id)
665 amount_unit=move_line.product_id.price_get(pricetype.field, context)[move_line.product_id.id]
666 return amount_unit
649 else:667 else:
650 return move_line.product_id.list_price668 return move_line.product_id.list_price
651669
@@ -1408,13 +1426,19 @@
1408 ref = move.picking_id and move.picking_id.name or False1426 ref = move.picking_id and move.picking_id.name or False
1409 product_uom_obj = self.pool.get('product.uom')1427 product_uom_obj = self.pool.get('product.uom')
1410 default_uom = move.product_id.uom_id.id1428 default_uom = move.product_id.uom_id.id
1429 date = time.strftime('%Y-%m-%d')
1411 q = product_uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, default_uom)1430 q = product_uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, default_uom)
1412 if move.product_id.cost_method == 'average' and move.price_unit:1431 if move.product_id.cost_method == 'average' and move.price_unit:
1413 amount = q * move.price_unit1432 amount = q * move.price_unit
1433 # Base computation on valuation price type
1414 else:1434 else:
1415 amount = q * move.product_id.standard_price1435 company_id=move.company_id.id
14161436
1417 date = time.strftime('%Y-%m-%d')1437 pricetype=self.pool.get('product.price.type').browse(cr,uid,move.company_id.property_valuation_price_type.id)
1438 amount_unit=move.product_id.price_get(pricetype.field, context)[move.product_id.id]
1439 amount=amount_unit * q or 1.0
1440 # amount = q * move.product_id.standard_price
1441
1418 partner_id = False1442 partner_id = False
1419 if move.picking_id:1443 if move.picking_id:
1420 partner_id = move.picking_id.address_id and (move.picking_id.address_id.partner_id and move.picking_id.address_id.partner_id.id or False) or False1444 partner_id = move.picking_id.address_id and (move.picking_id.address_id.partner_id and move.picking_id.address_id.partner_id.id or False) or False
@@ -1492,7 +1516,8 @@
1492 move_line = []1516 move_line = []
1493 for line in inv.inventory_line_id:1517 for line in inv.inventory_line_id:
1494 pid = line.product_id.id1518 pid = line.product_id.id
1495 price = line.product_id.standard_price or 0.01519
1520 # price = line.product_id.standard_price or 0.0
1496 amount = self.pool.get('stock.location')._product_get(cr, uid, line.location_id.id, [pid], {'uom': line.product_uom.id})[pid]1521 amount = self.pool.get('stock.location')._product_get(cr, uid, line.location_id.id, [pid], {'uom': line.product_uom.id})[pid]
1497 change = line.product_qty - amount1522 change = line.product_qty - amount
1498 lot_id = line.prod_lot_id.id1523 lot_id = line.prod_lot_id.id
14991524
=== modified file 'stock/wizard/wizard_partial_move.py'
--- stock/wizard/wizard_partial_move.py 2010-01-12 09:18:39 +0000
+++ stock/wizard/wizard_partial_move.py 2010-02-15 10:42:27 +0000
@@ -55,7 +55,7 @@
5555
56 for move in move_lines:56 for move in move_lines:
57 quantity = move.product_qty57 quantity = move.product_qty
58 if move.state <> 'assigned':58 if move.state != 'assigned':
59 quantity = 059 quantity = 0
6060
61 _moves_arch_lst.append('<field name="move%s" />' % (move.id,))61 _moves_arch_lst.append('<field name="move%s" />' % (move.id,))
@@ -124,7 +124,8 @@
124 currency = data['form']['currency%s' % move.id]124 currency = data['form']['currency%s' % move.id]
125125
126 qty = uom_obj._compute_qty(cr, uid, uom, qty, product.uom_id.id)126 qty = uom_obj._compute_qty(cr, uid, uom, qty, product.uom_id.id)
127127 pricetype=pool.get('product.price.type').browse(cr,uid,user.company_id.property_valuation_price_type.id)
128
128 if (qty > 0):129 if (qty > 0):
129 new_price = currency_obj.compute(cr, uid, currency,130 new_price = currency_obj.compute(cr, uid, currency,
130 user.company_id.currency_id.id, price)131 user.company_id.currency_id.id, price)
@@ -133,15 +134,17 @@
133 if product.qty_available<=0:134 if product.qty_available<=0:
134 new_std_price = new_price135 new_std_price = new_price
135 else:136 else:
136 new_std_price = ((product.standard_price * product.qty_available)\137 # Get the standard price
138 amount_unit=product.price_get(pricetype.field, context)[product.id]
139 new_std_price = ((amount_unit * product.qty_available)\
137 + (new_price * qty))/(product.qty_available + qty)140 + (new_price * qty))/(product.qty_available + qty)
138141
139 product_obj.write(cr, uid, [product.id],142 product_obj.write(cr, uid, [product.id],
140 {'standard_price': new_std_price})143 {pricetype.field: new_std_price})
141 move_obj.write(cr, uid, move.id, {'price_unit': new_price}) 144 move_obj.write(cr, uid, move.id, {'price_unit': new_price})
142145
143 for move in too_few: 146 for move in too_few:
144 if data['form']['move%s' % move.id] <> 0:147 if data['form']['move%s' % move.id] != 0:
145 new_move = move_obj.copy(cr, uid, move.id,148 new_move = move_obj.copy(cr, uid, move.id,
146 {149 {
147 'product_qty' : data['form']['move%s' % move.id],150 'product_qty' : data['form']['move%s' % move.id],
148151
=== modified file 'stock/wizard/wizard_partial_picking.py'
--- stock/wizard/wizard_partial_picking.py 2010-01-21 15:13:50 +0000
+++ stock/wizard/wizard_partial_picking.py 2010-02-15 10:42:27 +0000
@@ -61,7 +61,7 @@
61 if m.state in ('done', 'cancel'):61 if m.state in ('done', 'cancel'):
62 continue62 continue
63 quantity = m.product_qty63 quantity = m.product_qty
64 if m.state<>'assigned':64 if m.state!='assigned':
65 quantity = 065 quantity = 0
6666
67 _moves_arch_lst.append('<field name="move%s" />' % (m.id,))67 _moves_arch_lst.append('<field name="move%s" />' % (m.id,))
@@ -133,7 +133,7 @@
133 currency = data['form']['currency%s' % move.id]133 currency = data['form']['currency%s' % move.id]
134134
135 qty = uom_obj._compute_qty(cr, uid, uom, qty, product.uom_id.id)135 qty = uom_obj._compute_qty(cr, uid, uom, qty, product.uom_id.id)
136136 pricetype=pool.get('product.price.type').browse(cr,uid,user.company_id.property_valuation_price_type.id)
137 if (qty > 0):137 if (qty > 0):
138 new_price = currency_obj.compute(cr, uid, currency,138 new_price = currency_obj.compute(cr, uid, currency,
139 user.company_id.currency_id.id, price)139 user.company_id.currency_id.id, price)
@@ -142,11 +142,14 @@
142 if product.qty_available<=0:142 if product.qty_available<=0:
143 new_std_price = new_price143 new_std_price = new_price
144 else:144 else:
145 new_std_price = ((product.standard_price * product.qty_available)\145 # Get the standard price
146 amount_unit=product.price_get(pricetype.field, context)[product.id]
147 new_std_price = ((amount_unit * product.qty_available)\
146 + (new_price * qty))/(product.qty_available + qty)148 + (new_price * qty))/(product.qty_available + qty)
147149
150 # Write the field according to price type field
148 product_obj.write(cr, uid, [product.id],151 product_obj.write(cr, uid, [product.id],
149 {'standard_price': new_std_price})152 {pricetype.field: new_std_price})
150 move_obj.write(cr, uid, [move.id], {'price_unit': new_price})153 move_obj.write(cr, uid, [move.id], {'price_unit': new_price})
151154
152 for move in too_few:155 for move in too_few:
@@ -158,7 +161,7 @@
158 'move_lines' : [],161 'move_lines' : [],
159 'state':'draft',162 'state':'draft',
160 })163 })
161 if data['form']['move%s' % move.id] <> 0:164 if data['form']['move%s' % move.id] != 0:
162 new_obj = move_obj.copy(cr, uid, move.id,165 new_obj = move_obj.copy(cr, uid, move.id,
163 {166 {
164 'product_qty' : data['form']['move%s' % move.id],167 'product_qty' : data['form']['move%s' % move.id],

Subscribers

People subscribed via source and target branches

to all changes: