Odoo 12 - Generate and download CSV file - python-3.x

I have added a menu item in Reporting Tab in Manufacturing module. I have already written python code to create CSV file. But unable to figure out how to make it downloadable when I click the menu item in manufacturing module.
Here is the menu item code:
<record model="ir.actions.server" id="raw_material_planning">
<field name="name">Raw Material Planning</field>
<field name="type">ir.actions.server</field>
<field name="res_model">gear.manufacturing</field>
<field name="model_id">342</field>
<field name="state">code</field>
<field name="code">
action = model.raw_material_planning()
</field>
</record>
<menuitem name="Raw Material Planning" parent="mrp.menu_mrp_reporting" id="menu_raw_material_planning"
action="raw_material_planning"/>
Also, it should directly download and not go to any window.
UPDATE
saved dictionary to CSV file
files = base64.b64encode(open('test.csv','rb').read())
attachment = self.env['ir.attachment'].create({
'name': 'test.csv',
'datas': files,
'datas_fname': 'test.csv'
})
return {
'type': 'ir.actions.act_url',
'url': '/web/content/%s?download=true' % (attachment.id),
# 'target': 'new',
'nodestroy': False,
}
Kindly assist me

Here is all controllers are available for download contents or files.
You need to return any of controller with your file content it will automatically download.
[
'/web/content',
'/web/content/<string:xmlid>',
'/web/content/<string:xmlid>/<string:filename>',
'/web/content/<int:id>',
'/web/content/<int:id>/<string:filename>',
'/web/content/<int:id>-<string:unique>',
'/web/content/<int:id>-<string:unique>/<string:filename>',
'/web/content/<string:model>/<int:id>/<string:field>',
'/web/content/<string:model>/<int:id>/<string:field>/<string:filename>'
]
For download any file you need to create one attachment record for ir.attachment.
Then just add below code in your function for return file to url.
attachment = self.env['ir.attachment'].search([('name', '=', 'import_product_sample')])
return {
'type': 'ir.actions.act_url',
'url': '/web/content/%s?download=true' % (attachment.id),
'target': 'new',
'nodestroy': False,
}
It will automatically download your file in browser.

Related

close wizard after clicking button in odoo 12

can you please help me regarding close wizard.
i have created a wizard from xml when i add dates and click on xlsx button,
xlsx generated and wizard close it self. it works fine.
but when i click on pdf, pdf generate successfully but wizard remains open.
how can i close it.
here is my code of xml.
<record id="payment_invoice_wizard_form" model="ir.ui.view">
<field name="name">Invoice Payment Report</field>
<field name="model">invoice.payment_report</field>
<field name="arch" type="xml">
<form string="Invoice Payment Report">
<group>
<field name="start_date"/>
<field name="end_date"/>
<field name="status"/>
</group>
<!-- other fields -->
<footer>
<button name="print_pdf" string="Print" type="object" class="btn-primary"/>
<button name="print_xls" string="Print in XLS" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
on py side i am getting all necessary data and returning this function
#api.multi
def print_pdf(self):
#mycode
return self.env.ref('customer_products.pdf_products').report_action(self)
When Odoo launch the download action of a report it will check if close_on_report_download action attribute is set to true, if so it will return action of type ir.actions.act_window_close which will close the wizard.
#api.multi
def print_pdf(self):
action = self.env.ref('customer_products.pdf_products').report_action(self)
action.update({'close_on_report_download': True})
return action
Edit:
You can implement the same logic, override QWEBActionManager and check if the option is passed through the action definition and if yes close the window.
var ActionManager = require('web.ActionManager');
var session = require('web.session');
ActionManager.include({
ir_actions_report: function (action, options) {
var self = this;
return $.when(this._super.apply(this, arguments), session.is_bound).then(function() {
if (action && action.report_type === 'qweb-pdf' && action.close_on_report_download) {
return self.do_action({ type: 'ir.actions.act_window_close' });
}
});
},
});

How to open a form view (wizard) after button click in odoo 13 in Sales

