Odoo 14 overriding method - module

I'm trying to create an Odoo module which override Sales order confirm button. I followed the information I found, and I created the following code, but it doesn't work.
from odoo import models, fields, api
import logging
_logger = logging.getLogger(__name__)
class saleoverride(models.Model):
_name = 'saleoverride.saleoverride'
_description = 'saleoverride'
_inherit = 'sale.order'
name = fields.Char()
# value = fields.Integer()
# value2 = fields.Float(compute="_value_pc", store=True)
description = fields.Text()
transaction_ids = fields.Many2many('payment.transaction', 'saleoverride_transaction_rel', 'saleoverride_id', 'transaction_id',
string='Transactions', copy=False, readonly=True)
tag_ids = fields.Many2many('crm.tag', 'saleoverride_tag_rel', 'saleoverride_id', 'tag_id', string='Tags')
#api.model
def action_confirm(self):
res = super(SaleOrder, self).action_confirm()
_logger.info("saleoverride_action_confirm")
_logger.info(self)
return res
I tried to search the message in the log file, but can't find anything. Can someone help me?
Thanks!

The problem is that you are not extending the sale.order model, but creating a new one (saleoverride.saleoverride) based on sale.order.
Check odoo docs: Inheritance and extension
from odoo import models, fields, api
import logging
_logger = logging.getLogger(__name__)
class saleoverride(models.Model):
_description = 'saleoverride'
_inherit = 'sale.order'
name = fields.Char()
# value = fields.Integer()
# value2 = fields.Float(compute="_value_pc", store=True)
description = fields.Text()
transaction_ids = fields.Many2many('payment.transaction', 'saleoverride_transaction_rel', 'saleoverride_id', 'transaction_id',
string='Transactions', copy=False, readonly=True)
tag_ids = fields.Many2many('crm.tag', 'saleoverride_tag_rel', 'saleoverride_id', 'tag_id', string='Tags')
def action_confirm(self):
res = super(SaleOrder, self).action_confirm()
_logger.info("saleoverride_action_confirm")
_logger.info(self)
return res
Removing _name = 'saleoverride.saleoverride' from your class adds new features to sale.order.
Also remove the decorator since the original function doesn't have one.

When you want to override the code in addons, all you can do is just inheriting it. So, you can't define name while overriding the existing code.
Remove:
_name ='saleoverride.saleoverride'

Related

Unable to update image in Django Rest Framework , gives error " The submitted data was not a file. Check the encoding type on the form."

i was able to post the image but don't know why i am not able to update the image , i am using default form provided by DRF
i did not find any solutions yet for this one
i am uploading image via cloudinary api
the error
{
"image_1": [
"The submitted data was not a file. Check the encoding type on the form."
],
"image_2": [
"The submitted data was not a file. Check the encoding type on the form."
]
}
Model:
class MyDetail(models.Model):
name=models.CharField(max_length=50, null=True, blank=True)
image_1=models.URLField(null=True, blank=True)
image_2=models.URLField(null=True, blank=True)
Views:
class SingleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset=MyDetail.objects.all()
serializer_class = SingleDetailSerializer
lookup_field='id'
def update(self, request, *args, **kwargs):
instance = self.get_object()
image_1 = request.FILES.get('image_1',None)
image_2 = request.FILES.get('image_2',None)
if image_1:
uploaded_image_1 = cloudinary.uploader.upload(image_1)
request.data['image_1'] = uploaded_image_1['secure_url']
if image_2:
uploaded_image_2 = cloudinary.uploader.upload(image_2)
request.data['image_2'] = uploaded_image_2['secure_url']
serializer = self.get_serializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response({"message": "Updated successfully.", "data": serializer.data})
def perform_update(self, serializer):
serializer.save()
serializer:
class SingleDetailSerializer(serializers.ModelSerializer):
image_1 = serializers.ImageField(max_length=None,use_url=True,required=False)
image_2 = serializers.ImageField (max_length=None,use_url=True,required=False)
class Meta:
model = MyDetail
fields = ['id','name','image_1','image_2']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['image_1'] = instance.image_1
representation['image_2'] = instance.image_2
return representation
my DRF Form image
i even tried from my react form but it was still not working , i was not able to find solutions online and i don't know why it is not able to recognize the file though i uploaded the file. Help me to fix this
Here is how i solved it
Instead of updating image through views , i updated image directly serializer where i modified the url field to image field to upload the image
views :
class SingleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset=MyDetail.objects.all()
serializer_class = SingleDetailSerializer
lookup_field='id'
serializer :
class SingleDetailSerializer(serializers.ModelSerializer):
image_1 = serializers.ImageField(use_url=True, required=False)
image_2 = serializers.ImageField(use_url=True, required=False)
class Meta:
model = MyDetail
fields = ['id','name','image_1','image_2']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['image_1'] = instance.image_1
representation['image_2'] = instance.image_2
return representation
def update(self, instance, validated_data):
image_1 = validated_data.get('image_1',None)
image_2 = validated_data.get('image_2',None)
if image_1:
uploaded_image_1 = cloudinary.uploader.upload(image_1)
validated_data['image_1'] = uploaded_image_1['secure_url']
if image_2:
uploaded_image_2 = cloudinary.uploader.upload(image_2)
validated_data['image_2'] = uploaded_image_2['secure_url']
instance = super().update(instance, validated_data)
return instance

