Skip to content

Commit

Permalink
Merge branch 'release/1.0.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
RamezIssac committed Jul 3, 2023
2 parents e2b2eeb + ae8498b commit 7b315de
Show file tree
Hide file tree
Showing 9 changed files with 518 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project will be documented in this file.


## [1.0.1] - 2023-07-03

- Added missing js files ported from erp_framework package.
- Document the need for "crispy_bootstrap4" in the docs and add it as a dependency in the setup.

## [1.0.0] - 2023-07-03

- Added crosstab_ids_custom_filters to allow custom filters on crosstab ids
Expand Down
1 change: 1 addition & 0 deletions docs/source/howto/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The interface is simple, only 3 mandatory methods to implement, The rest are man
These filters will be passed to the report_model.objects.filter(*q_filters, **kw_filters)
#. get_start_date: return the start date to be used in the report

#. get_end_date: return the end date to be used in the report


Expand Down
18 changes: 12 additions & 6 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ Django Slick Reporting
Installation
------------

To install django-slick-reporting:
To install django-slick-reporting with pip

1. Install with pip: `pip install django-slick-reporting`.
2. Add ``slick_reporting`` to ``INSTALLED_APPS``.
3. For the shipped in View, add ``'crispy_forms'`` to ``INSTALLED_APPS``
and add ``CRISPY_TEMPLATE_PACK = 'bootstrap4'`` to your ``settings.py``
4. Execute `python manage.py collectstatic` so the JS helpers are collected and served.
.. code-block:: bash
pip install django-slick-reporting
Usage
-----

#. Add ``"slick_reporting", "crispy_forms", "crispy_bootstrap4",`` to ``INSTALLED_APPS``.
#. Add ``CRISPY_TEMPLATE_PACK = 'bootstrap4'`` to your ``settings.py``
#. Execute `python manage.py collectstatic` so the JS helpers are collected and served.



Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,7 @@ install_requires =
pytz
simplejson
django-crispy-forms
crispy-bootstrap4



4 changes: 2 additions & 2 deletions slick_reporting/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
default_app_config = "slick_reporting.apps.ReportAppConfig"

VERSION = (1, 0, 0)
VERSION = (1, 0, 1)

__version__ = "1.0.0"
__version__ = "1.0.1"
163 changes: 163 additions & 0 deletions slick_reporting/static/slick_reporting/erp_framework.datatable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/**
* Created by ramez on 2/5/15.
* A wrapper around Datatables.net
*
*/