i have created a button "+Add Products" below order lines using inheritance and xpath in sale.order in Odoo 13.0 Sales Module, my aim is that when i click "+Add Products" button, Just open a wizard (like customized form view, where i can fill products details) and also create below Add button in wizard.
quotation_product.xml
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record model="ir.ui.view" id="view_order_form">
<field name="name">sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="/form/sheet/notebook/page/field[#name='order_line']"
position="before">
<button name="my_button" string=" + Add Products" type="object" class="btn
btn-info btn- lg"/>
</xpath>
</field>
</record>
</data>
</odoo>
quotation_product.py
from odoo import api, fields, models, api
class SaleOrder(models.Model):
_inherit = "sale.order"
_name = "sale.order"
def my_button(self, context=None):
print("ghghhhghghghghg")
return True
Mr op,
On your button, you can return your view like this,
So pass the object and your module view.In that, your view added the button on footer and with same added the logic on that footer_button to perform in your customized way.
def my_button(self):
return {
'name': "Your String",
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'object',
'view_id': self.env.ref('module.view_id').id,
'target': 'new'
}
And In your py file if you want to inherit the odoo defaul_object like sale.order then no need to use the _name.
class SaleOrder(models.Model):
_inherit = "sale.order"
You can also refer and find the official odoo13 documentation.
Thanks

How to retrieve in cakephp3.7 the name as string of an image uploaded trough a form with blob column into a mysql database?

