Odoo DIN5008 append or change information_block - python

I'm having trouble append extra information to the information_block of the DIN5008 template.
I inherited the sale.order module like suggested here.
I tried override both _compute_l10n_de_template_data functions in the sale.order and the account.move but nothing changes. I can't append nor leave everything empty.
If I look for models in the odoo inteface I can see, that my module inherits the sale.order and account.move model. So I don't think I have an error in my __init__.py files. I can also create new fields, but trying to overwrite those functions won't change the output in the report.
Here is my code for the sale.order model:
from odoo import models, fields, _
from odoo.tools import format_date
class SaleOrder(models.Model):
_inherit = 'sale.order'
l10n_de_template_data = fields.Binary(compute='_compute_l10n_de_template_data')
def _compute_l10n_de_template_data(self):
for record in self:
record.l10n_de_template_data = data = []
if record.state in ('draft', 'sent'):
if record.name:
data.append((_("Quotation No."), record.name))
if record.date_order:
data.append((_("Quotation Date"), format_date(self.env, record.date_order)))
if record.validity_date:
data.append((_("Expiration"), format_date(self.env, record.validity_date)))
else:
if record.name:
data.append((_("Order No."), record.name))
if record.date_order:
data.append((_("Order Date"), format_date(self.env, record.date_order)))
if record.client_order_ref:
data.append((_('Customer Reference'), record.client_order_ref))
if record.user_id:
data.append((_("Salesperson"), record.user_id.name))
if record.partner_id:
data.append((_("Customer"), record.partner_id))
It doesn't matter what I do to _compute_l10n_de_template_data I can't see my changes in an offer or invoice (if I change the function in account.move)
Seems like I'm doing something fundamentally wrong.

You already linked to addon l10n_de_sale in which you can find the definition of _compute_l10n_de_template_data and its DIN 5008 infoblock.
See here.
I ended up adding additional information to the block in the code. After restarting the service it worked well for me.
if record.user_id and record.user_id.mobile:
data.append((_("Mobile"), record.user_id.mobile))
if record.user_id and record.user_id.email:
data.append((_("Email"), record.user_id.email))
if record.commitment_date:
data.append((_("Estimated Delivery"), format_date(self.env, record.commitment_date)))
It shouldn't be forgotten to restart the service to make the changes work.
To have the labels tranlated i generated missing translations in settings and could translate the newly added labels.

Related

Django import-export, only export one object with related objects

I have a form which enables a user to register on our website. Now I need to export all the data to excel, so I turned towards the import-export package. I have 3 models, Customer, Reference and Contact. The latter two both have a m2m with Customer. I also created Resources for these models. When I use Resource().export() at the end of my done() method in my form view, it exports all existing objects in the database, which is not what I want.
I tried googling this and only got one result, which basically says I need to use before_export(), but I can't find anywhere in the docs how it actually works.
I tried querying my customer manually like:
customer = Customer.objects.filter(pk=customer.id)
customer_data = CustomerResource().export(customer)
which works fine but then I'm stuck with the related references and contacts: reference_data = ReferenceResource().export(customer.references) gives me an TypeError saying 'ManyRelatedManager' object is not iterable. Which makes sense because export() expects an queryset, but I'm not sure if it's possible getting it that way.
Any help very appreciated!
One way is to override get_queryset(), you could potentially try to load all related data in a single query:
class ReferenceResource(resources.ModelResource):
def __init__(self, customer_id):
super().__init__()
self.customer_id = customer_id
def get_queryset(self):
qs = Customer.objects.filter(pk=self.customer.id)
# additional filtering here
return qs
class Meta:
model = Reference
# add fields as appropriate
fields = ('id', )
To handle m2m relationships, you may be able to modify the queryset to add these additional fields.
This isn't the complete answer but it may help you make progress.

Run code when "foreign" object is added to set

