Lift - Binding list of values to template - scala

Here is my template -
<div class="lift:Admin.showInvitees">
<tr class="success"> <!-- "success" "error" -->
<td><invitee:name></invitee:name></td>
<td><invitee:description></invitee:description></td>
<td><invitee:status></invitee:status></td>
<td></td>
</tr>
</div>
and here is the snippet -
class Admin {
def showInvitees(in: NodeSeq): NodeSeq = {
val invitees = Invitation.allInvitations
invitees.flatMap{invitee => bind("invitee", in, "name" -> invitee.name.is, "status" -> invitee.status.is, "description" -> invitee.description.is)}
}
}
I checked this question and used the solution. But it's not working for me. Values are not getting bound at all. This is what I get as output -
<tr class="success">
<td><invitee:name></invitee:name></td>
<td><invitee:description></invitee:description></td>
<td><invitee:status></invitee:status></td>
</tr>
Need help binding a list of values to template.
After the first answer I tried this as well -
def showInvitees(in: NodeSeq): NodeSeq = {
val invitees = Invitation.allInvitations
(".invitees" #> invitees.map{ inv =>
".invitee-name" #> inv.name.is &
".invitee-description" #> inv.description.is &
".invitee-status" #> inv.status.is
})(in)
}
Even this is not working-
Template -
<div class="lift:Admin.showInvitees">
<tr class="invitees success"> <!-- "success" "error" -->
<td><span class="invitee-name"></span></td>
<td><span class="invitee-description"></span></td>
<td><span class="invitee-status"></span> </td>
<td></td>
</tr>
</div>

This is the old syntax for binding values. Try the new one:
// snippet
class Admin {
def showInvitees = {
case class Invitee(name: String, descr: String, status: String)
val invitees = List(Invitee("Alex", "for cookies", "ok"), Invitee("Bob", "for beer", "kicked out"))
".invitee" #> invitees.map { i =>
".invitee-name" #> i.name.is &
".invitee-descr" #> i.description.is &
".invitee-status" #> i.status.is
}
}
}
// html
<div class="Admin.showInvitees">
<table>
<tr class="invitee success">
<td><span class="invitee-name"></span></td>
<td><span class="invitee-descr"></span></td>
<td><span class="invitee-status"></span></td>
</tr>
</table>
</div>
// result
<table>
<tbody><tr class="invitee success">
<td>Alex</td>
<td>for cookies</td>
<td>ok</td>
</tr><tr class="invitee success">
<td>Bob</td>
<td>for beer</td>
<td>kicked out</td>
</tr>
</tbody></table>

Related

invoice report - display discount in Line invoice - Odoo 12 - Qweb

