اقدامات

اکشن‌ها رفتار سیستم را در پاسخ به اقدامات کاربر تعریف می‌کنند: ورود به سیستم، دکمهٔ اکشن، انتخاب یک فاکتور، ...

اکشن‌ها می‌توانند در پایگاه‌داده ذخیره شوند یا مستقیماً به‌صورت دیکشنری در، برای مثال، متدهای button بازگردانده شوند. همهٔ اکشن‌ها دو ویژگی الزامی مشترک دارند:

type

دستهٔ اکشن فعلی؛ تعیین می‌کند چه فیلدهایی ممکن است استفاده شوند و اکشن چگونه تفسیر شود

name

توضیح کوتاه و قابل‌خواندن توسط کاربر برای اکشن؛ ممکن است در رابط کاربری کلاینت نمایش داده شود

یک کلاینت می‌تواند اکشن‌ها را در ۴ فرم دریافت کند:

  • False

    اگر هر دیالوگ اکشنی در حال حاضر باز است، آن را ببندید

  • یک رشته

    اگر یک client action مطابقت داشته باشد، به‌عنوان tag اکشن کلاینت تفسیر شود، در غیر این صورت به‌عنوان یک عدد در نظر گرفته شود

  • یک عدد

    رکورد اکشن متناظر را از پایگاه‌داده می‌خواند؛ ممکن است یک شناسهٔ پایگاه‌داده یا یک external id باشد

  • یک دیکشنری

    به‌عنوان توصیف‌گر (descriptor) اکشن کلاینت در نظر گرفته شود و اجرا گردد

بایندینگ‌ها

علاوه بر دو ویژگی الزامی، همهٔ اکشن‌ها ویژگی‌های اختیاری مشترکی نیز دارند که برای نمایش یک اکشن در منوی متنی (contextual menu) یک مدل دلخواه استفاده می‌شوند:

binding_model_id

مشخص می‌کند که اکشن به کدام مدل bind شده است

توجه

برای Server Actions، از model_id استفاده کنید.

binding_type

نوع binding را مشخص می‌کند، که اساساً تعیین می‌کند اکشن زیر کدام منوی متنی ظاهر شود

action (پیش‌فرض)

مشخص می‌کند که اکشن در منوی متنی Action مدل bind‌شده ظاهر خواهد شد.

report

مشخص می‌کند که اکشن در منوی متنی Print مدل bind‌شده ظاهر خواهد شد.

binding_view_types

فهرستی از انواع نما، جداشده با ویرگول، که اکشن برای آن‌ها در منوی متنی ظاهر می‌شود، اساساً "list" و/یا "form". مقدار پیش‌فرض list,form است (هم list و هم form)

اکشن‌های پنجره (ir.actions.act_window)

رایج‌ترین نوع اکشن، که برای نمایش بصری یک مدل از طریق views استفاده می‌شود: یک window action مجموعه‌ای از انواع نما (و احتمالاً نماهای خاص) را برای یک مدل (و احتمالاً رکورد خاصی از مدل) تعریف می‌کند.

فیلدهای آن عبارت‌اند از:

res_model

مدلی که نماها برای آن نمایش داده می‌شوند

views

فهرستی از جفت‌های (view_id, view_type). عنصر دوم هر جفت دستهٔ نما است (list، form، graph و غیره) و عنصر اول یک شناسهٔ پایگاه‌داده اختیاری است (یا False). اگر هیچ شناسه‌ای ارائه نشده باشد، کلاینت باید نمای پیش‌فرض نوع مشخص‌شده را برای مدل درخواست‌شده دریافت کند (این کار به‌صورت خودکار توسط fields_view_get() انجام می‌شود). نوع اول در فهرست، نوع نمای پیش‌فرض است و هنگام اجرای action به‌صورت پیش‌فرض باز می‌شود. هر نوع نما باید حداکثر یک بار در فهرست حضور داشته باشد

res_id (اختیاری)

اگر نمای پیش‌فرض form باشد، رکوردی را که باید بارگذاری شود مشخص می‌کند (در غیر این صورت باید رکورد جدیدی ایجاد شود)

search_view_id (اختیاری)

جفت (id, name)؛ id شناسهٔ پایگاه‌داده‌ٔ یک نمای جستجوی خاص برای بارگذاری برای این action است. به‌صورت پیش‌فرض نمای جستجوی پیش‌فرض مدل دریافت می‌شود

target (اختیاری)

اینکه نماها باید در ناحیهٔ محتوای اصلی (current)، در حالت تمام‌صفحه (fullscreen) یا در یک پنجرهٔ بازشو (new) باز شوند. برای پاک کردن مسیر راهبری، از main به جای current استفاده کنید. به‌صورت پیش‌فرض current.

