========
on_apply
========

on_apply(self, delta, params, connection)

**domain**: server

**language**: python

**class** :doc:`Item class </refs/server/item_api>`

Description
===========

Write ``on_apply`` event handler when you need to override the standard data saving 
procedure during the execution of the apply method on the
:doc:`client </refs/client/item/m_apply>`
or
:doc:`server <m_apply>`.

See
:doc:`on_apply events </programming/server/on_apply_events>`
to understand how on_apply events are triggered.

The ``on_apply`` event handler has the following parameters:

* ``item`` - a reference to the item,
* ``delta`` - a delta containing item change log (discussed in more detail below),
* ``params`` - the parameters passed to the server by apply method,
* ``connection`` - the connection that will be used to save changes to the database.

The delta parameter contains changes that must be saved in the database. 
By itself, this option is an item's copy, and its dataset is the item's change 
log. The nature of the record change can be obtained by using following methods: 

* ``rec_inserted``
* ``rec_modified`` 
* ``rec_deleted``
  
each of which returns a value of ``True``, if the record is added, modified or 
deleted, respectively. 

If the item has a detail items, delta also has a corresponding detail items, 
storing detail changes. 

.. note::
    Please note that when a record is deleted from an item and this record has 
    detail records, the change log will just keep this deleted record, 
    information about the deleted records of the details is not stored. 
    To add this deleted detail records, call delta's ``update_deleted`` method. 

    You do not need to open delta detail after the cursor has been moved to 
    another record.

Delta dataset fields have an old_value attribute that can be used to get the 
value of a field before changes have been made.


Fields of the delta dataset have an ``old_value`` attribute that can be used to 
get the value of a field before changes have been made.

when the ``on_apply`` event handler is not defined the ``apply_delta`` method
is executed, that generates SQL queries and executes them. After that it
returns the information about the result of processing, that stores the
id's of the new records as well. The client based on this information updates the 
item's change log and values of the primary fields of new records.

When ``on_apply`` event handler returns ``None`` the ``apply_delta`` is executed.

You can make some additional processing of the delta. In the following code, the
a value of the date field is set to the current date before changes are applied 
to the database table.

.. code-block:: py

  import datetime
  
  def on_apply(item, delta, params, connection): 
      for d in delta:
          d.edit()
          d.date.value = datetime.datetime.now()
          d.post()

.. note::
    Please note that changes made this way are not reflected in the item dataset
    on the client. You can use the item client methods
    :doc:`refresh_record </refs/client/item/m_refresh_record>` or
    :doc:`refresh_page </refs/client/item/m_refresh_page>` to display these
    changes.

In the following code, while saving the changes made to the invoices, the 
application as well updates the value of the ``tracks_sold`` field for tracks in 
this invoices. All this is done in one transaction.

.. code-block:: py

  def on_apply(item, delta, params, connection): 
      tracks = item.task.tracks.copy()
      changes = {}
      delta.update_deleted()    
      for d in delta:
          for t in d.invoice_table:
              if not changes.get(t.track.value):
                  changes[t.track.value] = 0
              if t.rec_inserted():
                  changes[t.track.value] += t.quantity.value
              elif t.rec_deleted():
                  changes[t.track.value] -= t.quantity.value                
              elif t.rec_modified():
                  changes[t.track.value] += t.quantity.value - t.quantity.old_value
      ids = list(changes.keys())
      tracks.set_where(id__in=ids)                
      tracks.open()
      for t in tracks:
          q = changes.get(t.id.value)
          if q:
              t.edit()
              t.tracks_sold.value += q
              t.post()
      tracks.apply(connection)

In the previous examples the ``on_apply`` event handler returns ``None`` so after 
that the ``apply_delta`` method is executed by the application.

The more general case is: 

.. code-block:: py

  def on_apply(item, delta, params, connection): 
  
    # execute some code before changes are written to the database
    
    result = item.apply_delta(delta, params, connection)
    
    # execute some code after changes are written to the database
    
    return result

See also
========

:doc:`Server side programming </programming/server/index>`

:doc:`on_apply events </programming/server/on_apply_events>`

:doc:`Modifying datasets </programming/data/modifying_datasets>`