I am making a report for the invoice line, I have purchased a module in the third-party odoo store and it performs its function well.
But I can't see the discount on the invoice line.
I think this is because the module prevents me, but I already have no developer support.
What I need is that the discount (price list) can be seen on the invoice line.
What table or what element of the invoice line discount?
I leave you the code that I have in the report
''''
<tbody class="invoice_tbody">
<tr t-foreach="invoice_lines[0]" t-as="line">
<td><b><span t-esc="line['client_ref']"/></b>
<span t-esc="line['description']"/></td>
<td class="text-right">
<span t-esc="line['qty']"/>
</td>
<td class="text-right">
<span t-esc="line['price_unit']"/>
</td>
<td t-if="display_discount" class="text-right">
</td>
<td class="text-right" id="subtotal">
<t t-if="line['price_subtotal']">
<span t-esc = "line ['price_subtotal']" t-options = "{& quot; widget & quot ;: & quot; monetario & quot ;, & quot; display_currency & quot ;: o.currency_id}" /> </t>
</td>
</tr>
<tr t-foreach = "range (max (5-len (o.invoice_line_ids), 0))" t-as = "l">
<td t-translation = "off"> & amp; nbsp; </td>
<td class = "hidden" />
<td />
<td />
<td t-if = "display_discount" />
<td />
<td />
</tr>
</tbody>
</t>
'''
Yes, this parameter is in the report
"view / report_invoice_document"
But the report that I try to modify is this
report_invoice_document_inherit
<?xml version="1.0"?>
<data inherit_id="account.report_invoice_document">
<xpath expr="//table[#name='invoice_line_table']/tbody" position="replace">
<t t-if="res_company.is_group_by_so">
<t t-set="invoice_lines" t-value="o.get_invoice_lines()"/>
<tbody class="invoice_tbody">
<tr t-foreach="invoice_lines[0]" t-as="line">
<td><b><span t-esc="line['client_ref']"/></b>
<span t-esc="line['description']"/></td>
<!-- <td class="hidden"><span t-esc="line['client_ref']"/></td> -->
<td class="text-right">
<span t-esc="line['qty']"/>
<!-- <span t-field="l.uom_id" groups="product.group_uom"/> -->
</td>
<td class="text-right">
<span t-esc="line['price_unit']"/>
</td>
</td>
<td t-if="display_discount" class="text-right">
<!-- <span t-esc="line['price_unit']"/> -->
</td>
<td class="text-right" id="subtotal">
<t t-if="line['price_subtotal']">
<span t-esc="line['price_subtotal']" t-options="{"widget": "monetary", "display_currency": o.currency_id}"/></t>
</td>
</tr>
<tr t-foreach="range(max(5-len(o.invoice_line_ids),0))" t-as="l">
<td t-translation="off">&nbsp;</td>
<td class="hidden"/>
<td/>
<td/>
<td t-if="display_discount"/>
<td/>
<td/>
</tr>
</tbody>
</t>
<t t-else="">
<tbody class="invoice_tbody">
<tr t-foreach="o.invoice_line_ids" t-as="l">
<td><span t-field="l.name"/></td>
<td class="hidden"><span t-field="l.origin"/></td>
<td class="text-right">
<span t-field="l.quantity"/>
<span t-field="l.uom_id" groups="product.group_uom"/>
</td>
<td class="text-right">
<span t-field="l.price_unit"/>
</td>
<td t-if="display_discount" class="text-right">
<span t-field="l.discount"/>
</td>
<td class="text-right">
<span t-esc="', '.join(map(lambda x: (x.description or x.name), l.invoice_line_tax_ids))"/>
</td>
<td class="text-right" id="subtotal">
<span t-field="l.price_subtotal" t-options="{"widget": "monetary", "display_currency": o.currency_id}"/>
</td>
</tr>
<tr t-foreach="range(max(5-len(o.invoice_line_ids),0))" t-as="l">
<td t-translation="off">&nbsp;</td>
<td class="hidden"/>
<td/>
<td/>
<td t-if="display_discount"/>
<td/>
<td/>
</tr>
</tbody>
</t>
</xpath>
</data>
I have tried to modify the second report, and put and have looked at the python code in case something
invoice_report_grouped_by \ report \ account_invoice.py
# -*- coding: utf-8 -*-
from odoo import api, models
from datetime import datetime
class AccountInvoice(models.Model):
_inherit = "account.invoice"
def get_notation_amt(self, amt):
'''This method help us to return the value of the product pricing'''
amount = str(amt).split('.')
if len(amount) == 2:
amount = amount[0] + "," + amount[1]
return amount
return amt
#api.multi
def get_product_invoice_lines(self, client_ref=False):
'''This method helps to get the data for the following Invoice Line.'''
product_invoices = []
client_order_ref = []
for line in self.invoice_line_ids:
sale_line = (False, line)
if line.sale_line_ids:
sale_line = (line.sale_line_ids[0].order_id, line)
client_order_ref.append(sale_line)
if client_order_ref:
for ref in client_order_ref:
if (client_ref == ref[0]):
product_invoices.append({'price_subtotal': ref[1].price_unit * ref[1].quantity,
'default_code': ref[1].product_id.default_code,
'client_ref': False,
'discount': ref[1].discount,
'taxes': ",".join(map(lambda x: (x.description or x.name), ref[1].invoice_line_tax_ids)),
'description': ref[1].name,
'qty': self.get_notation_amt(ref[1].quantity),
'price_unit': self.get_notation_amt("{0:.3f}".format(ref[1].price_unit)),
})
else:
for line in self.invoice_line_ids:
product_invoices.append({'price_subtotal': line.price_unit * line.quantity,
'default_code': line.product_id.default_code,
'client_ref': False,
'discount': line.discount,
'taxes': ",".join(map(lambda x: (x.description or x.name), ref[1].invoice_line_tax_ids)),
'description': line.name,
'qty': self.get_notation_amt(line.quantity),
'price_unit': self.get_notation_amt("{0:.3f}".format(line.price_unit)),
})
return product_invoices
#api.multi
def get_invoice_lines(self):
'''This method help to get the invoice line group by Sale order'''
vals = []
sale_order_lines = []
false_sale_order_lines = []
for line in self.invoice_line_ids:
sale_line = False
if line.sale_line_ids:
sale_line = line.sale_line_ids[0].order_id
if sale_line:
sale_order_lines.append(sale_line)
else:
false_sale_order_lines.append(sale_line)
sale_order_lines = list(set(sale_order_lines))
false_sale_order_lines = list(set(false_sale_order_lines))
for sale_order in sale_order_lines:
if sale_order and self.origin:
confirmation_date = str(
sale_order.confirmation_date, '%d-%m-%Y %H:%M:%S').strftime('%d/%m/%Y')
client_ref = sale_order.name + ' - ' + confirmation_date
if sale_order.client_order_ref:
client_ref = client_ref + ' - ' + sale_order.client_order_ref
vals.append({'price_subtotal': False, 'default_code': False,
'client_ref': client_ref, 'description': False,
'qty': False, 'price_unit': False, 'taxes': False, 'discount': False})
vals.extend(self.get_product_invoice_lines(client_ref=sale_order))
# for sort false sale order, display manually invoice line at last
for so in false_sale_order_lines:
vals.extend(self.get_product_invoice_lines(client_ref=so))
return [vals, len(vals)]
You can see the default report here:
https://github.com/odoo/odoo/blob/06f9baae968674547cb2592b1c22147bfb2e8ba9/addons/account/views/report_invoice.xml#L49
<t t-set="display_discount" t-value="any([l.discount for l in o.invoice_line_ids])"/>
This means that if any line has a discount, it should display it.
I think there are two options to disable it. One is to remove that line from the report, or the second option is to set display_discount to false.
Knowing the module that breaks your report, the problem should be easy to find.
But the exact reason is hard to tell without seeing your module.