context (اختیاری)

داده‌های context اضافی برای ارسال به نماها

domain (اختیاری)

دامنهٔ فیلترسازی که به‌صورت ضمنی به همهٔ کوئری‌های جستجوی نماها افزوده می‌شود

limit (اختیاری)

تعداد رکوردهایی که به‌صورت پیش‌فرض در فهرست‌ها نمایش داده می‌شوند. به‌صورت پیش‌فرض ۸۰ در وب‌کلاینت

برای مثال، برای باز کردن مشتریان (شریک با پرچم customer تنظیم‌شده) با نماهای فهرست و فرم:

{
    "type": "ir.actions.act_window",
    "res_model": "res.partner",
    "views": [[False, "list"], [False, "form"]],
    "domain": [["customer", "=", true]],
}

یا برای باز کردن نمای فرم یک محصول مشخص (به‌صورت جداگانه دریافت‌شده) در یک پنجرهٔ بازشوی جدید:

{
    "type": "ir.actions.act_window",
    "res_model": "product.product",
    "views": [[False, "form"]],
    "res_id": a_product_id,
    "target": "new",
}

اکشن‌های پنجره‌ای موجود در پایگاه‌داده چند فیلد متفاوت دارند که باید توسط کلاینت‌ها نادیده گرفته شوند و بیشتر برای ترکیب فهرست views استفاده می‌شوند:

view_mode (پیش‌فرض= list,form )

فهرست انواع نماها به‌صورت رشته‌ای جداشده با کاما (/!\ بدون فاصله /!\). همهٔ این انواع در فهرست views تولیدشده حضور خواهند داشت (حداقل با view_id برابر False)

view_ids

M2M1 به اشیای نما، محتوای اولیهٔ views را تعریف می‌کند

توجه

نماهای Act_window را می‌توان به‌صورت تمیز از طریق ir.actions.act_window.view نیز تعریف کرد.

اگر قصد دارید چندین نما برای مدل خود مجاز کنید، استفاده از ir.actions.act_window.view به جای view_ids در action ترجیح داده می‌شود

<record model="ir.actions.act_window.view" id="test_action_tree">
   <field name="sequence" eval="1"/>
   <field name="view_mode">list</field>
   <field name="view_id" ref="view_test_tree"/>
   <field name="act_window_id" ref="test_action"/>
</record>
view_id

نمای خاصی که به فهرست views اضافه می‌شود در صورتی که نوع آن بخشی از فهرست view_mode باشد و توسط یکی از نماهای view_ids پر نشده باشد

این‌ها بیشتر هنگام تعریف اکشن‌ها از Data Files استفاده می‌شوند:

<record model="ir.actions.act_window" id="test_action">
    <field name="name">A Test Action</field>
    <field name="res_model">some.model</field>
    <field name="view_mode">graph</field>
    <field name="view_id" ref="my_specific_view"/>
</record>

از نمای "my_specific_view" استفاده خواهد کرد حتی اگر آن نما، نمای پیش‌فرض مدل نباشد.

ترکیب سمت سرور دنبالهٔ views به شرح زیر است:

  • هر (id, type) را از view_ids (مرتب‌شده بر اساس sequence) دریافت کنید

  • اگر view_id تعریف شده باشد و نوع آن قبلاً پر نشده باشد، (id, type) آن را اضافه کنید

  • برای هر نوع پرنشده در view_mode، (False, type) را اضافه کنید

1

از نظر فنی M2M نیست: یک فیلد sequence اضافه می‌کند و ممکن است فقط از یک نوع نما بدون شناسهٔ نما تشکیل شود.

اکشن‌های URL (ir.actions.act_url)

اجازهٔ باز کردن یک URL (وب‌سایت/صفحهٔ وب) را از طریق یک action در Odoo می‌دهد. می‌تواند از طریق دو فیلد سفارشی‌سازی شود:

url

آدرسی که هنگام فعال‌سازی action باز می‌شود

target (پیش‌فرض= new)

مقادیر در دسترس عبارت‌اند از:

  • new: URL را در پنجره/صفحهٔ جدید باز می‌کند

  • self: URL را در پنجره/صفحهٔ جاری باز می‌کند (محتوای فعلی را جایگزین می‌کند)

  • download: به URL دانلود تغییر مسیر می‌دهد

مثال:

{
    "type": "ir.actions.act_url",
    "url": "https://odoo.com",
    "target": "self",
}

این کار بخش محتوای جاری را با صفحهٔ اصلی Odoo جایگزین می‌کند.

اکشن‌های سرور (ir.actions.server)

