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

on_apply(self, delta, params)

**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>`.

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,

The delta parameter contains changes that must be saved in the databae. 
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 item, delta also has a corresponding detail item, 
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 detail 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.
    
The following code is execute by default when the ``on_apply`` event 
handler is not defined:

.. code-block:: py

    sql = delta.apply_sql()
    return item.task.execute(sql)

The ``apply_sql`` method generates a dictionary, containing SQL queries, that the
:doc:`execute </refs/server/task/m_execute>`
method of the task knows how to process. After processing it 
:doc:`execute </refs/server/task/m_execute>`
returns to the client 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 ``id`` fields of new records.

When ``on_apply`` event handler returns ``None`` this standard code is 
executed after it, otherwise it is ommited.

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, privileges, user_info, enviroment):
        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!!!

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

.. code-block:: py

    def on_apply(item, delta, params, privileges, user_info, enviroment):
        tracks_sql = []
        delta.update_deleted()    
        for d in delta:
            for t in d.invoice_table:
                if t.rec_inserted():
                    sql = "UPDATE DEMO_TRACKS SET TRACKS_SOLD = COALESCE(TRACKS_SOLD, 0) + \
                    %s WHERE ID = %s" % \
                    (t.quantity.value, t.track.value)                
                elif t.rec_deleted():
                    sql = "UPDATE DEMO_TRACKS SET TRACKS_SOLD = COALESCE(TRACKS_SOLD, 0) - \
                    (SELECT QUANTITY FROM DEMO_INVOICE_TABLE WHERE ID=%s) WHERE ID = %s" % \
                    (t.id.value, t.track.value)
                elif t.rec_modified():
                    sql = "UPDATE DEMO_TRACKS SET TRACKS_SOLD = COALESCE(TRACKS_SOLD, 0) - \
                    (SELECT QUANTITY FROM DEMO_INVOICE_TABLE WHERE ID=%s) + %s WHERE ID = %s" % \
                    (t.id.value, t.quantity.value, t.track.value)
                tracks_sql.append(sql)                
        sql = delta.apply_sql()
        with item.task.invoices_lock:
            return item.task.execute(tracks_sql + [sql])

See also
========

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

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