How to use pattern matching in Binding.scala?

I have the following model:
case class CarBinding(ownerId: Var[String], specs: Var[Option[Specs]])
Specs is a trait and has the following concrete types:
trait Specs {
def name: String
}
case class SportsCarSpecs(name: String, details: Details) extends Specs
In my Scala.js app, I now want to create a table and list all the entries:
#dom
def buildTable(): Binding[BindingSeq[Node]] = {
val data = Vars.empty[CarBinding]
/* Initial population. */
// Some code...
<br/>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th class="col-md-1">
<small>Owner ID</small>
</th>
<th class="col-md-1">
<small>Specs</small>
</th>
</tr>
</thead>
<tbody>
{for (entry <- data) yield {
<tr>
<td>
<small>
{entry.ownerId.bind}
</small>
</td>
<td>
<small>
{entry.specs.bind match {
case Some(SportsCarSpecs(name, details)) => {name} <span>{details.ps}</span>
case _ => -
}}
</small>
</td>
</tr>
}}
</tbody>
</table>
</div>
}
However, I get the following error:
';' expected but $XMLSTART$< found.
[error] case Some(SportsCarSpecs(name, details)) => {name} <span>{details.ps}</span>
What am I doing wrong?
This:
entry.specs.bind match {
case Some(SportsCarSpecs(name, details)) => {name} <span>{details.ps}</span>
case _ => -
}
isn't a valid expression, so you can't interpolate it in the XML literal. If you had complete XML expressions in both branches, it should work. So the easiest fix I can see is to pull <small> inside:
<td>
{entry.specs.bind match {
case Some(SportsCarSpecs(name, details)) => <small>{name} <span>{details.ps}</span></small>
case _ => <small>-</small>
}}
</td>

Lift framework: Not able to render table rows using comet properly

