ODOO8: Untaxed and total amount in order lines not calculating - python

I add multiple PRODUCTS in the order lines of the REPAIR-ORDER, the price of each product shows up - but the untaxed sub total and total display (0) instead of the total of all products.
I've attached some of the code of the MRP REPAIR (.py) file :
def _amount_all_wrapper_repair(self, cr, uid, ids, field_name, arg, context=None):
""" Wrapper because of direct method passing as parameter for function fields """
return self._amount_all_repair(cr, uid, ids, field_name, arg, context=context)
def _amount_all_repair(self, cr, uid, ids, field_name, arg, context=None):
cur_obj = self.pool.get('res.currency')
res = {}
for order in self.browse(cr, uid, ids, context=context):
res[order.id] = {
'amount_untaxed': 0.0,
'amount_tax': 0.0,
'amount_total': 0.0,
}
val = val1 = 0.0
cur = order.sale_id.pricelist_id.currency_id
for line in order.order_line_ids:
val1 += line.price_subtotal
val += self._amount_line_tax_repair(cr, uid, line, context=context)
res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val)
res[order.id]['amount_untaxed'] = cur_obj.round(cr, uid, cur, val1)
res[order.id]['amount_total'] = res[order.id]['amount_untaxed'] + res[order.id]['amount_tax']
return res
The code for the mrp_repair.xml:
<group class="oe_subtotal_footer oe_right" colspan="2" name="sale_total">
<field name="amount_untaxed" widget='monetary' options="{'currency_field': 'currency_id'}"/>
<field name="amount_tax" widget='monetary' options="{'currency_field': 'currency_id'}"/>
<div class="oe_subtotal_footer_separator oe_inline">
<label for="amount_total" />
<button name="button_dummy"
states="draft,sent" string="(update)" type="object" class="oe_edit_only oe_link"/>
</div>
<field name="amount_total" nolabel="1" class="oe_subtotal_footer_separator" widget='monetary' options="{'currency_field': 'currency_id'}"/>
<div class="oe_inline" groups="garage.group_display_margin">
<label for="margin" style="font-weight:bold;"/>
</div>
<field name="margin" nolabel="1" style="font-weight:bold;" groups="garage.group_display_margin"/>
</group>
EDIT - Added info
I found that without the code below (this code causes MRP_REPAIR to add order lines both to the REPAIR ORDER and SALES ORDER), adding a product with a price doesnt get calculated in total field, and shows zero (0)
elif this.repair_sale_order_line_id:
sale_obj = self.pool.get('sale.order')
so_vals = {
'partner_id' : this.repair_sale_order_line_id.partner_id.id,
'fleet_id': this.repair_sale_order_line_id.fleet_id.id,
'responsable_id': uid,
}
created_so_id = so_obj.create(cr, uid, so_vals, context=context)
sol_vals = {'order_id': created_so_id,
'price_unit': this.price_unit,
'product_uom_qty': this.product_uom_qty,
'price_subtotal': this.price_subtotal,
'discount': this.discount,
'product_id': this.product_id.id,
'tax_id': [(6, 0, [x.id for x
in this.tax_id])],
'name': this.name,
}
self.pool.get('mrp.repair').write(cr, uid, this.repair_sale_order_line_id.id, {'sale_id':created_so_id},context=context)
sol_id = sol_obj.create_sol(cr, uid, sol_vals, context)
super(repair_sale_order_line, self).write(cr, uid, [res],{'sale_order_line_id':sol_id})
it seems that the Sale Order lines are used instead of the internal Repair Sale Order lines. The question is: how can i make the mrp not depend on the SO or its ORDER LINES.?

