# Hooks

## Hooks types

**Common**: reusable logic

[**Import**: Allows to import excel files](/dev/configurations/hooks/import-excel-files.md)

[Send Notification (web)](/dev/configurations/hooks/notifications.md)

[Scheduled Jobs](/dev/configurations/hooks/scheduled-jobs.md)

[Generate QR Code](/dev/configurations/hooks/generate-qr-code.md)

## Send Emails

* From: Email  address from where you want to send the email, It is not required if was configured in the application designer
* To: Email address of the destination person
* Subject: Subject of the email (text plain)
* Message: The body of the email can be in HTML format or Text Plain.

{% hint style="info" %}
To know more about the allowed email options please read [nodemailer](https://nodemailer.com/about/) docs
{% endhint %}

```javascript
const sendEmail = require("./utils/mailSender").default;

//...
   const options ={
     from: 'correo@gmail.com',
     to: 'correo@gmail.com',
     subject: 'subject of the email',
     message: '<a>message of the email in HTML format or TEXT plain<a>'
   }
   await sendEmail(options);
```

## [Documentation for Sending Emails with Base64 Attachments (backend, hooks)](/dev/configurations/integrations/sending-emails-with-attachments-in-your-application-frontend.md#documentation-for-sending-emails-with-base64-attachments-backend-hooks)

#### Override email provider settings

If you want to use a different mail provider you can pass that configuration as a second parameter of the sendEmail function

```javascript
const sendEmail = require("./utils/mailSender").default;

//...
   const options ={
     from: 'correo@gmail.com',
     to: 'correo@gmail.com',
     subject: 'subject of the email',
     message: '<a>message of the email in HTML format or TEXT plain<a>'
   }
   
   const mailSenderOptions = {
      host: '',
      port: '',
      secure: true, //true or false
      user: '',
      pass: '',
      emailFrom: '' //optional if you are already using options.from
   }
   await sendEmail(options, mailSenderOptions);
```

## Async Logic

```javascript
const asyncFunctionExample = async (instance) => {
   // implement code here for async functions
}
asyncFunctionExample(instance);
```

## Querying and importing database model

```javascript
//import the model
const modelsapp = require("../modelsapp").default;

const asyncFunctionExample = async (instance) => {
    const personas = await modelsapp.Persona.findAll({
        where: { IglesiaId: '123' },
        limit: 100,
    });
   // implement code here for async functions
}

asyncFunctionExample(instance);
```

{% hint style="info" %}
To see more querying examples you can use any sequelize method: <https://sequelize.org/v4/manual/tutorial/querying.html>
{% endhint %}

## Hooks Errors

This section will show you how to throw hook errors.

The simplest way to throw an error looks like this

```javascript
throw new Error("My error message");
```

### 🔁Redirecting to a different Feature

If you want to allow the user to see a modal with a button that redirects to a new **Feature**, you should throw an exception using the `CodenullError` class with the following parameters:

**✅ Example:**

```js
jsCopyEditconst CodenullError = require("./utils/CodenullError").default;

throw new CodenullError(
  {
    featureId: "6122b2944ee09f001813a6fe", // ID of the Feature to redirect to
    params: [
      {
        type: "hardcoded",   // Type of value (e.g., "hardcoded")
        value: instance.Id,  // Relevant value to pass
        name: "Id"           // Descriptive name of the parameter
      }
    ],
    target: "_blank", //open in a new tab
    okLabel: "Aceptar", //label for ok button
    cancelLabel: "Cancelar", //lable for cancel button
    message: error,          // Error message or object
    type: "navigation"       // Type must be "navigation" to trigger redirection
  },
  "my message"               // Optional message for logs or modal display
);
```

> 💡 `type: "navigation"` is mandatory to trigger the redirect behavior.
>
> The `params` array allows dynamic values to be passed to the destination feature

This is how the error message will look, once the user hit the "Aceptar/Ok" button will be redirected to the new feature

![](/files/-MixV091_uukOTp4U6rm)

{% hint style="warning" %}
This requires the 1.1.9 version or greater
{% endhint %}

## Executing Store Procedure from Hooks

```javascript
//import a database connection
const dbApp = require("../modelsapp/db").default

const ReplicarDatos = async (instance) => {
    //pass a transaction configuration in case you need it
    await dbApp.query(`exec ReplicarDatos '${instance.Id}'`, { transaction: options.transaction })
}
ReplicarDatos(instance);
```

*You can know more about queries here* [*https://sequelize.org/master/manual/raw-queries.html*](https://sequelize.org/master/manual/raw-queries.html)

## Other Import examples

```javascript
const axios = require("axios").default;
const sortBy = require("lodash/sortBy");
```

## Troubleshooting

* Timeout doing database operations on the `afterSave` or any other *after* hook

Solution: Add the transaction to the operation as the second parameter

```javascript
await modelsapp.Usuario.create(data, { transaction: options.transaction });
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://codenull.gitbook.io/dev/configurations/hooks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