(function ($) {
let _cache = {};
let _instances = {}


function constructTable(css_class, cols, cols_names, add_footer, total_verbose, total_fields, data) {
// Construct an HTML table , header and footer , without a body as it is filled by th datatable.net plugin
cols = typeof cols != 'undefined' ? cols : false;
cols_names = typeof cols_names != 'undefined' ? cols_names : cols;

let return_val = `<table class="${css_class}"> <thead><tr>`;
let header_th = '';
let footer_th = '';
let footer_colspan = 0;
let stop_colspan_detection = false;
let totals_container = calculateTotalOnObjectArray(data, total_fields);
if (data.length <= 1) {
add_footer = false;
}

for (let i = 0; i < cols.length; i++) {
let col_name = cols[i].name;
header_th += `<th data-id="${col_name}">${cols_names[i]}</th>`;
if (total_fields.indexOf(col_name) !== -1) {
stop_colspan_detection = true;
}
if (!stop_colspan_detection) {
footer_colspan += 1;
} else {
let column_total = totals_container[col_name]
if (!(column_total || column_total === 0)) {
column_total = ''
}
footer_th += `<th data-id=${col_name}">${column_total}</th>`;
}
}
let footer = '';
if (add_footer && stop_colspan_detection) {
footer = '<tfoot><tr class="tr-totals active"><th colspan="' + footer_colspan + '" style="text-align:left">' + total_verbose + '</th>' + footer_th + '</tr></tfoot>';
}
return_val = return_val + header_th + `</tr> </thead>${footer}</table>`;
return return_val;
}


function buildAndInitializeDataTable(data, $elem, extraOptions, successFunction) {
// Responsible for turning a ReportView Response into a datatable.

let opts = $.extend({}, $.erp_framework.datatable.defaults, extraOptions);
opts['datatableContainer'] = $elem;

let datatable_container = opts.datatableContainer;

let provide_total = true; // typeof provide_total == 'undefined' ? true : provide_total;
let total_fields = []; //# frontend_settings.total_fields || [];
let column_names = [];
for (let i = 0; i < data['columns'].length; i++) {
let col = data['columns'][i];
column_names.push(col['verbose_name']);
if (col['is_summable'] === true) {
total_fields.push(col['name'])
}
}

if (total_fields.length === 0) provide_total = false;

datatable_container.html(constructTable(
$.erp_framework.datatable.defaults.tableCssClass, data['columns'], column_names,
provide_total, opts.messages.total, total_fields, data.data));
initializeReportDatatable(datatable_container.find('table'), data, opts);

if (typeof (successFunction) === 'function') {
successFunction(data);
}

}


function getDatatableColumns(data) {
let columns = [];
for (let i = 0; i < data['columns'].length; i++) {

let server_data = data['columns'][i];
let col_data = {
"data": server_data['name'],
'visible': server_data['visible'],
'title': server_data['verbose_name']
};
columns.push(col_data);

}
return columns;
}


function initializeReportDatatable(tableSelector, data, extraOptions) {
tableSelector = typeof tableSelector != 'undefined' ? tableSelector : '.datatable';
extraOptions = typeof extraOptions != 'undefined' ? extraOptions : {};

let opts = $.extend({}, $.erp_framework.datatable.defaults, extraOptions);


let dom = typeof (extraOptions.dom) == 'undefined' ? 'lfrtip' : extraOptions.dom;
let paging = typeof (extraOptions.paging) == 'undefined' ? true : extraOptions.paging;
let ordering = typeof (extraOptions.ordering) == 'undefined' ? true : extraOptions.ordering;
let info = typeof (extraOptions.info) == 'undefined' ? true : extraOptions.info;
let searching = typeof (extraOptions.searching) == 'undefined' ? true : extraOptions.searching;
if (data.data.length === 0) dom = '<"mb-20"t>';

let datatableOptions = $.extend({}, extraOptions['datatableOptions']);

datatableOptions.dom = dom;
datatableOptions.ordering = ordering;
datatableOptions.paging = paging;
datatableOptions.info = info;
datatableOptions.searching = searching;

datatableOptions.sorting = [];
datatableOptions.processing = true;
datatableOptions.data = data['data'];
datatableOptions.columns = getDatatableColumns(data);
datatableOptions.initComplete = function (settings, json) {
setTimeout(function () {
if (opts.enableFixedHeader) {
new $.fn.dataTable.FixedHeader(dt, {"zTop": "2001"});
}
}, 100);

};
_instances[data.report_slug] = $(tableSelector).DataTable(datatableOptions);
}


$.erp_framework.datatable = {
initializeDataTable: initializeReportDatatable,
_cache: _cache,
buildAdnInitializeDatatable: buildAndInitializeDataTable,
constructTable: constructTable,
instances: _instances
}
}(jQuery));

$.erp_framework.datatable.defaults = {

enableFixedHeader: false,
fixedHeaderZindex: 2001,
messages: {
total: $.erp_framework.defaults.messages.total,
},
tableCssClass: 'table table-xxs datatable-basic table-bordered table-striped table-hover ',

datatableOptions: { // datatables options sent to its constructor.
css_class: 'display'

}
};
163 changes: 163 additions & 0 deletions slick_reporting/static/slick_reporting/erp_framework.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/**
* Created by ramez on 1/5/15.
*/