I found that without the code below (this code causes MRP_REPAIR to add order lines both to the REPAIR ORDER and SALES ORDER), adding a product with a price doesnt get calculated in total field, and shows zero (0)
elif this.repair_sale_order_line_id:
sale_obj = self.pool.get('sale.order')
so_vals = {
'partner_id' : this.repair_sale_order_line_id.partner_id.id,
'fleet_id': this.repair_sale_order_line_id.fleet_id.id,
'responsable_id': uid,
}
created_so_id = so_obj.create(cr, uid, so_vals, context=context)
sol_vals = {'order_id': created_so_id,
'price_unit': this.price_unit,
'product_uom_qty': this.product_uom_qty,
'price_subtotal': this.price_subtotal,
'discount': this.discount,
'product_id': this.product_id.id,
'tax_id': [(6, 0, [x.id for x
in this.tax_id])],
'name': this.name,
}
self.pool.get('mrp.repair').write(cr, uid, this.repair_sale_order_line_id.id, {'sale_id':created_so_id},context=context)
sol_id = sol_obj.create_sol(cr, uid, sol_vals, context)
super(repair_sale_order_line, self).write(cr, uid, [res],{'sale_order_line_id':sol_id})
it seems that the Sale Order lines are used instead of the internal Repair Sale Order lines. The question is: how can i make the mrp not depend on the SO or its ORDER LINES.?

Related

Odoo Accounting Report returning IndexError: list index out of range

I'm developing a custom accounting report on Odoo Enterprise. It's first time I try to do this kind of report, so I have a lot of doubts that I haven't solved on internet.
Based on native reports I came to this so far:
class BudgetaryPositionCompanyReport(models.AbstractModel):
_name = "budgetary.position.report"
_inherit = "account.report"
filter_date = {'date_from': '', 'date_to': '', 'filter': 'this_month'}
filter_unfold_all = False
def _get_columns_name(self, options):
return [{'name': _('Budget Item')}, {'name': _('Column1')}, {'name': _('Column2')}, {'name': _('%')}]
#api.model
def _get_lines(self, options, line_id=None):
context = dict(self._context or {})
date_from = context.get('date_from')
date_to = context.get('date_to')
lines = []
sql_parents = """
SELECT abp.name "name", sum(cbl.planned_amount) planned_amount, sum(cbl.r_practical_amount) r_practical_amount, sum(cbl.r_percentage) r_percentage
FROM crossovered_budget_lines cbl
JOIN account_budget_post abp ON (cbl.general_budget_id = abp.id)
GROUP BY abp.id;
"""
self.env.cr.execute(sql_parents)
results_parents = self.env.cr.dictfetchall()
for parent in results_parents:
lines.append({
'id': parent.get('id'),
'name': parent.get('name'),
'level': 1,
'unfoldable': True,
'unfolded': True,
'colspan': 4,
'columns': [
{'name': parent.get('name') and parent.get('name')},
{'name': parent.get('planned_amount') and self.format_value(parent.get('planned_amount'))},
{'name': parent.get('r_practical_amount') and self.format_value(parent.get('r_practical_amount'))},
{'name': parent.get('r_percentage') and self.format_value(parent.get('r_percentage'))}
],
})
print(lines)
return lines
def _get_report_name(self):
return _('Budgetary Positions (per company)')
def _get_templates(self):
templates = super(BudgetaryPositionCompanyReport, self)._get_templates()
return templates
Problem is when I try to access to this report, I'm getting the following:
Error to render compiling AST
IndexError: list index out of range
Template: account_reports.line_template
Path: /templates/t/t/tr/t[2]/td
Node: <td t-att-class="'o_account_report_line ' + (column.get('class', lines.get('columns_header')[-1][column_index+line.get('colspan', 1)].get('class', '')) + (line.get('unfoldable') and ' o_foldable_total' or '')) + ('' if hierarchies_enabled else ' o_account_report_line_indent')" t-att-style="column.get('style', lines.get('columns_header')[-1][column_index+line.get('colspan', 1)].get('style', ''))">
<span class="o_account_report_column_value" t-att-title="column.get('title')">
<t t-esc="column.get('name')"/>
</span>
</td>
Am I missing something?

Converting dictionary values into a string object with a specific order