اجازهٔ راه‌اندازی کد پیچیدهٔ سرور را از هر مکان action معتبر می‌دهد. فقط دو فیلد برای کلاینت‌ها مرتبط هستند:

id

شناسهٔ موجود در پایگاه‌داده‌ٔ action سرور برای اجرا

context (اختیاری)

داده‌های context برای استفاده هنگام اجرای action سرور

رکوردهای موجود در پایگاه‌داده به‌طور قابل توجهی غنی‌تر هستند و می‌توانند تعدادی action خاص یا عمومی را بر اساس state خود انجام دهند. برخی فیلدها (و رفتارهای متناظر) بین حالت‌ها مشترک هستند:

model_id

مدل Odoo که به action متصل است.

state

  • code: کد Python داده‌شده از طریق آرگومان code را اجرا می‌کند.

  • object_create: یک رکورد جدید از مدل crud_model_id بر اساس مشخصات fields_lines ایجاد می‌کند.

  • object_write: رکورد(های) جاری را بر اساس مشخصات fields_lines به‌روزرسانی می‌کند

  • multi: چندین action داده‌شده از طریق آرگومان child_ids را اجرا می‌کند.

فیلدهای حالت

بسته به state آن، رفتار از طریق فیلدهای مختلف تعریف می‌شود. state مربوطه بعد از هر فیلد ذکر شده است.

code (code)

یک قطعه کد Python برای اجرا هنگام فراخوانی action مشخص کنید

<record model="ir.actions.server" id="print_instance">
    <field name="name">Res Partner Server Action</field>
    <field name="model_id" ref="model_res_partner"/>
    <field name="state">code</field>
    <field name="code">
        raise Warning(record.name)
    </field>
</record>

توجه

بخش کد می‌تواند متغیری به نام action تعریف کند که به‌عنوان action بعدی برای اجرا به کلاینت بازگردانده می‌شود:

<record model="ir.actions.server" id="print_instance">
    <field name="name">Res Partner Server Action</field>
    <field name="model_id" ref="model_res_partner"/>
    <field name="state">code</field>
    <field name="code">
        if record.some_condition():
            action = {
                "type": "ir.actions.act_window",
                "view_mode": "form",
                "res_model": record._name,
                "res_id": record.id,
            }
    </field>
</record>

اگر رکورد شرط مشخصی را برآورده کند، از کلاینت می‌خواهد یک فرم برای رکورد باز کند

crud_model_id (create)(الزامی)

مدلی که در آن رکورد جدیدی ایجاد می‌شود

link_field_id (create)

many2one به ir.model.fields، فیلد m2o رکورد جاری را مشخص می‌کند که رکورد تازه ایجاد شده باید روی آن تنظیم شود (مدل‌ها باید مطابقت داشته باشند)

fields_lines (create/write)

فیلدهایی که هنگام ایجاد یا کپی کردن رکورد بازنویسی شوند. One2many با فیلدهای:

col1

ir.model.fields برای تنظیم در مدل مربوطه (crud_model_id برای ایجاد، model_id برای به‌روزرسانی)

value

مقدار فیلد، که از طریق type تفسیر می‌شود

type (value|reference|equation)

اگر value باشد، فیلد value به‌عنوان یک مقدار لیترال (با احتمال تبدیل) تفسیر می‌شود؛ اگر equation باشد، فیلد value به‌عنوان یک عبارت Python تفسیر و ارزیابی می‌شود

child_ids (multi)

چندین زیر-action (ir.actions.server) را برای اجرا در state چندگانه مشخص کنید. اگر خود زیر-action‌ها action برمی‌گردانند، آخرین مورد به‌عنوان action بعدی خود multi به کلاینت بازگردانده می‌شود

context ارزیابی

تعدادی کلید در context ارزیابی اکشن‌های سرور یا پیرامون آن‌ها در دسترس هستند:

  • model شیء مدلی که از طریق model_id به action متصل است

  • record/records رکورد/recordset که action روی آن راه‌اندازی می‌شود، می‌تواند خالی باشد.

  • env محیط Odoo

  • datetime، dateutil، time، timezone ماژول‌های متناظر در Python

  • log: log(message, level='info') تابع لاگ‌گیری برای ثبت اطلاعات اشکال‌زدایی در جدول ir.logging

  • Warning سازندهٔ استثنای Warning

اکشن‌های گزارش (ir.actions.report)

Triggers the printing of a report.

If you define your report through a <record> instead of a <report> tag and want the action to show up in the Print menu of the model's views, you will also need to specify binding_model_id from بایندینگ‌ها. It's not necessary to set binding_type to report, since ir.actions.report will implicitly default to that.

name (mandatory)