function parseArabicNumbers(str) {
str = typeof str == 'undefined' ? '0' : str;
return Number(str.replace(/[٠١٢٣٤٥٦٧٨٩]/g, function (d) {
return d.charCodeAt(0) - 1632;
}).replace(/[۰۱۲۳۴۵۶۷۸۹]/g, function (d) {
return d.charCodeAt(0) - 1776;
}));
}


function calculateTotalOnObjectArray(data, columns) {
// Compute totals in array of objects
// example :
// calculateTotalOnObjectArray ([{ value1:500, value2: 70} , {value1:200, value2:15} ], ['value'])
// return {'value1': 700, value2:85}

let total_container = {};
for (let r = 0; r < data.length; r++) {

for (let i = 0; i < columns.length; i++) {
if (typeof total_container[columns[i]] == 'undefined') {
total_container[columns[i]] = 0;
}
let val = data[r][columns[i]];
if (val === '-') val = 0;

else if (typeof (val) == 'string') {
try {
val = val.replace(/,/g, '');
} catch (err) {
console.log(err, val, typeof (val));
}
}
total_container[columns[i]] += parseFloat(val);
}
}
return total_container;
}

function executeFunctionByName(functionName, context /*, args */) {
let args = Array.prototype.slice.call(arguments, 2);
let namespaces = functionName.split(".");
let func = namespaces.pop();
for (let i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
try {
func = context[func];
if (typeof func == 'undefined') {
throw 'Function {0} is not found the context {1}'.format(functionName, context);
}

} catch (err) {
console.error('Function {0} is not found the context {1}'.format(functionName, context), err)
}
return func.apply(context, args);
}


(function ($) {


// let opts = $.extend({}, $.erp_framework.defaults, options);

function enable_tab_support() {
//support for enter key as a navigation
let focusables = $(':focusable');
$('input').not('[ra_autocomplete_bind="true"]').not('[type="search"]').not('#top_search_box')
.on("keydown", function (event) {
if (event.keyCode === 13) {
let current = focusables.index(this);
let check = false;
while (!check) {
let next = getNext(current);
let readOnly = $(next).attr('readonly');

if (typeof readOnly == 'undefined') {
check = true;
}
if ($(next).hasClass('delete-row')) {
check = false;
}
current++;
}
next.focus();
next.select();
event.preventDefault();
}

function getNext(current) {
return focusables.eq(current + 1).length ? focusables.eq(current + 1) : focusables.eq(0);
}
});
}

function smartParseFloat(number, to_fixed) {
// Wrapper around parseFloat aimed to deliver only numbers

let val = parseFloat(number);
if (isNaN(val)) return 0;
else {
if (to_fixed > 0 && to_fixed <= 20) return val.toFixed(to_fixed);
else return val
}

}

function focus_first($div) {
$div = $div || $('body');
$div.find('input:visible').not(':disabled').not('.hasDatepicker').not('.timeinput').first().select().focus();
}

function adjustNumberWidget() {
$('input[type=number]').on('focus', function (e) {
$(this).on('mousewheel.disableScroll', function (e) {
e.preventDefault();
var scrollTo = (e.originalEvent.wheelDelta * -1) + $(document.documentElement).scrollTop();
$(document.documentElement).scrollTop(scrollTo);
})
}).on('blur', function (e) {
$(this).off('mousewheel.disableScroll')
});
}

$.erp_framework = {
enterTabSupport: enable_tab_support,
smartParseFloat: smartParseFloat,
focus_first: focus_first,

} ;
// };

$.erp_framework.defaults = {
debug: true,

messages: {

DoneMessage: "Done...",
SuccessMessage: "<i class='icon-checkmark-circle'></i> Done...",
ErrorMessage: "An error happened :( ",
WaitMessage: 'Just a moment...',
LoadingMessage: 'loading...',
total: 'Total',

},
urls: {

},
};

$.erp_framework.cache = {};
$.erp_framework.rtl = false;

$.erp_framework.debug = false; // turned on only on dev ;
}(jQuery));


0 comments on commit 7b315de

Please sign in to comment.