I am looking to create a function that will turn a dictionary with address values into a string value with a specific order. I also need to account for missing values (Some address wont have a second or third address line. I want my output to look like the below so that I can copy the text block, separated by a new line, into a database field.
name
contact
addr1
addr2 (if not empty)
addr3 (if not empty)
city, state zip
phone
I have the following to create the dictionary, but I am stuck on creating the string object that ignores the empty values and puts everything in the correct order.
def setShippingAddr(name, contact, addr1, addr2, addr3, city, state, zipCode, phone):
addDict = {'name': name, 'contact': contact, 'addr1': addr1,
'city': city, 'state': state, 'zip': zipCode, 'phone': phone}
if addr2 is True: # append dict if addr2/addr 3 are True
addDict['addr2'] = addr2
if addr3 is True:
addDict['addr3'] = addr3
shAddr = # This is where i need to create the string object
return shAddr
I would rewrite the function to only return the string, the dictionary is not necessary:
def setShippingAddr(name, contact, addr1, city, state, zipCode, phone, addr2=None, addr3=None):
shAddr = f'{name}\n{contact}\n{addr1}'
shAddr = f'{shAddr}\n{addr2}' if addr2 else shAddr
shAddr = f'{shAddr}\n{addr3}' if addr3 else shAddr
shAddr = f'{shAddr}\n{city}, {state} {zipCode}\n{phone}'
return shAddr
Considering that you may want to add new entries to the dictionary
def setShippingAddr(name, contact, addr1, addr2, addr3, city, state, zipCode, phone):
addDict = {'name': name, 'contact': contact, 'addr1': addr1,
'city': city, 'state': state, 'zip': zipCode, 'phone': phone}
if addr2 is True: # append dict if addr2/addr 3 are True
addDict['addr2'] = addr2
if addr3 is True:
addDict['addr3'] = addr3
shAddr = ''
for key in addDict:
shAddr += addDict[key] + '\n'
return shAddr
It looks like (assuming you're using python3), an f string would work here.
shAddr = f"{addDict['name']} {addDict['contract'] etc..."
You can add logic within the {}, so something like
{addDict['addr2'] if addDict['addr2'] else ""}
should work, depending on what the specific output you were looking for was.
I'm not sure I understand the part with the dictionary. You could just leave it out, right?
Then
def setShippingAddr(*args):
return "\n".join([str(arg) for arg in args if arg])
s = setShippingAddr("Delenges", "Me", "Streetstreet", "Borrough", False,
"Town of City", "Landcountry", 12353, "+1 555 4545454")
print(s)
prints
Delenges
Me
Streetstreet
Borrough
Town of City
Landcountry
12353
+1 555 4545454
Here's a more pythonic solution,
def dict_to_string(dic):
s = ''
for k, v in dic.items():
s += "{} : {}\n".format(k, v)
return s
addDict = {'name': 'name', 'contact': 'contact', 'addr1': 'addr1', 'addr2': '',
'city': 'city', 'state': 'state', 'zip': 'zipCode', 'phone': 'phone'}
print(dict_to_string(addDict))
In this case, I've used addr2, which has a blank value. If you want, addr2 to be omitted completely, then check for the value while iterating.
def dict_to_string(dic):
s = ''
for k, v in dic.items():
if k:
s += "{} : {}\n".format(k, v)
return s
addDict = {'name': 'name', 'contact': 'contact', 'addr1': 'addr1', 'addr2': '',
'city': 'city', 'state': 'state', 'zip': 'zipCode', 'phone': 'phone'}
print(dict_to_string(addDict))
Finally if the natural order of iterating is not what you want you can use the OrderedDict

Odoo 10 - Retrieve the value of a field of another model

Here is code:
Target model:
class SchoolYears(models.Model):
_name = "ecole.partner.school.years"
_rec_name = "school_years" # POUR ASSIGNER PAR DEFAUT UN AUTRE CHAMP AUTRE QUE NAME
_order = 'id desc'
school_years = fields.Char(string='School year', required=True, copy=False)
year_begin_date = fields.Date(string='Start date', required=True, copy=False)
year_end_date = fields.Date(string='End date', required=True, copy=False)
default_school_year = fields.Boolean(string='Current school year', copy=False)
period_school_year = fields.Boolean(string='Registration period', copy=False)
active = fields.Boolean(default=True)
Targeted fields:-> year_begin_date = fields.Date(string='Start date', required=True, copy=False)
Model where I want to access the fields:
class ResPartnerSchool(models.Model):
_name = 'ecole.partner.school'
_order = 'id desc'
#api.multi
def _get_begin_date(self):
domain = [('period_school_year', '=', False), ('default_school_year', '=', True)]
begin_date_id = self.env['ecole.partner.school.years'].search(domain, limit=1).year_begin_date
begin_date = fields.Date.from_string(begin_date_id)
date_j = datetime.date.today()
if begin_date_id:
if begin_date > date_j:
return begin_date_id
else:
return date_j
...
school_year_id = fields.Many2one(string='Period',
ondelete='SET NULL',
comodel_name="ecole.partner.school.years",
default=_get_period_year)
school_registration = fields.Date(string='Beginning',
copy=False,
default=_get_begin_date)
...
Here is the view:
I want to get the correct start date of the school year related to school_years which is of type char and which is a Many2one in the model ecole.partner.school.
I know there are many ways to do this, especially with a "related field". Except that I have a function that allows me to recover the date of the day as of the beginning of the school year when one is in full in a school period.
Currently my function is written in "hard" -> this is what we see in the variable "domain". And I do not want to use "related field" in my school_registration field.
Do you have an idea to get the right start date when choosing a school year?
Thank you
You can try with a computed fields :
school_year_id = fields.Many2one(string='Period',
ondelete='SET NULL',
comodel_name="ecole.partner.school.years",
default=_get_period_year)
school_registration = fields.Date(string='Beginning',
copy=False,
compute=_get_begin_date)
#api.multi
#api.depends('school_year_id')
def _get_begin_date(self):
for record in self:
record.school_registration = record.school_year_id.year_begin_date

How to create stock move in Odoo from custom module?

I'm creating a custom module for Odoo.
I have Fabrication Orders with different phases : Order , Preparation , Fabrication , Shipping and Final.
And I have the product_id for the product that I want to Fabricate.
When the "Final" phase comes , the stock for that product need to be increased with the quantity that I choose from a field called "quantity".
Here's the code :
class fabrication_orders(models.Model):
_name = 'proyecto.fabrication_orders'
order_id = fields.Many2one('proyecto.products',required="true",string="Product Id")
name = fields.Char(related='order_id.name',required="true",string="Product Name")
order_number = fields.Char(compute='_get_order_number',string="Order Nº",store="true")
image = fields.Binary(related='order_id.image_medium',string="Image")
quantity = fields.Float(required="true")
date = fields.Datetime(required="true",string="Order Date") ### Order Date
end_date = fields.Datetime(compute='_get_end_date',string="Finish Date",store="true") ### Finish Date
initial_cost = fields.Float(related='order_id.standard_price',string="Initial Cost")
final_cost = fields.Float(compute='_get_order_cost',string="Fabrication Cost")
#venue = fields.Many2one('proyecto.venues',required="true",string="Ship to")
order_state = fields.Selection([
('orden', "Order"),
('preparacion', "Preparation"),
('fabricacion', "Fabrication"),
('envio', "Shipping"),
('final', "Final"),
], default='orden')
#Este metodo pone la fecha final segun la cantidad
#api.depends('date')
def _get_end_date(self):
for d in self:
if d.date:
d.end_date = datetime.now() + timedelta(hours=d.quantity)
#api.depends('order_id')
def _get_order_number(self):
for r in self:
if r.order_id:
r.order_number=str(random.randint(1, 1e6))
#api.multi
def change_order_state(self):
for r in self:
if r.order_state == 'orden':
r.write({'order_state':'preparacion'})
elif r.order_state == 'preparacion':
r.write({'order_state':'fabricacion'})
elif r.order_state == 'fabricacion':
r.write({'order_state':'envio'})
elif r.order_state == 'envio':
r.write({'order_state':'final'})
r.end_date = datetime.now()
elif r.order_state == 'final':
raise ValidationError("La fabricación ha finalizado !")
Can you , please , help to increase the stock quantity of the product ?
Thanks a lot.
I am using Odoo 11. In my use case I wanted to reduce the amount of a product when the stage of my custom model is set to 'done'. Inventory amount is changed by stock.move and stock.move.line. So what I did is creating a stock.move and linked a stock.move.line to it when the state changes to 'done'.
Examples of stock.move creation can be found in addons/stock/tests/test_move.py
Here is a recipe:
(1.) If you do not have one yet, create a location
<record id="location_mylocation" model="stock.location">
<field name="name">MyLocation</field>
<field name="location_id" ref="stock.stock_location_locations_virtual"/>
<field name="usage">inventory</field>
<field name="company_id"></field>
</record>
The usage is set to 'inventory' to reduce the amount of the product. Scrap Orders use the same mechanism.
(2.) Create a stock.move
stock_location = self.env.ref('stock.stock_location_stock')
move = self.env['stock.move'].create({
'name': 'Use on MyLocation',
'location_id': stock_location.id,
'location_dest_id': mylocation.id,
'product_id': product.id,
'product_uom': product.uom_id.id,
'product_uom_qty': qty,
})
move._action_confirm()
move._action_assign()
# This creates a stock.move.line record.
# You could also do it manually using self.env['stock.move.line'].create({...})
move.move_line_ids.write({'qty_done': qty})
move._action_done()

OpenERP create & write methods at once

Here is my error when i'm going to create records.please advice me where is the missing point.?
File "/home/bellvantage/Documents/openerp-7.0/openerp-7/openerp/addons/bpl/bpl.py", line 394, in create
self.write(cr, uid, [id], {'name': name}, context)
File "/usr/lib/python2.7/dist-packages/psycopg2/extensions.py", line 129, in getquoted
pobjs = [adapt(o) for o in self._seq]
ProgrammingError: can't adapt type 'builtin_function_or_method'
2013-04-26 06:14:07,719 5739 INFO demo werkzeug: 127.0.0.1 - - [26/Apr/2013 06:14:07] "POST /web/dataset/call_kw HTTP/1.1" 200 -
relevant line in my code is like this
def create(self, cr, uid, values, context=None):
name = 'CheckRoll No : ' + str(values['checkroll_no']) + ' & Gang No : ' + str(values['gang_no'])
self.write(cr, uid, [id], {'name': name}, context)
return True
error comes and shows that my write method is incorrect.seems some parameter missing by me.
needs your advices to implement module
thanks..
EDITED
Now error like below
File "/home/bellvantage/Documents/openerp-7.0/openerp-7/openerp/addons/bpl/bpl.py", line 395, in create
res = super('bpl.work.offer',self).create(cr,uid,values,context=context)
TypeError: must be type, not str
2013-04-26 07:58:43,452 6947 INFO demo werkzeug: 127.0.0.1 - - [26/Apr/2013 07:58:43] "POST /web/dataset/call_kw HTTP/1.1" 200 -
here shows my fields in model class
'name': fields.char('Name', size=50),
'checkroll_no': fields.integer('Checkroll No'),
'gang_no': fields.integer('Gang'),
here shows values when i debug (at super.create() time),
dict: {'selected_tea_workers_line_ids': [[5, False, False], [0, False, {'worker_emp_no': '1000', 'worker_id':
1, 'tea_line_worker_id': False, 'is_selected': False}]], 'user_id': False, 'is_confirmed': False,
'date_of_offer': '2013-04-26', 'bpl_division_id': 1, 'work_type': 'tea', 'checkroll_no': 10, 'name':
'CheckRoll No : 10 & Gang No : 100', 'selected_rubber_workers_line_ids': [[5, False, False], [0, False,
{'worker_emp_no': '1001', 'worker_id': 2, 'rubber_line_worker_id': False, 'is_selected': False}]],
'work_update_id': False, 'field_no': 15, 'selected_sundry_workers_line_ids': [], 'payment_type':
'normal_work', 'gang_no': 100, 'total_workers': 0, 'no_of_workers': 0, 'norm': 15,
'selected_other_workers_line_ids': [], 'bpl_estate_id': 1, 'select_by': 'by_name'}
now its worked. thanks AnomA
Last Edited
def create(self, cr, uid, values, context=None):
name = 'CheckRoll No = ' + str(values['checkroll_no']) + ' & Gang No = ' + str(values['gang_no'])
values.update({'name': name})
return super(bpl_work_offer,self).create(cr,uid,values,context=context)
Actually you are doing wrong. You are trying to write to a record that is not created.Also I dont think you need to use write in this case.
class bpl_abc(osv.osv)
_inherit = 'bpl.work.offer'
def create(self, cr, uid, values, context=None):
name = 'CheckRoll No : ' + str(values['checkroll_no']) + ' & Gang No : ' + str(values['gang_no'])
values.update({'name': name})
res = super('bpl_abc',self).create(cr,uid,values,context=context)
return res
bpl_abc()
Please keep in mind that create function in openerp always return an id of the newly created record.
May be because 'write' method is the built-in method
EX:
with open("a.txt","r+") as f:
f.write("sometext")
Don't use self.write as write is the built-in method on 'file' object

Categories