Witam serdecznie,
Mam tabelkę https://datatables.net w swoim projekcie:


    require('datatables.net');
    require('datatables.net-bs4');
    
    //require('datatables.net-responsive');
    require('./../../vendor/dataTables.responsive');
    
    require('datatables.net-responsive-bs4');
    
    import langpacks from './_langs';
    
    
    (function ( $ ) {
        if( typeof $.fn.DataTable !== 'function' )
        {
            throw new Error('Datatables not defined!');
        }
    
        if(typeof $.fn.purgetText !== 'function')
        {
            $.fn.purgeText = function() {
                var $html = $(this).children();
                $(this).text(null).html( $html );
                return this;
            };
        }
    
        var initComplete = function() {},
            preXhr = function(e, settings, data) {
                const contextSelector = isArray(window.dtables) && window.dtables.length > 1 ? this.id : '';
                const selector = contextSelector ? [
                    `#${contextSelector}_filter_content [data-action~="table-filter"]`,
                    `#${contextSelector}_filter [data-action~="table-filter"]`
                ].join(', ') : '[data-action~="table-filter"]';
    
                document.querySelectorAll(selector).forEach(filter => {
                    if( ! filter.value.length || inArray(filter.type, ['radio', 'checkbox']) && !filter.checked) {
                        return;
                    }
                    _.set(data, 'filters.' + filter.name, filter.value);
                });
    
                let tLength = $('[data-action~="table-length"]');
    
                if( tLength && tLength.value ) {
                    _.set(data, 'length', tLength.value);
                }
            },
            draw = function(e, settings) {
                var dtable = $('#' + this.id + '_wrapper');
    
                if( parseInt(lastReceivedJSON.drawedCount) === 0)
                {
                    return dtable.find('.dataTables_info').text( _.get(langpacks, document.querySelector('html').getAttribute('lang') + '.zeroRecords', 'No records found.') );
                }
    
                dtable.find('.dataTables_info').text(
                    _.get(langpacks, document.querySelector('html').getAttribute('lang') + '.info', 'Positions from _START_ to _END_ from _TOTAL_ total.')
                            .replace('_START_', (lastReceivedJSON.start + 1))
                            .replace('_END_', (lastReceivedJSON.start + lastReceivedJSON.drawedCount ))
                            .replace('_TOTAL_', (lastReceivedJSON.filteredCount))
                    + (
                        lastReceivedJSON.totalCount !== lastReceivedJSON.filteredCount
                            ? ' ' + _.get(langpacks, document.querySelector('html').getAttribute('lang') + '.infoFiltered', '(filtered out of _MAX_)').replace('_MAX_', lastReceivedJSON.totalCount)
                            : ''
                    )
                );
    
                highlightRow();
            },
            highlightRow = function() {
                let url = new URL(document.location);
                let highlightRow = url.searchParams.get('highlight');
    
                if(highlightRow != undefined)
                {
                    var target = $('tr[data-id="' + highlightRow + '"]');
    
                    if(target.length) {
                        $('html, body').animate({
                            'scrollTop': target.offset().top - $(window).height()/2
                        }, 750);
                        target.addClass('blink');
                    }
                }
    
                url.searchParams.delete('highlight');
                history.replaceState({}, null, url);
            },
            placeFilters = function(e, settings) {
                let _id = this.id;
                let dtable = $('#' + _id + '_wrapper');
                let contextSelector =  isArray(window.dtables) && window.dtables.length > 1 ? '#' + this.id + '_filter_content' : '';
                let filtersSource = $(contextSelector + '[data-content="table-filters"]');
    
                let filterTarget = dtable.find('.dataTables_filter');
    
                if( filtersSource.length === 0 || filtersSource.is(':empty') )
                {
                    return dtable.find('.row').first().children().last().addClass('text-right');
                }
    
                if( !filterTarget.length || filtersSource.data('filter-type') === 'nomove' )
                {
                    return filtersSource.removeClass('d-none')
                                        .find('input, select, textarea').each(function() {
                                            this.dataset.filterFor = _id;
                                        });
                }
    
                filterTarget.prepend( filtersSource.html() )
                            .parent().removeClass('col-md-6').addClass('col-md-12 col-xl-9')
                            .prev().removeClass('col-md-6').addClass('col-md-12 col-xl-3');
    
                if(typeof $.fn.datepickerWrapper === 'function')
                {
                    dtable.find('[data-picker="datepicker"]').datepickerWrapper();
                }
    
                filtersSource.empty();
            },
            reloadTable = function(e, data) {
                if(typeof window.dtables !== 'undefined' && Array.isArray(window.dtables))
                {
                    var $instance = _.get(data, 'instance', null) !== null
                                    ? _.get(window, 'dtables.' + _.get(data, 'instance'), null)
                                    : null;
    
                    if( $instance !== null )
                    {
                        return $instance.ajax.reload();
                    }
    
                    // fallback...
                    $.each(window.dtables, function(k, instance) {
                        instance.ajax.reload();
                    });
                }
            },
            applyFilter = function() {
                let $filterTarget = this.dataset.filterFor ? $('#' + this.dataset.filterFor) : $(this).closest('.dataTables_wrapper');
    
                $(document).trigger('dtables:reload', {
                    instance: $filterTarget.prop('id').replace(/(DataTables_Table_|_wrapper)/g,'')
                });
            },
            applyLength = function() {
                $(document).trigger('dtables:reload', {
                    instance: $(this).prop('name').replace(/(DataTables_Table_|_length)/g,'')
                });
            },
            rowCallback = function(row, data) {
                if( data._popover )
                {
                    row.dataset.popover = data._popover;
                }
    
                if(data.id)
                {
                    row.dataset.id = data.id;
                }
    
                row.dataset.md5 = data._md5;
            },
    
    
            footerCallback = function(row, data, start, end, display) {
            var api = this.api();
            var rcnt=0;
            api.columns('.sum', {
                page: 'current'
            }).every(function() {
                var sum = this
                    .data()
                    .reduce(function(a, b) {
                        var x = parseFloat(a) || 0;
                        var y = parseFloat(b) || 0;
                        return x + y;
                    }, 0);
                console.log(sum); //alert(sum);
    
                if(rcnt==0){
                    $("#foot").append('<td style="background:#a1eaed;color:black; text-align: center;">Total</td>');
                }else{
                    $("#foot").append('<td style="background:#a1eaed;color:black; text-align: center;">'+sum+'</td>');
                }
                rcnt++;
                //$(this.footer()).html(sum);
            });
        },
    
    
    
            buildOpts = (context) => {
                return {
                    processing: true,
                    serverSide: true,
                    responsive: true,
                    searching: false,
                    iDisplayLength: typeof context.data('def-length') !== 'undefined' ? context.data('def-length') : 50,
                    order: [],
                    columns: [],
                    ajax: {
                        url: context.data('url'),
                        method: 'POST',
                        data: {},
                        dataSrc: function(data) {
                            lastReceivedJSON = $.extend({}, data);
    
                            /*
                             * Little hack to make pagination work as expected
                             * while having proper count of filtered objects;;
                             */
                            data.iTotalDisplayRecords = data.filteredCount;
    
                            return data.data;
                        },
                        error: (xhr) => {
                            $(document).trigger('bs-swal:error', [{
                                title: 'Błąd pobierania danych tabeli',
                                text: _.get(xhr, 'responseJSON.message')
                            }]);
    
                            try {
                                document.querySelector('#' + context.get(0).id + '_processing').style.display = 'none';
                            } catch(e) {}
                        }
                    },
                    initComplete: initComplete,
                    rowCallback: rowCallback,
                    footerCallback: footerCallback
                };
            },
            lastReceivedJSON = null;
    
    	$.fn.esDataTable = function() {
                var $this = this;
    
                if( typeof this.data('url') === 'undefined' )
                {
                    throw new Error('Invalid esDtables url!');
                    return this;
                }
    
                let opts = buildOpts(this);
                let documentLang = document.querySelector('html').getAttribute('lang');
    
                if( documentLang && documentLang in langpacks )
                {
                    opts.language = langpacks[documentLang];
                }
    
                if( typeof $(this).data('ajax-items') !== 'undefined')
                {
                    let items = $(this).data('ajax-items');
    
                    $.each(items.split(';'), function(k,v) {
                        var i = v.split(':');
                        if(i.length === 2)
                        {
                            opts.ajax.data[ i[0] ] = i[1];
                        }
                    });
                }
    
                let contextSelector =  isArray(window.dtables) && window.dtables.length > 1 ? '#' + this.id + '_filter ' : '';
    
                document.querySelectorAll(contextSelector + '[data-action~="table-filter"]').forEach(filter => {
                    if( ! filter.value.length || inArray(['radio', 'checkbox'], filter.type) && !filter.checked) {
                        return;
                    }
                    _.set(opts.ajax.data, 'filters.' + filter.name, filter.value);
                });
    
                this.find('th[data-column]').each(function(k,v) {
                    let $this = $(this);
    
                    var title = $this.text().length > 0 ? $this.text() : '';
                    var colData = typeof $this.data('column') !== 'undefined' ? $this.data('column') : null;
    
                    if( colData === null )
                    {
                        throw new Error('Insuficient column [' + k  +'] data!');
                    }
    
                    var col = {
                            title: title,
                            data: colData,
                            searchable: typeof $this.data('searchable') !== 'undefined' ? $this.data('searchable') : false,
                            orderable: typeof $this.data('orderable') !== 'undefined' ? $this.data('orderable'): false,
                            width: typeof $this.data('width') !== 'undefined'
                                            ? $this.data('width')
                                            : colData === 'actions'
                                                ? '59px'
                                                : 'auto',
                            className: typeof $this.data('class') !== 'undefined' ? $this.data('class') : ''
                        };
    
                    opts.searching = opts.searching || col.searchable;
                    opts.columns.push(col);
    
                    if( col.orderable !== false && this.hasAttribute('data-default-direction') )
                    {
                        opts.order.push([k, this.getAttribute('data-default-direction')]);
                    }
                });
    
                if( ! opts.order.length )
                {
                    this.find('th[data-column]').each(function(idx, col) {
                        if( opts.columns[idx].orderable ) {
                            opts.order = [[idx, "asc"]];
                            return false;
                        }
                    });
                }
    
                if( ! isArray(window.dtables) )
                {
                    window.dtables = [];
                }
    
                window.dtables.push( this.DataTable(opts) );
    
                // Register events only once.
                if( ! window.jQueryEventRegistered(document, 'dtables:reload', null, reloadTable) )
                {
                    $(document).on('dtables:reload', reloadTable);
                }
    
                if( !  window.jQueryEventRegistered(document, 'change', '[data-action~="table-filter"]', applyFilter) )
                {
                    $(document).on('change', '[data-action~="table-filter"]', applyFilter);
                }
    
                this.on('preXhr.dt', preXhr);
                this.on('draw.dt', draw);
                this.one('init.dt', placeFilters);
    
                return this;
            };
    
    	$('table[data-url]').each(function() {
                $(this).esDataTable();
    	});
    
    }( jQuery ));

Działa poprawnie,
Html z tabelką:

    <table id="work_time_dt" class="table table-striped table-bordered table-hover" cellspacing="0" width="100%"
                   data-url="{{ get_lockdown_href('cases.worktime', $caseInstance) }}">
                <thead>
                <tr>
                    <th data-column="_natural_order" data-width="20px" data-class="text-right">LP</th>
                    <th data-column="user">Pracownik</th>
                    <th data-column="name">Nazwa</th>
                    <th data-column="date">Data</th>
                    <th data-column="elapsed_time">Przepracowany czas</th>
                    <th data-column="description">Opis</th>
                    <th data-column="actions" data-width="59px"></th>
                </tr>
                </thead>
                <tbody></tbody>
                <tfoot data-column="summary" data-id="4" id="foot">
                    1234.6
                </tfoot>
            </table>

Chciałbym dodać w DataTables takie podsumowanie 4 kolumny: https://datatables.net/examples/advanced_init/footer_callback.html

W jaki sposób mogę to zrobić?

Mój powyższy kod nie działa :(