I have a foreign key relationship in my Django (v3) models:
class Example(models.Model):
title = models.CharField(max_length=200) # this is irrelevant for the question here
not_before = models.DateTimeField(auto_now_add=True)
...
class ExampleItem(models.Model):
myParent = models.ForeignKey(Example, on_delete=models.CASCADE)
execution_date = models.DateTimeField(auto_now_add=True)
....
Can I have code running/triggered whenever an ExampleItem is "added to the list of items in an Example instance"? What I would like to do is run some checks and, depending on the concrete Example instance possibly alter the ExampleItem before saving it.
To illustrate
Let's say the Example's class not_before date dictates that the ExampleItem's execution_date must not be before not_before I would like to check if the "to be saved" ExampleItem's execution_date violates this condition. If so, I would want to either change the execution_date to make it "valid" or throw an exception (whichever is easier). The same is true for a duplicate execution_date (i.e. if the respective Example already has an ExampleItem with the same execution_date).
So, in a view, I have code like the following:
def doit(request, example_id):
# get the relevant `Example` object
example = get_object_or_404(Example, pk=example_id)
# create a new `ExampleItem`
itm = ExampleItem()
# set the item's parent
itm.myParent = example # <- this should trigger my validation code!
itm.save() # <- (or this???)
The thing is, this view is not the only way to create new ExampleItems; I also have an API for example that can do the same (let alone that a user could potentially "add ExampleItems manually via REPL). Preferably the validation code must not be duplicated in all the places where new ExampleItems can be created.
I was looking into Signals (Django docu), specifically pre_save and post_save (of ExampleItem) but I think pre_save is too early while post_save is too late... Also m2m_changed looks interesting, but I do not have a many-to-many relationship.
What would be the best/correct way to handle these requirements? They seem to be rather common, I imagine. Do I have to restructure my model?
The obvious solution here is to put this code in the ExampleItem.save() method - just beware that Model.save() is not invoked by some queryset bulk operations.
Using signals handlers on your own app's models is actually an antipattern - the goal of signal is to allow for your app to hook into other app's lifecycle without having to change those other apps code.
Also (unrelated but), you can populate your newly created models instances directly via their initializers ie:
itm = ExampleItem(myParent=example)
itm.save()
and you can even save them directly:
# creates a new instance, populate it AND save it
itm = ExampleItem.objects.create(myParent=example)
This will still invoke your model's save method so it's safe for your use case.

Many2many field related to another model

I'm trying to create a many2many field inside a Contact model that would have the same values like company_ids inside a Users model at all times.
I was looking for the anwserws but the odoo docs have like two sentences about this topic and do not explain this firmly.
Other sources seem to contradict themselfs because some says that related stored field do not update while other says that they do.
And after all I don't know the syntax for creating one myself because dosc are so poorly written.
I have this piece of code:
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class custom_partner_fields(models.Model):
_inherit = 'res.partner'
company_ids = fields.Many2many(comodel_name='res.company', string='Related users Allowed companies', readonly=True)
It is creating field inside Contact model and now I need something to fill it in. Preferably without using onchange methods or automatic actions (I have automatic action right now - created via developer UI).
Just set the field in partner record after creating or editing the user record
__inherit = 'res.users'
#api.model
def create(self, vals):
res = super(TheClassName, self).create(vals)
res.partner_id.company_ids = res.company_ids
return res
#api.multi
def write(self, vals):
super(TheClassName, self).write(vals)
# if we edited company_ids we edit partners too
if 'company_ids' in vals:
# use mapped to call write one time good for performance
self.mapped('partner_id').write({'company_ids': vals['company_ids']})
return True
So when ever you edit company_ids in user you do the same for related partner.
This will work for new user for sure but I think you need to handle existing users
by a script or some solution to fill up the field.

Display icons in Django admin for each item

I want to add a specified icon for each model on admin index page. I added an attribute named "picture" on each model then I modified /contrib/admin/sites.py to pass that picture name to template and checked and use it on index.html template of admin to get the result.
I wonder to know if there is a better way
class Product(models.Model):
abbr = models.CharField(max_length=20,unique=True)
title = models.CharField(max_length=200,unique=True)
owner = models.ForeignKey(UserProxy)
des = models.TextField(blank=True,null=True)
picture = 'product.png'
def __unicode__(self):
return self.abbr
class Meta:
none
What You did seems OK, only small tips that can make Your code a little better:
Instead of modifying django/contrib/admin/sites.py You can subclass the AdminSite class (if You didn't do that already).
Modify the AdminSite.index() method to pass not picture, but whole admin class (there is a model_admin variable available in the index() method).
Assign picture in the ModelAdmin classes, not models, to separate admin stuff from models.
The answer from 'Python Fanboy' was so brief but useful to me, I could avoid modifying django base classes
picture field were moved to admin class
I subclass AdminSite as CustomAdminSite and copied index and app_index and made modification
(I don't know if there is a better way than copying whole of index and app_index like overriding)
In urls.py, 'admin.sites.url' replaced by 'custom_site.url'
(custom_site is instance of CustomAdminSite)
I did not want another url instead of '/admin' like '/my_admin' so I have to use instance of CustomAdminSite for all my models even User, Group & Site
I'm using admin_tools, now I've lose my application menu
Any better Idea or solution for my new encountered problems?

How do I filter by a ForeignKey's db_column field without going through the foreign object in Django

I have a legacy database with non-django naming conventions. If I have the following (cut down) models:
class Registration(models.Model):
projectId=models.IntegerField(primary_key=True)
class Application(models.Model):
applicationId=models.IntegerField(primary_key=True)
registration=models.ForeignKey(Registration,db_column='projectId')
The ForeignKey instance causes a property to be created on Application called registration_id, but this is neither the correct name for the field (I have a hack to fix this), nor is it able to be used in a QuerySet.
Is there some way of using the id field provided by the ForeignKey on the Application model, rather than having to reference it via Registration?
Ie. I write lots of code like:
Application.objects.get(projectId=1234)
And don't want to have to write it out as:
Application.objects.get(registration__projectId=1234)
or even
Application.objects.get(registration__pk=1234)
I'm slightly surprised that:
Application.objects.get(registration_id=1234)
doesn't work...
Also note, I tried defining the id column as a field as well as the foreignkey which worked for queryset, but inserts complain of trying to insert into the same column twice:
class Application(models.Model):
...
projectId=models.IntegerField()
...
Have you tried this?
Application.objects.get(registration=1234)
I think just doing Application.objects.registration.get(projectId=1234) should do what you want.

Categories

Resources