In my web page I have a text box in which user enters an item name that would be sent to server asynchronously, that message would be sent to CometActor then further it adds additional information to it and in the render method it tries to append a new row to existing table on the page asynchronously. Whenever I add an item always new row is getting placed on top of table rather than as table row, after that if I press refresh it is getting placed properly in the table. Here is
<table cellpadding="0" cellspacing="0" border="1" class="display" id="example">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Time</th>
</tr>
</thead>
<tbody class="lift:comet?type=ProvisionComet">
<tr id="tr_content">
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
LiftActor object
object ItemsServer extends LiftActor with ListenerManager {
private var items = Vector[Item]()
private lazy val date: Box[Date] = DependencyFactory.inject[Date] // inject the date
def createUpdate = items
override def lowPriority = {
case s: String => items :+= new Item(items.length + 1, s, date.map(_.toString)); updateListeners()
case _ => None
}
}
Comet Actor
class ItemComet extends CometActor with CometListener {
private var items = Vector[Item]()
def registerWith = ItemsServer
override def lowPriority = {
case v: Vector[Item] => items = v; reRender()
}
def render = "#tr_content *" #> {
items.map(i => {
<td>{i.sNum}</td>
<td>{i.itemName}</td>
<td>{i.updatedTime.toString}</td>
})
}
The result before refresh is
The result after refresh
How to get the correct result without refreshing?
render method is the place where I am adding rows
Try moving the class attribute from tbody to table:
<table class="lift:comet?type=ProvisionComet" cellpadding="0" cellspacing="0" border="1" class="display" id="example">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Time</th>
</tr>
</thead>
<tbody >
<tr id="tr_content">
<td></td>
<td></td>
<td></td>
</tr>
</tbody>

Scala Lift: how to get ajaxRadio parameters

I have ajaxRadio ineach row of a table.
when this Radio is selected, I want scala function to get two parameters:
1st one is the selected radio, 2nd one is the data key of the row.
my source is as follows:
val radioList = List("wideArea", "oldArea","newArea")
def liftForm(xhtml: NodeSeq): NodeSeq = {
var areaList = newOrderList.map(values =>{
<li id={values(1)} >
<table>
<thead></thead>
<tbody>
<tr class = "real">
<td class="listImage">
<img class="areaImage" src={values(6)}/>
</td>
<td style="vertical-align:top;">
<tr><p class="areaName">{values(4)}</p></tr>
<tr><p class="areaComment">{values(5)}</p></tr>
</td>
<td class="listCheck" >
{ajaxButton(S.?("delete"), () => doDelete(values(1)), "class" -> "button delete")}
</td>
</tr>
<tr>
<td></td>
<td>
{
val it = ajaxRadio[String](radioList,Box.legacyNullTest(values(2)),doRadioChange _).toForm.grouped(4)
for(i <- it)yield(<tr>{i.flatMap(y => <td> {y} </td>)}</tr>)
}
</td>
</tr>
</tbody>
</table>
</li>})
bind("list",xhtml,"areaList" -> <ul>{areaList}</ul>)
By doRadioChange _, I can only get selected radio. How can I get the the 2nd parameter: data key of the row. ie values(1)?
Your functions can close over all of the local state at that point in the function. You should be able to replace doRadioChange _ with:
doRadioChange(_, values(1))
Assuming, of course, that doRadioChange accepts the proper parameters.

Variable within scala template in play framework

I need to be able to declare variables and after some markup later I
need to reference them. In order to accomplish this, this is
simplified version of my scala template:
#(map1:
java.util.LinkedHashMap[String,java.util.LinkedHashMap[String,Object]])
#import scala.collection.JavaConversions._
#import play.Logger
#for( (key,value) <- map1) {
<div>
#{
val rmap = Foo.someMethod(value)
val baz = rmap.getOrElse("baz", null)
<table border="0" cellpadding="0" cellspacing="0" >
<tbody>
<tr>
<td rowspan="3">
<div class="bar">
#baz
</div>
</td>
</tr>
</tbody>
</table>
}
</div>
}
Is above valid scala template and if not how can I declare baz and
reference it later in the markup?
I am using 1.2.2RC2 and scala 0.9.1
I was curious so did some digging. See https://groups.google.com/forum/#!topic/play-framework/Mo8hl5I0tBQ - there is no way at the moment, but an interesting work-around is shown. Define utils/Let.scala:
package utils
Object Let {
def let[A,B](a:A)(f:A=>B):B = f(a)
}
and then
#import utils.Let._
#let(2+3){ answer =>
#answer <hr> #answer
}
It's a very functional way of handling it, but then, what'd you expect in Scala :)
You can just use a for comprehension:
#for( (key,value) <- map1;
rmap = Foo.someMethod(value);
baz = rmap.getOrElse("baz", null)
) {
<div>
<table border="0" cellpadding="0" cellspacing="0" >
<tbody>
<tr>
<td rowspan="3">
<div class="bar">
#baz
</div>
</td>
</tr>
</tbody>
</table>
</div>
}
... and if you don't have anything you need to loop over, you can just say #for(i <- List(1); <declare variables>){<html here>}