I'm building an e-commerce website with cakephp3.7, and for sellers to post their products they need to upload the image of the article to sell, and that through a form with a Blob column. The images are being uploaded well from the view, but in the database the real name of the image does not appear, instead of that, in that place the name that appears for all the images is 'Blob' for all the articles. The problem is now that when I try to retrieve the article's image (which is only knowledgeable by it's name) from the database to the controller in order to send it to the frontend of the website, it doesn't find the image, and I'm seriously stuck !!!
But when I get to webroot/img folder, I find the uploaded image and, when I manually copy/paste the name in the frontend view, the image appears on the frontend with the other properties of the articles.
This is the controller code that is supposed to find the articles and their images from the database, the table to adress is table 'annonces', and the field of the table to store the image in is 'piece_jointe':
public function articles()
{
$this->viewBuilder()->layout('react2019');
$annonces = $this->Annonces->find()
->where(['Annonces.subcategorie_id'=>1])
->contain(['Comptes', 'Subcategories'])
->all();
$this->set(compact('annonces'));
}
And this is the article view when to forward the posted article to the frontend, the field which I can't retreive now is 'piece_jointe':
<?php foreach ($annonces as $annonce): ?>
<div class="col-lg-4 col-md-6 mb-4">
<div class="card h-100">
<?= $this->Html->image($annonce->piece_jointe, array('height'=>90, 'width'=>90)); ?>
<div class="card-body">
<h4 class="card-title">
<?= h($annonce->annonce_titre) ?>
</h4>
<h5><?= h($annonce->prix_produit) ?></h5>
<p class="card-text"><?= h($annonce->annonce_description) ?></p>
</div>
<div class="card-footer">
<small class="text-muted">★ ★ ★ ★ ☆</small>
</div>
</div>
</div>
<?php endforeach; ?>
I want to know the way to retrieve the name of a Blob type 'piece_jointe' from the mysql database and use it in the cakephp syntax:
<?= $this->Html->image($annonce->piece_jointe, array('height'=>90, '
width'=>90)); ?>
since this works fine when I replace the $annonce->piece_jointe varaible to it's real name 'macbook' for example :
<?= $this->Html->image('macbook', array('height'=>90, 'width'=>90)); ?>
So far so good ! I dived deeper into cakephp's conventions about dealing with files such as images, videos, pdf, docs etc.. and I understood more things. First I thought I should store the image as BLOB in database in order to respect the MVC concept. But I finally figure out that cakephp has a leverage on how to deal with images and files in general, for images and files are sensible informations that open loopholes in applications and cakephp recommends not to store images straight in database to prevent from attacks such as SQL INJECTION. Many people have asked questions about how to deal with images in cakephp, but the answers that were given were not all fully applicable. So I wanna give the essentials in some 4 steps:
1- When we upload a file just as I did with the column 'piece_jointe' which type I changed from 'BLOB' to 'VARCHAR', cakephp gives parameters to that image as you can see here from the rendering of my debug($this->request->data) :
[
'title' => 'computer',
'category_id' => '1',
'subcategory_id' => '3',
'announce_description' => 'smart price',
'prix_produit' => '500000',
'photo'=> '',
'compte_id' => '1',
'piece_jointe' => [
'tmp_name' => '/private/var/folders/kl/lgxkfn5x4r1fjht2wckngjzr0000gn/T/phpodWgh1',
'error' => (int) 0,
'name' => 'macbook.jpg',
'type' => 'image/jpeg',
'size' => (int) 37780
]
]
You can observe that 'piece_jointe' has fields such as 'temp_name','error', 'name', 'type', 'size' created by cakephp for us to customise image and file uploading.
But what we do need in this bunch of informations is 'name'. So we are going to add an other varchar column to the table announce in database, and that's why I added the column 'photo' with varchar type that you can see in the above debug result. The aim is to give to 'photo' the image's path $uploadPath = WWW_ROOT.'img/products/' and its name $fileName = $this->request->data['piece_jointe']['name'] in our controller add() method
so cakephp may follow that path and get the image from the relevant folder which is in my case products folder inside webroot/img. The overall actions look something like these:
if (!empty ($this->request->data['piece_jointe']['tmp_name']))
{
$fileName = $this->request->data['piece_jointe']['name'];
$uploadPath = WWW_ROOT.'img/products/';
$uploadFile = $uploadPath.$fileName;
if (move_uploaded_File($this->request->data['piece_jointe']['tmp_name'], $uploadFile))
{
$annonce->photo = 'products/'.$fileName;
}
}
2- Then in the Model/Table don't forget to add this to the public function initialize(array $config) method:
$this->addBehavior('Timestamp');
An other thing is also not to forget to mention in the add() view where to upload the image that 'piece_jointe' is of 'type'=>'file'.
You may have it like this:
<?php
echo $this->Form->input('piece_jointe', [ 'type' => 'file']);
?>
</Div>
3- Finally the column 'photo' receives this value in database /products/macbook.jpg instead of 'BLOB' while I was going nuts.
4- And to retrieve the image we just have to add this to the view:
<?= $this->Html->image($annonce->photo, array('height'=>90, 'width'=>90)); ?>
In conclusion, these are reliable steps to handle images and files uploading in cakephp. Storing images into database with BLOB type and expecting it to be displayed in frontend frow a raw MVC concept is just too loopy.
Also thanks to #ndm for making me know I was missing the concept.

Odoo: how to filter values from related project_task_type

In Odoo, I inherited the "project" model and made some small changes.
Project model in my module:
class project(models.Model):
_inherit = "project.project"
_columns = {
'is_project' : fields.boolean("Is project", default=True)
}
class project_task_type(models.Model):
_inherit = "project.task.type"
_columns = {
'task_type_is_project' : fields.boolean("Is project", default=True)
}
Relation beetwen project_project and project_task_type in original project module:
project_project:
'type_ids': fields.many2many(
'project.task.type', 'project_task_type_rel', 'project_id',
'type_id', 'Tasks Stages',
states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
project_task_type:
'project_ids': fields.many2many(
'project.project', 'project_task_type_rel',
'type_id', 'project_id', 'Projects'),
In original form view :
<record id="edit_project" model="ir.ui.view">
<field name="name">project.project.form</field>
<field name="model">project.project</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
[...]
<page string="Project Stages" attrs="{'invisible': [('use_tasks', '=', False)]}" name="project_stages">
<field name="type_ids"/>
</page>
[...]
So my question is how to filter type_ids records to get values from project_task_type where task_type_is_project = False.
I added domain attribute to field with name "type_ids"
<field name="type_ids domain="[('type_id.task_type_is_poject','=',False)]"/>
<field name="type_ids domain="[('task_type_is_poject','=',False)]"/>
but without success.
I will be very grateful for any help.
I added domain attribute to field with name "type_ids"
<field name="type_ids domain="[('type_id.task_type_is_poject','=',False)]"/>
<field name="type_ids domain="[('task_type_is_poject','=',False)]"/>
but without success.
The second way is the correct one, the domain operates on the model of the field, so project.task.type, which means you should directly filter on its fields, in this case task_type_is_project. There is no type_id field.
The only problem I see is a typo: you forgot a r in project.

Show Activities Tab when clicking on a custom navigation link

I am working on a customisation for CRM 2011. I have created a custom entity (which is based on activity so is an activity type aswell), created the relationship to account and on the account form created a custom navigation link pointing to a web resource which will power the custom display (this is just a html page with JavaScript).
The Web resource is used instead of a standard relationship link because it is doing a listings and preview display and not just the list view that the out of the box feature provides.
What i am trying to do is show the activities tab (the activities ribbon tab) on the accounts form, whenever the custom navigation link is pressed and a user goes into that section, in the same way it displays when you click the activities navigation link. I can't seem to find that much information on Tab Display Rules as i think that is the place (if this is possible) that it should be done.
Also, if there is a JavaScript way of doing it (although i have not found any) then that would work as well.
We have a solution.
DISCLAIMER This solution is not recommended (or supported) as it is a complete hack of epic proportions, but it solved the issue for us. this is a temporary bit of functionality as we build out a custom solution which will better fit the client, so it will not be there moving forwards which is why the hack worked for us. Additionally, a scripts could be written much better, we simply wanted to get it out the door.
NOTE: This solution will use some external libraries such as JQuery & CRM FetchKit
1) Adding a relationship to the custom object and account
We have a custom entity, and we created a 1:N relationship from the Account entity to our custom entity. What this does enables us to do is create a navigation link on the account form which points to an associated view of our custom entity. Once the link is in, we save and publish changes.
2) Get the id of the new navigation link created
The link above should now be on the form, so after saving and publishing we go to the live view and using the IE developer tools we get the id of the link as we need to catch the onclick and do some things with it later.
3) Decorating the onclick of the navigation link created
We have the id so and we want to decorate the onclick with some additional functionality. We create 2 new web resources:
"YourCustomEntity"_init : Javascript Web Resource: this will be used in the onload of the account form to get the link we created and alter the onclick to do some additional things
YourCustomEntity_page : HTML Page Web Resource: As per the original question, we have a additional requirement of showing a preview pane which is why we couldn't use the standard grid
Code for "YourCustomEntity"_init
Code is pretty basic and doesn't have any object caching or the like it was simply written to solve our problem. I have added comments to the code. Also Entity is a generic name, this was the name of our custom type. We set the original associated view to hidden instead of display:none because we still need it to load in the background as this is where the ribbon gets updated and loads, so there is definitely some script going on to do this, wish we knew it so we could just use that :)
function previewEntityInit(){
//Catch any navigation link click, we need this because we need to hide our
//grid when we are not on the custom entity page
$('.ms-crm-Nav-Subarea-Link, .ms-crm-FormSelector-SubItem').click(function () {
//Get the id of the link clicked and the frame injected object
var id = $(this).attr('id'),
cFrame = $('#entity_frame_preview');
//if the frame has already been injected
if(cFrame.length !== 0) {
//If we are not in the correct section
//(i.e. activities nav link was clicked) hide it
if (id !== 'nav_new_account_new_entity') {
cFrame.attr('style', 'display:none;');
}
else{
//The correct link was clicked, so show it
cFrame.attr('style', 'display:block; width:100%; height:100%;');
$('#new_account_new_entityFrame').attr('style', 'visibility: hidden;');
}
}
else{
//This is the first time the correct link has been clicked
//So we hide the default associated view and inject our
//own iframe point to the YourCustomEntity_page embedded resource we created
var src = Xrm.Page.context.getServerUrl();
if (id === 'nav_new_account_new_entity') {
$('#new_account_new_entityFrame').attr('style', 'visibility: hidden;');
$('<iframe />', {
id: 'entity_frame_preview',
src: src + '/WebResources/new_entity_page',
width: '100%',
height: '100%'
}).prependTo('#tdAreas');
}
}
});
YourCustomEntity_page
Not going to show all the code here, but we based ours on this link:
Preview Form Link
We changed it in the following ways:
Only the view name is hardcodes, the rest is taken via code (code below)
We don't use the second iframe opting instead to have a simple HTML section which loaded this (code for this and our load function below)
No Hard Coded Values
var server = Xrm.Page.context.getServerUrl();
var orgName = "";
// grid related settings
var entityId = window.parent.Xrm.Page.data.entity.getId();
var entityType = "1";
var areaView = "new_account_new_entity";
var internalGridElement = "crmGrid_new_account_new_entity";
var timeoutKey = null;
HTML For Preview
<div id="previewForm" style="display: none;">
<ol>
<li><span class="lbl">Account:</span><span id="lblAccount"></span></li>
<li><span class="lbl">Created:</span><span id="lblDate"></span></li>
<li><span class="lbl">Regarding:</span><span id="lblRegarding"></span></li>
<li><span class="lbl">Owner:</span><span id="lblOwner"></span></li>
</ol>
<div id="subject">
<span class="lbl">Subject:</span><span id="lblSubject" class="value"></span>
</div>
<div>
<span id="lblMsg"></span>
</div>
</div>
LoadPreview Code
This uses an external library called CRMFetchKit. The code actually does three fetch calls, this is not ideal and it should be one really (using joins, google it :)), but this wasn't working and was dragging so we decided just to go with three as this whole section will be replaced with a managed solution soon.
function LoadPreviewPane(entity) {
if (entity != null) {
$('#previewForm').show();
var fetchxml = ['<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">',
' <entity name="new_entity">',
'<attribute name="subject" />',
'<attribute name="description" />',
'<attribute name="createdon" />',
'<attribute name="new_account" />',
'<attribute name="ownerid" />',
' <filter type="and">',
' <condition attribute="activityid" operator="eq" value="' + entity.Id + '" />',
' </filter>',
' </entity>',
'</fetch>'].join('');
CrmFetchKit.Fetch(fetchxml).then(function (results) {
var account = window.parent.Xrm.Page.getAttribute("name").getValue(),
subject = results[0].getValue('subject'),
desc = results[0].getValue('description'),
created = new Date(results[0].getValue('createdon')),
theDate = created.getDate() + "/" + (created.getMonth() + 1) + "/" + created.getFullYear(),
owner = '',
regarding = '';
var fetchxml2 = ['<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">',
' <entity name="systemuser">',
'<attribute name="fullname" />',
' <filter type="and">',
' <condition attribute="systemuserid" operator="eq" value="' + results[0].getValue('ownerid') + '" />',
' </filter>',
' </entity>',
'</fetch>'].join('');
CrmFetchKit.Fetch(fetchxml2).then(function (users) {
owner = users[0].getValue('fullname');
$('#lblOwner').html(owner);
});
var fetchxml3 = ['<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">',
' <entity name="account">',
'<attribute name="name" />',
' <filter type="and">',
' <condition attribute="accountid" operator="eq" value="' + results[0].getValue('new_accountname') + '" />',
' </filter>',
' </entity>',
'</fetch>'].join('');
CrmFetchKit.Fetch(fetchxml3).then(function (regardings) {
regarding = regardings[0].getValue('name');
$('#lblRegarding').html(regarding);
});
$('#lblAccount').html(account);
$('#lblSubject').html(subject);
$('#lblMsg').html(nl2br(desc));
$('#lblDate').html(theDate);
});
}
}

Resources