DRF update view with many to many field

Am trying to write update view,but got an error please help me to find the problem,thanks :)
At first I have many to many field in my model.It is my model
class Portfolio(models.Model):
name = models.CharField(max_length=50, unique=True, blank=False, null=True)
market = models.ForeignKey(Market, on_delete=models.DO_NOTHING, related_name='market')
investor = models.ForeignKey('accounts.User', on_delete=models.DO_NOTHING, related_name='investor')
assets = models.ManyToManyField(Assets, related_name='assets')
def __str__(self):
return self.name
After that I have a serializer for my view:
class PortfolioSerializer(serializers.ModelSerializer):
class Meta:
model = Portfolio
fields = ['name', 'market', 'investor', 'assets']
And it's my view:
class PortfolioUpdateView(APIView):
serializer_class = PortfolioSerializer
def put(self, request, *args,):
data = request.data
portfo = Portfolio.objects.get(id=id)
print(portfo)
serilize = self.serializer_class(instance=request.user, data=request.POST)
if serilize.is_valid():
name = serilize.data['name']
market = Market.objects.get(pk=int(request.POST.get('market', '')))
assets = Assets.objects.get(pk=int(request.POST.get('assets', '')))
Portfolio.objects.update(name=name, market=market,
assets=assets,
)
return portfo
else:
pass
and at the end it is my error:
TypeError at /market/update/1
put() got an unexpected keyword argument 'id'
I found the answer by my self,because I needed to use id for get obj so I used request.data that is body's data of object include obj's id and added query-set method for getting the class objs
class PortfolioUpdateView(viewsets.ModelViewSet):
serializer_class = PortfolioSerializer
def get_queryset(self):
portfolio = Portfolio.objects.all()
return portfolio
def put(self, request, *args, **kwargs):
data = Portfolio.objects.get(id=request.data['id'])
update_portfolio = Portfolio.objects.update(name=data['name']
, market=Market.objects.get(pk=int(request.POST.get('market', ''))))
update_portfolio.save()
for asset in data['assets']:
asset_obj = Assets.objects.update(asset_name=asset['asset_name'])
update_portfolio.assets.add(asset_obj)
serializer = PortfolioSerializer(update_portfolio)
return Response(serializer.data)
And this is the URL
router.register("update", PortfolioUpdateView, basename="update")

fill up binary field with default_get

I have two binary fields. In the sale order line tree view, I have a button to open my wizard. I chose and save file and it's perfectly saved in my label_file field of the selected sale order line.
The problem is that when I open the wizard I want to see it as a saved file, but it's not generated and only bytes are in the path.
first
Class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
label_file = fields.Binary('Saved Label')
Saved in SaleOrderLine
second
class OrderLineLabel(models.TransientModel):
_name = 'order.line.label'
label_file_show = fields.Binary('Label file')
#api.multi
def write_label_vals(self):
self.ensure_one()
sale_order_line = self.env['sale.order.line'].browse(self.env.context.get('active_ids'))
vals = {
'label_file': self.label_file,
}
sale_order_line.write(vals)
#api.model
def default_get(self, fields):
res = super(OrderLineLabel, self).default_get(fields)
order_line_id = self.env['sale.order.line'].browse(self.env.context.get('active_ids'))
status, headers, content = binary_content(model='sale.order.line', field='label_file', id=order_line_id.id,filename='test',download=True)
#tried like this
res['label_file_show'] = content
#or just like this
res['label_file_show'] = order_line_id.label_file
return res
this is how it looks when I open the wizard.
You need to add filename to the binary fields.
Declare a char field to hold the name:
label_file_name = fields.Char()
And use filename attribute to specify the file name to the binary field:
<field name="label_file_name" invisible="True"/>
<field name="label_file_show" filename="label_file_name"/>
In write_label_vals add one more line to save also the file name.
order_line_id.label_file_name = self.label_file_name
# vals = {'label_file': self.label_file, 'label_file_name': self.label_file_name}
Set the value of the filename in the wizard default_get method :
res['label_file_name'] = order_line_id.label_file_name