used as the file name if print_report_name is not specified. Otherwise, only useful as a mnemonic/description of the report when looking for one in a list of some sort

model (mandatory)

the model your report will be about

report_type (default=qweb-pdf)

either qweb-pdf for PDF reports or qweb-html for HTML

report_name (mandatory)

the name (external id) of the qweb template used to render the report

print_report_name

python expression defining the name of the report.

groups_id

Many2many field to the groups allowed to view/use the current report

multi

if set to True, the action will not be displayed on a form view.

paperformat_id

Many2one field to the paper format you wish to use for this report (if not specified, the company format will be used)

attachment_use

if set to True, the report is only generated once the first time it is requested, and re-printed from the stored report afterwards instead of being re-generated every time.

Can be used for reports which must only be generated once (e.g. for legal reasons)

attachment

python expression that defines the name of the report; the record is accessible as the variable object

Client Actions (ir.actions.client)

Triggers an action implemented entirely in the client.

tag

the client-side identifier of the action, an arbitrary string which the client should know how to react to

params (optional)

a Python dictionary of additional data to send to the client, alongside the client action tag

target (اختیاری)

whether the client action should be open in the main content area (current), in full screen mode (fullscreen) or in a dialog/popup (new). Use main instead of current to clear the breadcrumbs. Defaults to current.

{
    "type": "ir.actions.client",
    "tag": "pos.ui"
}

tells the client to start the Point of Sale interface, the server has no idea how the POS interface works.

همچنین ببینید

Scheduled Actions (ir.cron)

Actions triggered automatically on a predefined frequency.

name

Name of the scheduled action (Mainly used in log display)

interval_number

Number of interval_type uom between two executions of the action

interval_type

Unit of measure of frequency interval (minutes, hours, days, weeks, months)

model_id

Model on which this action will be called

code

Code content of the action. Can be a simple call to the model's method :

model.<method_name>()
nextcall

Next planned execution date of this action (date/time format)

priority

Priority of the action when executing multiple actions at the same time

Writing cron functions

When running a scheduled action, it's recommended that you try to batch the progress in order to avoid blocking a worker for a long period of time and possibly run into timeout exceptions. Therefore, you should split the processing so that each call makes progress on some of the work to be done.

When writing such a function, you should focus on processing a single batch. A batch should process one or many records and should generally take no more than a few seconds.

Work is committed by the framework after each batch. The framework will call the function as many times as necessary to process the remaining work. Do not reschedule yourself the job.

def _cron_do_something(self, *, limit=300):  # limit: allows for tweaking
    domain = [('state', '=', 'ready')]
    records = self.search(domain, limit=limit)
    records.do_something()
    # notify progression
    remaining = 0 if len(records) == limit else self.search_count(domain)
    self.env['ir.cron']._commit_progress(len(records), remaining=remaining)

In some cases, you may want to share resources between multiple batches or manage the loop yourself to handle exceptions. In this case, you should inform the scheduler of the progress of your work by calling IrCron._commit_progress() and checking the result. The progress function returns the number of seconds remaining for the call; if it is 0, you must return as soon as possible.

The following is an example of how to commit after each record that is processed, while keeping the connection open.

def _cron_do_something(self):
    assert self.env.context.get('cron_id'), "Run only inside cron jobs"
    domain = [('state', '=', 'ready')]
    records = self.search(domain)
    self.env['ir.cron']._commit_progress(remaining=len(records))

    with open_some_connection() as conn:
        for record in records:
            # You may have other needs; we do some common stuff here:
            # - lock record (also checks existence)
            # - prefetch: break prefetch in this case, we process one record
            # - filtered_domain: record may have changed
            record = record.try_lock_for_update().filtered_domain(domain)
            if not record:
                continue
            # Processing the batch here...
            try
                record.do_something(conn)
                if not self.env['ir.cron']._commit_progress(1):
                    break
            except Exception:
                # if you handle exceptions, the default stategy is to
                # rollback first the error
                self.env.cr.rollback()
                _logger.warning(...)
                # you may commit some status using _commit_progress

Running cron functions

You should not call cron functions directly. There are two ways to run functions:

Testing of a cron function should be done by calling IrCron.method_direct_trigger() in the registry test mode.

امنیت

To avoid a fair usage of resources among scheduled actions, some security measures ensure the correct functioning of your scheduled actions.

  • If a scheduled action encounters an error or a timeout three consecutive times, it will skip its current execution and be considered as failed.

  • If a scheduled action fails its execution five consecutive times over a period of at least seven days, it will be deactivated and will notify the DB admin.

  • A hard-limit exists for the cron execution at the database level after which the process executing cron jobs is killed.