Script Action
The <action-script>, introduced in v5, can be used to create complex actions using scripting languages.
<action-script
name="create.invoice" (1)
model="com.axelor.sale.db.Order" (2)
>
<script
language="js" (3)
transactional="true" (4)
>
<![CDATA[
var req = $request; (5)
var res = $response; (6)
var so = req.context;
var invoice = new Invoice();
invoice.date = so.confirmDate;
// prepare invoice lines from sale order
//TODO: invoice.invoiceLines = listOf(...);
// if you want to save invoice
//invoice.saleOrder = em.find(Order.class, so.id);
//return $em.persist(invoice);
res.setValue('invoice', invoice);
res.setReadonly('customer', true);
// and so on...
]]>
</script>
</action-script>
| 1 | the name of the action (required) |
| 2 | the name of the context model |
| 3 | scripting language to use (required, currently js and groovy only) |
| 4 | whether the code is transactional |
| 5 | the ActionRequest is available as $request |
| 6 | the ActionResponse is available as $response |
The action-script is nothing but the controller method
dynamically created using a scripting language. The $request and $response variables are nothing
but the ActionRequest and ActionResponse parameters of controller method.
Following variables are available in script execution context:
| Name | Description |
|---|---|
|
the |
|
the |
|
the |
|
instance of |
The action-script can be used for custom models too. Here is an example:
<action-script name="create.hello" model="com.axelor.meta.db.MetaJsonRecord">
<script language="js" transactional="true">
<![CDATA[
var hello = $json.create('hello'); (1)
hello.name = "Hello!!!"; (2)
var world = $json.all('world').by('name', '=', 'World!!!').fetchOne(); (3)
if (world == null) {
world = $json.create('world');
world.name = "World!!!";
world = $json.save(world); (4)
// now we can't update world, as it's converted to real instance
}
hello.world = world; (5)
// return as response values
$response.values = hello;
]]>
</script>
</action-script>
| 1 | create a new empty context for MetaJsonRecord for the hello model |
| 2 | the context allows seamless access to custom field values |
| 3 | find a world model record by field name |
| 4 | record(s) intended for relational field values must be saved manually |
| 5 | set relational value (m2o) |
Using Java types
In js scripts, a bare capitalized name resolves directly to a Java type —
entity and repository classes (by simple name, no import or FQN), plus the common
java.time, java.math and java.util helpers (LocalDate, LocalDateTime,
ZonedDateTime, Instant, BigDecimal, HashMap, ArrayList, Arrays, …).
Static members and constructors are usable directly:
var today = LocalDate.now(); // static method
var amount = new BigDecimal('1.50'); // constructor
var order = new Order(); // entity constructor
var repo = __repo__(Order); // usable as a Class argument
var isOrder = record instanceof Order; // instanceof
For any other class, resolve it explicitly with Java.type():
var UUID = Java.type('java.util.UUID');
var id = UUID.randomUUID().toString();
All type access — bare names as well as Java.type() — is governed by the
scripting policy. Depending on the
configured policy a given class may or may not be accessible; a denied class
fails at resolution, so don’t assume an arbitrary type is reachable.
A resolved type exposes the class’s static members and its constructor,
not the instance methods of java.lang.Class. To reach the java.lang.Class
object — for reflection, or getName() / getSimpleName() — go through .class
(e.g. Order.class.getName()), and use the instanceof operator rather than
Class.isInstance(…). This applies to the js engine; in groovy, a bare
name is the java.lang.Class object and statics, constructors and Class
methods all work on it.
|
See available helper functions in script helper functions documentation.