How to add one more entry in selection field of an already defined odoo model using inheritance

Environment :- Odoo 9, Python 2.7
Module A
from openerp import models, fields, api, _, exceptions
class Games(models.Model):
_name = 'moduleA.games'
game = fields.Selection([
('cricket', 'Cricket'),
('hockey', 'Hockey'),
('golf', 'Golf')],
string='Game', default='cricket', required=True
)
Module B
from openerp import models, fields, api, _, exceptions
class ExtraGames(models.Model):
_inherit = 'moduleA.games'
def __init__(self, pool, cr):
res = super(ExtraGames,self)._columns # res = {}
super(ExtraGames,self)._columns['game'].selection.append(
('chess', 'Chess')
)
Now using that code, I want to add one more game Chess inside already defined games list but its not working. Actually I am getting empty dictionary ( {} ) as result of super(ExtraGames,self)._columns and because of that its giving KeyError 'game'.
How can we do it ?
You can use selection_add:
from openerp import fields, models
class ExtraGames(models.Model):
_inherit = 'moduleA.games'
game = fields.Selection(
selection_add=[('chess', 'Chess')],
)

Sequential Order for Item Output | Scrapy

I am using a ScrapingHub API, and am using shub, to deploy my project. However, the items result is in as shown:
Unfortunately, I need it in the following order --> Title, Publish Date, Description, Link. How can I get the output to be in exactly that order for every item class?
Below is a short sample of my spider:
import scrapy
from scrapy.spiders import XMLFeedSpider
from tickers.items import tickersItem
class Spider(XMLFeedSpider):
name = "Scraper"
allowed_domains = ["yahoo.com"]
start_urls = ('https://feeds.finance.yahoo.com/rss/2.0/headline?s=ABIO,ACFN,AEMD,AEZS,AITB,AJX,AU,AKERMN,AUPH,AVL,AXPW
'https://feeds.finance.yahoo.com/rss/2.0/headline?s=DRIO
'https://feeds.finance.yahoo.com/rss/2.0/headline?s=IDXG,IMMU,IMRN,IMUC,INNV,INVT,IPCI,INPX,JAGX,KDMN,KTOV,LQMT
)
itertag = 'item'
def parse_node(self, response, node):
item = {}
item['Title'] = node.xpath('title/text()',).extract_first()
item['Description'] = node.xpath('description/text()').extract_first()
item['Link'] = node.xpath('link/text()').extract_first()
item['PublishDate'] = node.xpath('pubDate/text()').extract_first()
return item
Additionally, here is my attached items.py file, it is in the same order as my spider, so I have no idea why the output is not in order.
Items.py:
import scrapy
class tickersItem(scrapy.Item):
Title = scrapy.Field()
Description = scrapy.Field()
Link = scrapy.Field()
PublishDate = scrapy.Field()
The syntax of my code is in order for both the items and the spider file, and I have no idea how to fix it. I am a new python programmer.
Instead of defining items in items.py, you could use collections.OrderedDict. Just import collections module and in parse_node method, change the line:
item = {}
to line:
item = collections.OrderedDict()
Or, if you want defined items, you could use approach outlined in this answer. Your items.py would then contain this code:
from collections import OrderedDict
from scrapy import Field, Item
import six
class OrderedItem(Item):
def __init__(self, *args, **kwargs):
self._values = OrderedDict()
if args or kwargs: # avoid creating dict for most common case
for k, v in six.iteritems(dict(*args, **kwargs)):
self[k] = v
class tickersItem(OrderedItem):
Title = Field()
Description = Field()
Link = Field()
PublishDate = Field()
You should then also modify your spider code to use this item, accordingly. Refer to the documentation.