i created a method as below: but it only takes the last loop data not all the data to xml for generating pdf,so need a way to generate pdf on a loop from this method
def bsku_asin_picking(self):
website = self.env['website'].search([('company_id', '=', self.env.company.id)], limit=1)
# print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%', website.label_type)
# vals = []
for rec in self.move_ids_without_package:
product = self.env['product.product'].browse(rec.product_id.id)
data = {
'quantity': rec.product_uom_qty,
'display_name': product.display_name,
'product': product,
}
if website.label_type == 'bsku':
data['barcode_value'] = product.bsku
else:
data['barcode_value'] = product.asin
# vals.append(data)
return self.env.ref('product_label_bsku_sin.report_product_template_label').report_action(product, data=data)
The variables passed through data will be available in the rendering context.
Example:
def bsku_asin_picking(self):
website = self.env['website'].search([('company_id', '=', self.env.company.id)], limit=1)
vals = []
for rec in self.move_ids_without_package:
product = rec.product_id
product_data = {
'quantity': rec.product_uom_qty,
'display_name': product.display_name,
'product': product,
}
if website.label_type == 'bsku':
product_data['barcode_value'] = product.bsku
else:
product_data['barcode_value'] = product.asin
vals.append(product_data)
datas = {'vals': vals}
return self.env.ref('product_label_bsku_sin.action_report_product_template_label').report_action(self, data=datas)
Then you can loop over vals and print product data.
Example:
<t t-foreach="vals" t-as="product_data">
<p t-out="product_data['quantity']"/>
<p t-out="product_data['display_name']"/>
<p t-out="product_data['product']"/>
<p t-out="product_data['barcode_value']"/>
</t>
Alternative
You can also call report_action without data and loop over the move_ids_without_package:
Example:
<t t-set="website_label_type" t-value="doc.env['website'].search([('company_id', '=', doc.env.company.id)], limit=1)"/>
<t t-foreach="doc.move_ids_without_package" t-as="line">
<p t-out="line.product_uom_qty"/>
<p t-out="line.display_name"/>
<p t-out="line.product_id.name"/>
<t t-if="website_label_type == 'bsku'">
<span t-out="line.product_id.bsku"/>
</t>
<t t-else="">
<span t-out="line.product_id.asin"/>
</t>
</t>
I'm new in this community and I setting up Odoo Community version for my little comapny. I does all the things just doesn't know how to set up num2words to show Total Amount in Invoice Reports!
I found num2words api in res_currency.py in Base/Modules but I spend two days researching how to connect and nothing. What I have to inherite and how and also what to put in invoice document qweb?
I made module like this:
from num2words import num2words
class account_invoice(models.Model):
_inherit = "account.invoice"
#api.multi
def amount_to_text(self, amount):
self.ensure_one()
def _num2words(number, lang):
try:
return num2words(number, lang=lang).title()
except NotImplementedError:
return num2words(number, lang='en').title()
if num2words is None:
logging.getLogger(__name__).warning("The library 'num2words' is missing, cannot render textual amounts.")
return ""
formatted = "%.{0}f".format(self.decimal_places) % amount
parts = formatted.partition('.')
integer_value = int(parts[0])
fractional_value = int(parts[2] or 0)
lang_code = self.env.context.get('lang') or self.env.user.lang
lang = self.env['res.lang'].search([('code', '=', lang_code)])
amount_words = tools.ustr('{amt_value} {amt_word}').format(
amt_value=_num2words(integer_value, lang=lang.iso_code),
amt_word=self.currency_unit_label,
)
if not self.is_zero(amount - integer_value):
amount_words += ' ' + _('and') + tools.ustr(' {amt_value} {amt_word}').format(
amt_value=_num2words(fractional_value, lang=lang.iso_code),
amt_word=self.currency_subunit_label,
)
return amount_words
Got error like this:
Error to render compiling AST
AttributeError: 'NoneType' object has no attribute 'currency_id'
Template: account.report_invoice_document_with_payments
Path: /templates/t/t/div/p[1]/span
Node: <span t-if="doc.currency_id" t-esc="doc.currency_id.amount_to_text(doc.amount_total)"/>
In QWeb I put this:
<span t-if="doc.currency_id" t-esc="doc.currency_id.amount_to_text(doc.amount_total)"/>
Thank you in advance!
In your case "currency_id" is a Many2one field. The 'res.currency' model does not contain the class 'amount_to_text' function.
You have written amount_to_text function in 'account.invoice' model. So change your like this,
<span t-if="doc.currency_id" t-esc="doc.amount_to_text(doc.amount_total)"/>
OR(if you don't have currency_id field in your object)
<span t-if="doc.amount_to_text" t-esc="doc.amount_to_text(doc.amount_total)"/>
Please use the below code
<span t-if="o.currency_id" t-esc="o.amount_to_text(o.amount_total)"/>
You are getting the error because in the base report they are using o instead of doc. please see the below part of code from base.
<t t-foreach="docs" t-as="o">
So try to use o instead of doc
Is there a way to display the label we put on a field in a qweb reports?
For example
In my .py
findings = fields.Text(string="Findings")
And in my .xml
<t t-esc="findings" /> <!-- only shows the value -->
Can we also get the label in qweb?
You can not get the label of the field.
Instead you can add html tag to show the label
Ex:
<p>Your Label <t t-esc="findings" /> </p>
or
<span> Some Text <t t-esc="findings" /> </span>
You can get field description (label) using a function but I encourage you to display labels as they did in odoo invoice reports.
To get date_invoice label:
def get_field_label(self, model_name, field_name):
ir_model_obj = self.env['ir.model']
ir_model_fields_obj = self.env['ir.model.fields']
model_id = ir_model_obj.search([('model', '=', model_name)], limit=1)
field_id = ir_model_fields_obj.search([('name', '=', field_name), ('model_id', '=', model_id.id)], limit=1)
return field_id.field_description
I would like to print some product barcodes with the custom configuration.
Now, the problem is, I have created the wizard but when I click the print button there is no data is transferred to the report.
class BarcodeConfig(models.Model):
_name = 'report.barcode.print'
#api.model
def _default_product_line(self):
active_ids = self._context.get('active_ids', [])
products = self.env['product.product'].browse(active_ids)
return [(0, 0, {'product_id': x.id, 'qty': 1}) for x in products]
product_line = fields.One2many('product.print.wizard', 'barcode_id', string="Products",
default=_default_product_line)
#api.multi
def print_report(self):
data = self.read()[0]
ids = [x.product_id.id for x in self.product_line]
config = self.env['barcode.config'].get_values()
data.update({
'config': config
})
datas = {'ids': ids,
'form': data
}
return self.env.ref('odoo_barcode.barcode_report').report_action(self,data=datas)
In the above code, I had ids as well for product.product model.
<template id="report_barcode_temp">
<t t-call="web.html_container">
<t t-call="web.internal_layout">
<div class="page">
<h2>Report title</h2>
<strong t-esc="docs"/>
<strong t-esc="doc_ids"/>
<span t-esc="data"/>
<t t-foreach="docs" t-as="o">
<span t-esc="o"/>
<p>This object's name is
<span t-field="o.name"/>
</p>
</t>
</div>
</t>
</t>
In the above code, I'm just trying to print what the data's I've, but I've nothing in docs.
<strong t-esc="docs"/>
this line print product.product model as well. but ids not here, That's the problem I have.
Can anyone help me to tell why this happens? Or is there any other way to achieve this?
I have solved this by get_report_values method.
class classname(models.AbstractModel):
_name = 'report.modulename.templatename'
#api.model
def get_report_values(self, docids, data=None):
# docids: pass from the wizard print button.
records = self.env[objectname].browse(docids)
return {
'doc_ids': docids,
'doc_model': objectname,
'docs': records,
'data': data,}
I am working on editing the survey module in odoo.
When I answer a survey which is composed of pages and then click on submit survey, it calculates the whole score of the survey and displays it. What I want is that it calculates the score of each page and display it when I click on submit survey for example:
It displays: Your score is: 200 points.
And I want it to display: Score of first page : 20 points, Second page: 50 points and so on...
Here is the code that I want to change but I don't know how should I change this function.
questionnaire.py (survey.py) : class survey_user_input
class survey_user_input(osv.Model):
''' Metadata for a set of one user's answers to a particular survey '''
_name = "questionnaire.user_input"
_rec_name = 'date_create'
_description = 'Survey User Input'
def _quizz_get_score(self, cr, uid, ids, name, args, context=None):
ret = dict()
for user_input in self.browse(cr, uid, ids, context=context):
ret[user_input.id] = sum([uil.quizz_mark for uil in user_input.user_input_line_ids] or [0.0])
return ret
_columns = {
'survey_id': fields.many2one('questionnaire.questionnaire', 'Questionnaire', required=True,
readonly=1, ondelete='restrict'),
'date_create': fields.datetime('Date de creation', required=True,
readonly=1, copy=False),
'deadline': fields.datetime("Date limite",
oldname="date_deadline"),
'type': fields.selection([('manually', 'Manuellement'), ('link', 'Lien')],
'Type de reponse', required=1, readonly=1,
oldname="response_type"),
'state': fields.selection([('new', 'Pas encore commence'),
('skip', 'Partiellement acheve'),
('done', 'Termine')],
'Statut',
readonly=True),
'test_entry': fields.boolean('Entree de test', readonly=1),
'token': fields.char("Piece d'identite", readonly=1, required=1, copy=False),
# Optional Identification data
'partner_id': fields.many2one('res.partner', 'Partenaire', readonly=1),
'email': fields.char("E-mail", readonly=1),
# Displaying data
'last_displayed_page_id': fields.many2one('questionnaire.page',
'Derniere page affichee'),
# The answers !
'user_input_line_ids': fields.one2many('questionnaire.user_input_line',
'user_input_id', 'Reponses', copy=True),
# URLs used to display the answers
'result_url': fields.related('survey_id', 'result_url', type='char',
string="Lien public aux resultats du sondage"),
'print_url': fields.related('survey_id', 'print_url', type='char',
string="Lien public au sondage vide"),
'quizz_score': fields.function(_quizz_get_score, type="float", string="Score pour le quiz", store=True)
}
_defaults = {
'date_create': fields.datetime.now,
'type': 'manually',
'state': 'new',
'token': lambda s, cr, uid, c: uuid.uuid4().__str__(),
'quizz_score': 0.0,
}
questionnaire.py (survey.py) : class survey_user_input_line
_name = 'questionnaire.user_input_line'
_description = 'Survey User Input Line'
_rec_name = 'date_create'
_columns = {
'user_input_id': fields.many2one('questionnaire.user_input', 'Entree de l\'utilisateur',
ondelete='cascade', required=1),
'question_id': fields.many2one('questionnaire.question', 'Question',
ondelete='restrict', required=1),
'page_id': fields.related('question_id', 'page_id', type='many2one',
relation='questionnaire.page', string="Page"),
'survey_id': fields.related('user_input_id', 'survey_id',
type="many2one", relation="questionnaire.questionnaire",
string='Questionnaire', store=True),
'date_create': fields.datetime('Date de creation', required=1),
'skipped': fields.boolean('Ignore'),
'answer_type': fields.selection([('text', 'Texte'),
('number', 'Nombre'),
('date', 'Date'),
('free_text', 'Texte Libre'),
('suggestion', 'Suggestion')],
'Type de reponse'),
'value_text': fields.char("Reponse texte"),
'value_number': fields.float("Reponse numerique"),
'value_date': fields.datetime("Reponse date"),
'value_free_text': fields.text("Reponse texte libre"),
'value_suggested': fields.many2one('questionnaire.label', "Reponse suggeree"),
'value_suggested_row': fields.many2one('questionnaire.label', "Reponse en ligne"),
'quizz_mark': fields.float("Score donne pour ce choix")
}
survey_templates.xml
<!-- "Thank you" message when the survey is completed -->
<template id="sfinished" name="Survey Finished">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<t t-call="questionnaire.back" />
<div class="jumbotron mt32">
<h1>Thank you!</h1>
<div t-field="questionnaire.thank_you_message" class="oe_no_empty" />
<div> You scored <t t-esc="user_input.quizz_score" /> points.</div>
<div>If you want you can <a t-att-href="'/questionnaire/print/%s/%s' % (slug(questionnaire), token)">review your answers</a>.</div>
</div>
</div>
</div>
</t>
</template>
One alternative way is to use pure qweb rather than function field; like this:
<!-- First finding which page is related to the survey. This is a bit odd but I couldn't find any other way!! -->
<t t-set="pages" t-value="dict((l.id, l.page_id.id) for l in user_input.user_input_line_ids).values()" />
<!-- Then print the score per each page -->
<t t-foreach='pages' t-as='p'>
<t t-set="page_score" t-value="sum([(uil.quizz_mark or 0.0) if uil.page_id.id == p else 0.0 for uil in user_input.user_input_line_ids])" />
<div> You scored <t t-esc="page_score" /> points in page <t t-esc="p" />.</div>
</t>
I have not tested this code but logically it seems to work fine.
Thank you so much #MICROCOM .. The line that display the score for each page is diplayed more than once ..
The result Of The code - 1
So i added a condition to just display the score of a certain page once (I don't know if it's correct but it works :p ) .. Here is the code :
<!-- First finding which page is related to the survey. This is a bit odd but I couldn't find any other way!! -->
<t t-set="pages" t-value="dict((l.id, l.page_id.title) for l in user_input.user_input_line_ids).values()" />
<!-- Then print the score per each page -->
<t t-set="previous" t-value="void" />
<t t-foreach='pages' t-as='p'>
<t t-if="p != previous">
<t t-set="page_score" t-value="sum([(uil.quizz_mark or 0.0) if uil.page_id.title == p else 0.0 for uil in user_input.user_input_line_ids])" />
<div> You scored <t t-esc="page_score" /> points in page <t t-esc="p" />.</div>
</t>
<t t-set="previous" t-value="p" />
</t>
The result Of The code - 2
Thank you so much for your help #MICROCOM ^^