### Initialize $.cash Library Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/layouts/Static.html Initializes the $.cash JavaScript library with user-specific settings and routing information. This setup is required before using $.cash functionalities. ```javascript var apiSettings = {$api_settings|json_encode}; $(function() { $.cash.init({ isAdmin: {$isAdmin}, userId: {$userId}, accountName: '{$wa->accountName()|escape}', appName: '{$wa->appName()}', routingOptions: { wa_url: '{$wa_url}', wa_backend_url: '{$wa_backend_url}', wa_app_url: '{$wa_app_url}', wa_app_static_url: '{$wa_app_static_url}' } }); }); ``` -------------------------------- ### Start/Update Import Process Source: https://github.com/1312inc/webasyst-cashflow/blob/master/plugins/tinkoff/templates/actions/backend/Backend.html Initiates or updates the data import process. It validates the cash account selection, serializes form data, and sends it to the server. It then starts a polling mechanism to track the import progress. ```javascript $start_button.on('click', function () { let $that = $(this); let $tab_content = $('.js-tab-content-'+ profile_id); let $cash_account = $('select[name="profiles['+ profile_id +'][cash_account]"]'); if (!$cash_account.val()) { setTimeout(function () { $cash_account.removeClass('state-error'); }, 1500); $cash_account.addClass('state-error'); return; } let instance = profiles[profile_id]['progressbar']; let form_data = $tab_content.find('input, textarea, select').serialize(); $that.addClass('hidden'); $tab_content.find('.js-progressbar').removeClass('hidden'); $tab_content.find('.js-settings-block').addClass('hidden'); $tab_content.find('.js-settings-show').addClass('hidden'); renderText('
[`Подключение...`]'); saveProfile(form_data, function () { $.post(url, form_data, function (response) { renderText(''); if (response && response.error) { $tab_content.find('.js-error-msg').text(response.error); } else if (response && response.processid) { process_id = response.processid; if (instance && response.progress) { instance.set({ percentage: response.progress }); } if (response.text_legend) { renderText(response.text_legend); } step(profile_id, instance); } else { $tab_content.find('.js-error-msg').text('Server error'); } }, 'json').error(function () { $tab_content.find('.js-error-msg').text('Server error'); }); }); }); ``` -------------------------------- ### Order Import Date Range Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/shop/ShopSettings.html Displays the date range for importing all historical orders. This is shown only on the first time setup. ```html All time {sprintf('%s — %s', $shopOrderDateBounds['min']|wa_date:humandate, $shopOrderDateBounds['max']|wa_date:humandate)} ``` -------------------------------- ### Order Import Filter for Paid Orders Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/shop/ShopSettings.html A setting to import only orders that were paid after a specified date. This is part of the initial setup. ```html Only orders paid after ``` -------------------------------- ### Initialize Application State Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/layouts/Static.html Sets up a global JavaScript object `appState` with essential account, language, URL, and configuration details from the Webasyst environment. This is crucial for client-side scripts to access application context. ```javascript window.appState = { "accountName": "{$wa->accountName()}", "lang": "{$wa->locale()}", "baseUrl": "{$wa_app_url}", "baseApiUrl": "{$wa_url}api.php", "baseStaticUrl": "{$wa_app_static_url}", "token": "{$token}", "currencies": {$currencies}, "categories": {$categories}, "accounts": {$accounts}, "api_settings": {$api_settings}, "emptyFlow": {json_encode(!empty($emptyFlow))}, "shopscriptInstalled": {json_encode(boolval($wa->shop))}, "isPremium": {json_encode(boolval($isPremium))} }; ``` -------------------------------- ### Create Cash Flow App Directory Source: https://github.com/1312inc/webasyst-cashflow/blob/master/README.md Create the directory for the Cash Flow app within the Webasyst apps folder. ```bash cd /PATH_TO_WEBASYST/wa-apps/ mkdir cash git clone git://github.com/1312inc/Webasyst-CashFlow.git ./ ``` -------------------------------- ### Add Cash Flow App to Configuration Source: https://github.com/1312inc/webasyst-cashflow/blob/master/README.md Register the Cash Flow app by adding its entry to the Webasyst configuration file. ```php 'cash' => true, ``` -------------------------------- ### Enable Shop-Script Integration Toggle Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/shop/ShopSettings.html This snippet shows how to initialize a Webasyst Switch component for toggling the Shop-Script integration. It listens for changes to update the integration status. ```javascript ( function($) { $("#c-switch-ss-integration-core").waSwitch({ change: function(active, wa_switch) { } }); })(jQuery); ``` -------------------------------- ### JavaScript for Forecasted Sales Switch Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/shop/ShopSettings.html Initializes a Webasyst Switch component for the forecasted sales setting. The 'change' callback is currently empty. ```javascript ( function($) { $("#c-switch-forecasted-ss-sales").waSwitch({ change: function(active, wa_switch) { } }); })(jQuery); ``` -------------------------------- ### Initialize JavaScript Application State Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/layouts/Default.html Initializes the global `appState` object with account, locale, URL, token, and configuration data. This state is crucial for the frontend to function correctly. ```html {$wa->appName()} — {$wa->accountName()} {$wa->css()} window.appState = { "accountName": "{$wa->accountName()}", "lang": "{$wa->locale()}", "baseUrl": "{$wa_app_url}", "baseApiUrl": "{$wa_url}api.php", "baseStaticUrl": "{$wa_app_static_url}", "token": "{$token}", "currencies": {$currencies}, "categories": {$categories}, "accounts": {$accounts}, "api_settings": {$api_settings}, "emptyFlow": {json_encode(!empty($emptyFlow))}, "shopscriptInstalled": {json_encode(boolval($wa->shop))}, "isPremium": {json_encode(boolval($isPremium))} }; ``` -------------------------------- ### Import Process Step Source: https://github.com/1312inc/webasyst-cashflow/blob/master/plugins/tinkoff/templates/actions/backend/Backend.html Manages the step-by-step import process by polling the server for status updates. It uses `setInterval` to periodically send requests and updates the UI based on the response, including progress bars and status messages. It redirects to the account page upon successful import. ```javascript let step = function (profile_id, $progressbar) { timer = setInterval(function () { $.post(url, { processid: process_id, profile_id: profile_id }, function (response) { renderText(''); if (response && response.error) { $('.js-tab-content-'+ profile_id).find('.error-msg').text(response.error); } else if (response && response.ready) { clearInterval(timer); if ($progressbar) { $progressbar.set({ percentage: 100 }); } if (response.text_legend) { renderText(response.text_legend); } setTimeout(function () { let cash_account = response.cash_account_id || $('select[name="profiles['+ profile_id +'][cash_account]"]').val(); renderText(''); $('.progressbar').hide(); window.location = window.appState.baseUrl +'account/'+ cash_account +'?show_success_import_hint=1'; }, 1000); } else { if ($progressbar && response && response.progress) { $progressbar.set({ percentage: response.progress }); } if (response.text_legend) { renderText(response.text_legend); } } }, 'json'); }, 2000); }; ``` -------------------------------- ### Initialize Webasyst Cashflow App State Source: https://github.com/1312inc/webasyst-cashflow/blob/master/client/index.html Configures the global `window.appState` object with essential application settings. This includes UI mode, account information, localization, API URLs, and feature flags. It also conditionally initializes an event emitter for mobile mode. ```javascript window.appState = { "webView": <%- mode === 'mobile' %>, "accountName": "accountName", "lang": "ru\_RU", "baseUrl": "/", "baseApiUrl": "/api.php", "baseStaticUrl": "/wa-apps/cash/", "token": "<%= token %>", "currencies": <%- currencies %>, "categories": <%- categories %>, "accounts": <%- accounts %>, "api\_settings": <%- settings %>, "emptyFlow": true, "shopscriptInstalled": true, "isPremium": true }; <% if (mode === 'mobile'){ %> window.emitter = mitt(); <% } %> <% if (mode === 'desktop'){ %> <% } %> <% if (mode === 'mobile'){ %> <% } %> ``` -------------------------------- ### JavaScript Data Fetching and Widget Initialization Source: https://github.com/1312inc/webasyst-cashflow/blob/master/widgets/balanceflow/templates/Default.html Fetches data for the Balance Flow Widget and initializes it. This script should be used when the Webasyst UI version is 2.0. ```javascript import { fetchData } from '{$url_root}wa-apps/cash/widgets/balanceflow/js/balanceFlowWidget.js'; fetchData({ baseUrl: '{$url_root}', token: '{$token}' }); window.addEventListener('balanceflowWidgetDataFetchFinished', function (e) { e.detail.makeBallanceFlowWidget({ container: document.querySelector(".cash-widget-{$info['id']}"), data: e.detail.result, currencyCode: "{$currency_code}", currencySign: "{$currencies[$currency_code]->getSign()}", size: "{$info['size']}", locale: "{$locale}".replace("_", "-"), localeMessages: { arrowUp: '[`Going positive!`]', arrowDown: '[`Cash gap is coming`]', month: '[`m`]', noAccess: '[`noAccess`]' } }) }, { once: true }); (function () { setTimeout(function () { try { DashboardWidgets[{$info['id']]].renderWidget(); } catch (e) { } }, 10 * 60 * 1000); })(); ``` -------------------------------- ### Shop Settings Form Handling Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/shop/ShopSettings.html Handles form submission, toggling elements, and updating UI based on user input for shop settings. Includes AJAX post for saving settings and real-time UI updates. ```javascript 'use strict'; (function () { var $ssform = $('#cash-shopscript-settings'), formData = $ssform.serialize(); if ($ssform.length) { $ssform .on('submit.cash', function (e, data) { var $saved = $(""), $loading = $(""), $button = $ssform.find('[type="submit"]'); e.preventDefault(); formData = $ssform.serialize(); $button.after($loading); $.post('?module=shop&action=settings', formData, function (html) { $loading.remove(); $button.after($saved); setTimeout(function () { $saved.remove(); window.location.reload(); }, 131.2); }) }) .on('click.cash', '[data-cash-shop-configure-actions]', function (e) { e.preventDefault(); var $this = $(this), type = $this.data('cash-shop-configure-actions'), $w = $ssform.find('[data-cash-shop-configure-actions-' + type + ']'); if ($w.length) { $w.toggle(); } }) .on('change.cash', '[data-cash-category-color-icon] select', function () { var $select = $(this), $w = $select.closest('[data-cash-category-color-icon]'), $color = $w.find('i.color'), $selected = $select.find(':selected'); $color.css('background', $selected.data('cash-category-color')); }) .on('change.cash', '[name="shopscript_settings[enableForecast]"]', function (e) { $ssform.find('[data-cash-settings="forecast-variants"]').toggle($(this).is(':checked')); }) .on('change.cash', '[name="shopscript_settings[accountId]"]', function (e) { var $this = $(this), $error = $this.closest('.field').find('.errormsg'); $error.hide(); $.post('?module=json&action=checkShopCurrency', { account: $this.val() }, function (r) { if (r.status === 'fail') { $error.text(r.errors).show(); } }, 'json') }) .on('change.cash', ':input', function (e) { $ssform.find('[data-cash-shop-save-button]').addClass(formData != $ssform.serialize() ? 'yellow' : 'green'); }) .on('click.cash', '[data-cash-shop-action="rerun-import"]', function (e) { e.preventDefault(); $.get('?module=shop&action=resetImportDialog', function(dialogHtml) { $.waDialog({ html: dialogHtml, onOpen: function ($dialogWrapper, d) { var $errorMsg = $dialogWrapper.find('.errormsg'), $submitButton = $dialogWrapper.find('.js-ok'); setTimeout(function () { $dialogWrapper.find('[name="code"]').trigger('focus'); }, 13.12); $errorMsg.hide(); $dialogWrapper.find('[name="code"]').on('keypress', function (e) { if (e.key === "Enter") { e.preventDefault(); $submitButton.trigger('click'); } }); $submitButton.after($.cash.$loading).on('click.cash', function (e) { e.preventDefault(); $.post('?module=shop&action=resetImport', $dialogWrapper.find('form').serialize(), function (r) { $.cash.$loading.remove(); if (r.status === 'ok') { d.close(); window.location.reload(); } else { $errorMsg.text(r.errors.join('
')).show(); } }, 'json'); }); $dialogWrapper.find('.js-close').on('click.cash', function (e) { d.close(); }); } }); }) }) .on('change.cash', '[name="shopscript_settings[enabled]"]:checkbox', function (e) { var $setW = $ssform.find('[data-cash-shop-settings-wrapper]'); if ($(this).is(':checked')) { $setW.removeClass('c-shop-settings-wrapper-disabled'); } else { $setW.addClass('c-shop-settings-wrapper-disabled'); } }) .on('click.cash', '.firstTimeHiddenBlockToggler', function (e) { e.preventDefault(); $ssform.find('.firstTimeHiddenBlock').toggle(); }); $ssform.find('select').trigger('change.cash'); var $welcome = $('#cash-welcome-shop-start'); if ($welcome.length) { var $allPeriod = $ssform.find('[name="import_period"]:first'), $afterPeriod = $ssform.find('[name="import_period"]:last'), datepicker_options = { changeMonth: true, changeYear: true, shortYearCutoff: 2, dateShowWeek: false, showOtherMonths: true, selectOtherMonths: true, stepMonths: 1, numberOfMonths: 1, gotoCurrent: true, constrainInput: false, dateFormat: "yy-mm-dd", onSelect: function(date) { $afterPeriod.prop('checked', true); updateImportOrderCount(date); }, }, $datePicker = $ssform.find('[name="import_period_after"]'); $datePicker.datepicker(datepicker_options); var updateImportOrderCount = function (after) { $.post('?module=json&action=updateImportOrderCount', { after: after }, function (r) { if (r.status !== 'fail') { $welcome.val($_( 'Import ' + parseInt(r.data) + ' paid orders')) } }, 'json') }; $afterPeriod.on('click.cash', function (e) { updateImportOrderCount($datePicker.val()); }); $allPeriod.on('click.cash', function (e) { updateImportOrderCount(); }); $welcome.on('click.cash', function (e) { e.preventDefault(); var $button = $(this), $progress = $('#c-welcome-import'), $progressBar = $progress.find('.progressbar'), $progressLoading = $progress.find('[data-cash-shop-import-progress-icon="loading"]'), $progressCounts = $progressLoading.find('[data-cash-shop-import-progress-counts]'), $progressSuccess = $progress.find('[data-cash-shop-import-progress-icon="success"]'), $progressError = $progress.find('[data-cash-shop-import-progress-icon="progre'] }); } } })(); ``` -------------------------------- ### Download Error Log Link Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/csv/view.html Conditionally displays a link to download the error log if the import entity has errors. ```html {if $filter->entity->getErrors()}* [[\`Download error log\`]](?module=import&action=csvDownloadErrors&id={$filter->identifier}){/if} ``` -------------------------------- ### Load Backend Layout Plugins Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/layouts/Default.html Iterates through registered backend layout plugins and loads their respective JavaScript files. This allows for extending the backend interface. ```html {\* @event backend_layout.%plugin_id%.js *} {foreach $backend_layout_plugins as $plugin_name => $backend_layout_plugin} {$backend_layout_plugin.js|default:''} {/foreach} ``` -------------------------------- ### Shop Settings Validation and Import Process Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/shop/ShopSettings.html Handles form submission for shop settings validation and initiates a long action for importing data. Includes progress bar updates and error display. ```javascript ($progressBar.length && $progressBar.data('progressbar')) || ($progressBar.waProgressbar({ "color": "var(--green)", "text-inside": true }), $progressBar.data('progressbar')); var progressInstance = $progressBar.data('progressbar'); $.post('?module=shop&action=settingsValidate', $ssform.serialize(), function (r) { var $errors = $ssform.find('[data-cash-shop-errors]'); $errors.find('.box').empty(); if (r.status === 'fail') { $errors.show(); var errors = []; for(var error in r['errors']) { errors.push(r['errors'][error]); } $errors.find('.box').html(errors.join('
')); } else { $errors.hide(); $button.prop('disabled', true).hide(); var long = $.wa.kmLongAction(); long.start({ process_url: '?module=shop&action=importProcess', parallel: 2, debug: true, start: { data: { 'period': $('[name="import_period"]:checked').val(), 'period_after': $datePicker.val() }, onStart: function (r) { $button.hide(); $progressLoading.show().siblings().hide(); }, onSuccess: function (r) { $progressBar.show(); progressInstance.set({ percentage: 10 }); }, onError: function (r) { $progressError.show().siblings().hide(); $progressError.find('em').text(r.error); $button.prop('disabled', false).show(); } }, step: { onProgress: function (r) { progressInstance.set({ percentage: Math.round( r.progress * 0.9) + 10 }); $progressCounts.text(r.passed_orders + ' / ' + r.total_orders) }, onReady: function (r) { $progressSuccess.show().siblings().hide(); progressInstance.set({ percentage: Math.round(r.progress) }); window.location = window.appState.baseUrl + 'account/' + $ssform.find('[name="shopscript_settings[accountId]"]').val() + '?show_ss_import_hint=1'; }, onError: function (r) { $progressError.show().siblings().hide(); $progressError.find('em').text(r.error); $button.prop('disabled', false).show(); } } }); } }); ``` -------------------------------- ### Premium App Icon CSS Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/upgrade/Upgrade.html CSS for styling the premium app icon, including its position, z-index, height, and background image. ```css .c-premium-appicon { position: relative; z-index: 10; height: 9rem; background: url('{$wa_url}wa-apps/cash/img/cash.png') no-repeat center / 8rem; } ``` -------------------------------- ### Manage Import Progress Steps Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/Import.html This JavaScript code manages the visual progress indicator for the import steps. It updates the UI to show completed and current steps based on the provided step number. This is typically triggered after a successful file upload or configuration. ```javascript $w.on("stepChange.cash", function (e, stepN) { stepN--; $importProgress.find("li").removeClass().each(function (index) { if (index < stepN) { $(this).addClass("completed"); } if (index == stepN) { $(this).addClass("current"); } }); }); ``` -------------------------------- ### Profile Selection Handling Source: https://github.com/1312inc/webasyst-cashflow/blob/master/plugins/tinkoff/templates/actions/backend/Backend.html Handles clicks on profile elements to select a profile. It updates the UI to reflect the selected profile and shows the corresponding tab content. It also displays the last update date if available. ```javascript $('#js-profile-c').on('click', 'div.c-profile', function (e) { profile_id = $(this).find('a').data('profile-id'); $('#js-profile-c > div.c-profile').removeClass('c-selected'); $(this).addClass('c-selected'); if (profile_id) { $('[name="profile_id"]').val(profile_id); $('[class*=js-tab-content').addClass('hidden'); $('.js-tab-content-'+ profile_id).removeClass('hidden'); if (profiles.hasOwnProperty(profile_id)) { let $up_dt = $('.js-update-date'); if (profiles[profile_id].hasOwnProperty('update_date') && profiles[profile_id]['update_date']) { $up_dt.text(profiles[profile_id]['update_date']); $up_dt.closest('strong.hint').removeClass('hidden'); } else { $up_dt.closest('strong.hint').addC ``` -------------------------------- ### Main Pagination Logic Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/include/pagination.html This snippet contains the core logic for rendering pagination controls. It conditionally displays total rows, navigation links (previous, page numbers, next), and records per page options based on the presence and values of variables like $pagination, $show_total_rows, $current_page, $base_url, $limit, and $show_records_on_page. ```HTML (Templating) {if count($pagination) > 1 || $show_records_on_page} {if $show_total_rows}[`Total`]: {$total_rows}{/if} {if count($pagination) > 1} {if $current_page != 1} [[\`prev\`]]({$base_url}/{$start-$limit}/{$limit}/) {/if} {foreach $pagination as $page => $offset} {$page} {else} ... {/if} {/foreach} {if $current_page != $page} [[\`next\`]]({$base_url}/{$start+$limit}/{$limit}/) {/if} {/if} {if $show_records_on_page} [`Show`] {foreach $records_on_page as $onpage} {$onpage} {/foreach} [`at page`] {/if} {/if} ``` -------------------------------- ### JavaScript for Transaction List and Import Deletion Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/csv/view.html Initializes the transaction list, loads transactions, and handles the deletion of a CSV import via an AJAX POST request. If deletion is successful, it redirects to the root hash; otherwise, it logs errors. ```javascript 'use strict'; (function () { var $w = $('#cash-imports-page'), $transactionList = $('[data-cash-wrapper="transaction-list"]'), filterId = '{$filter->identifier}', filterType = '{$filter->type}', startDate = '{$startDate}', endDate = '{$endDate}'; $.cash.loadTransactions(startDate, endDate, filterId, filterType, $transactionList); // $.cash.loadGraphData(startDate, endDate, filterId, filterType, '#cash-chart'); $w.on('click', '[data-csv-import-action="delete"]', function (e) { e.preventDefault(); $.post( '?module=import&action=csvDelete', { id: filterId }, function (r) { if (r.status === 'ok') { window.location.hash = '#/'; } else { $.cash.log(r.errors.join("\n")); } }, 'json' ); }); }()); ``` -------------------------------- ### Webasyst Cashflow Upgrade Logic (Smarty) Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/upgrade/Upgrade.html Smarty template logic to determine premium status, cloud status, and construct the upgrade URL. This logic is used to conditionally display upgrade buttons and pricing information. ```smarty {$\_is\_premium = cashHelper::isPremium()} {$\_is\_cloud = cashHelper::isCloud()} {$\_premium\_pricing = cashHelper::getPremiumPricing()} {$\_upgrade\_url = '[\`https://www.webasyst.com/my/buy/upgrade-to-premium/cash/\]'|cat:'?domain='|cat:str\_replace('http://','',str\_replace('https://','',$wa->domainUrl()))} {capture "getpremiumbutton"} {if !$\_is\_premium} [{if $\_is\_cloud}\[\`Upgrade to premium\`\]{else}{$\_premium\_pricing.special\_button|default:'\[\`Upgrade to premium\`\]'}{/if}]({$_upgrade_url}) #### {if $\_is\_cloud} {if !empty($\_premium\_pricing.compare\_price)}{$\_premium\_pricing.compare\_price}{/if} \[\`All inclusive in the cloud\`\] {else} {if !empty($\_premium\_pricing.upgrade\_compare\_price)}{$\_premium\_pricing.upgrade\_compare\_price}{/if} {if !empty($\_premium\_pricing.upgrade\_price)} {$\_premium\_pricing.upgrade\_price} — \[\`upgrade basic → premium\`\] {/if} {if !empty($\_premium\_pricing.compare\_price)}{$\_premium\_pricing.compare\_price}{/if} {$\_premium\_pricing.price} — \[\`new premium license\`\] {/if} {if $\_is\_cloud} \[\`In Webasyst Cloud, simply upgrade to the **Premium** plan and get all premium features at once with no extra purchase.\`\] {sprintf('[\[\`Or get [new license](%s) for the Custom plan.\`\]', $\_upgrade\_url)} {else} {if !empty($\_premium\_pricing.special)} **\[\`One-time payment, not a subscription!\`\]** {sprintf('[\[\`%s intro offer for upgrading existing app license to the premium version\`\]', sprintf('%s', $\_premium\_pricing.special\_color, $\_premium\_pricing.special))} — **{date('Y.m')} \[\`special offer!\`\]** {else} \[\`Per-server license for the entire company. Unlimited users, all the premium features, and free updates forever.\`\] {/if} {/if} {/if} {/capture} ``` -------------------------------- ### Initialize Report Stream Chart Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/report/internal/ReportStream.html Import and initialize the reportStream function to render a chart. Ensure the correct data, locale, and target element ID are provided. This is typically used within an HTML template. ```html {if $wa->locale() !== 'en_US'} {/if} import reportStream from "{$wa_app_static_url}js/reports/reportStream.js?v={$wa->version()}"; reportStream('chartdiv_stream', {$data|json_encode}, '{$wa->locale()}'); ``` -------------------------------- ### Report Period Navigation Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/report/internal/ReportDds.html Provides a list of report periods for navigation, highlighting the currently selected period. Includes JavaScript for initializing a dropdown. ```html * {$currentPeriod->getName()} {foreach array_reverse($reportPeriods) as $reportPeriod} * isEqual($reportPeriod)}class="selected"{/if}> [{$reportPeriod->getName()|escape}]({$wa_app_url}report/dds/type={$type->id}&year={$reportPeriod->getValue()}) {/foreach} ( function($) { $("#c-dds-year-dropdown").waDropdown(); })(jQuery); ``` -------------------------------- ### Initiate Tinkoff Connection Source: https://github.com/1312inc/webasyst-cashflow/blob/master/plugins/tinkoff/templates/actions/backend/Backend.html Handles the connection process with Tinkoff. It redirects the user to a Tinkoff authorization URL or displays errors if the connection fails. It also reloads the page if profiles are successfully retrieved. ```javascript function tinkoffConnect($button, param) { $button.addClass('disabled'); $.get('?plugin=tinkoff&module=auth'+ (param ? '&add=1' : ''), function (data) { data = (data.hasOwnProperty('data') ? data.data : data); if (data.redirect_url) { window.location.href = data.redirect_url; } else if (data.error_description) { alert(data.error_description); } else if (data.errors) { $('.js-connect-error').text(data.errors.join(' ').replace(/[,\s]+$/m, '')); } else if (data.profiles) { window.location.reload(); } }); } ``` -------------------------------- ### Create New Category via Prompt Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/csv/form.html Handles the creation of new income or expense categories. Prompts the user for a new category name and sends a POST request to save it. Updates dropdowns with the new category. ```javascript }).on('change.cash', '[data-cash-csv-import-conditions-category] select, [name="import[category][single][income][column]"] , [name="import[category][single][expense][column]"]', function(e) { var $this = $(this), $selected = $this.find(':selected'), val = $selected.val(), newCatName = '', type = ''; if (val == {cashImportResponseCsv::NEW_INCOME_ID}) { newCatName = prompt($\_('New income category: ')); type = '{cashCategory::TYPE_INCOME}'; } else if (val == {cashImportResponseCsv::NEW_EXPENSE_ID}) { newCatName = prompt($\_('New expense category: ')); type = '{cashCategory::TYPE_EXPENSE}'; } if (newCatName && type) { $this.prop('disabled', true); $.post('?module=category&action=save', { category: { type: type, name: newCatName } }, function (r) { $this.prop('disabled', false); if (r.status === 'ok') { var $optgroup = $form.find('[data-cash-categories-optgroup="' + type + '"]'), $expenses = $form.find('[name="import[category][single][expense][column]"]'), $incomes = $form.find('[name="import[category][single][income][column]"]'), option = ''; if ($optgroup.length) { $optgroup.find('option:first').after(option); } $expenses.find('option:nth(1)').after(option); $incomes.find('option:nth(1)').after(option); $this.find('option[value="' + r.data.id + '"]').attr('selected', 'selected'); } }, 'json'); } }) ``` -------------------------------- ### Conditional Header for Single App Mode Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/layouts/Default.html Renders a specific header for the user when the application is running in single-app mode. Includes JavaScript to adjust container styling. ```html {if $wa->isSingleAppMode()} {$wa->headerSingleAppUser()} $(function () { $('#wa-single-app-nav-container') .parent() .css({ 'z-index': 100500, 'overflow': 'visible' }); }); {/if} ``` -------------------------------- ### Display Order Financial Summary Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/include/shop-legacy/backend_order.aux_info.html This snippet iterates through and displays income, expense, and profit counts and totals for an order. It also shows the total delta and provides links to add new transactions or view all associated transactions. It uses conditional logic for locale-specific text. ```html {\n\t$\_ smthngshwn = 0\n} {if $info->incomeCount} {$\_ smthngshwn = 1}* {implode(' ', $info->income)} ({$info->incomeCount}) {/if} {if $info->expenseCount} {$\_ smthngshwn = 1}* {implode(' ', $info->expense)} ({$info->expenseCount}) {/if} {if $info->profitCount} {$\_ smthngshwn = 1}* {implode(' ', $info->profit)} ({$info->profitCount}) {/if} {if $info->delta} {$\_ smthngshwn = 1}* {if $wa->locale() == 'ru\_RU'}Итого{else}Total{/if} {implode(' ', $info->delta)} {/if} {if !$\_ smthngshwn} {if $wa->locale() == 'ru\_RU'}С заказом еще не связано ни одной денежной операции.{else}No transactions are linked with the order yet.{/if} {/if} [\\+ {if $wa->locale() == 'ru\_RU'}Доход{else}Income{/if}]({$info->link}?addtransaction=income) [− {if $wa->locale() == 'ru\_RU'}Расход{else}Expense{/if}]({$info->link}?addtransaction=expense) [{\\+} {if $wa->locale() == 'ru\_RU'}Все операции{else}View transactions{/if} ({$info->incomeCount + $info->expenseCount + $info->profitCount})]({$info->link}) ``` -------------------------------- ### Responsive Chart CSS for TV Dashboard Source: https://github.com/1312inc/webasyst-cashflow/blob/master/widgets/balanceflow/templates/Default.html Applies CSS to make the cash widget chart responsive on the TV dashboard for Webasyst UI 2.0. ```css body.tv .cash-widget-{$info['id']} .cash-widget-chart { width: auto !important; height: auto !important; } ``` -------------------------------- ### Initialize Report Categories Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/report/internal/ReportDdsCategories.html Initializes the report categories using provided data, locale, year, and category values. This script should be included in your HTML to enable interactive report visualizations. ```javascript import reportCategories from "/static/js/reports/reportCategories.js?v=1.0.0"; const data = {"all_income":[],"all_expense":[]}; const categories = {}; const year = Number(new URL(window.location).pathname.split('/').pop().split('=')[1]) || new Date().getFullYear(); reportCategories(data, 'en_US', year, Object.values(categories)); ``` -------------------------------- ### jQuery Dropdown Initialization Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/report/internal/ReportDdsCategories.html Initializes a Webasyst dropdown component for the year selection. This snippet assumes jQuery and the Webasyst UI library are available. ```javascript ( function($) { $("#c-dds-year-dropdown").waDropdown(); })(jQuery); ``` -------------------------------- ### CSV Import Date Format Selection Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/csv/form.html Handles user interaction for selecting or entering a custom date format. It prompts the user for a format if none is selected and triggers a change event. ```javascript (function ($) { var $dateFormatW = $('[name="import[datetime]"]'); var $form = $('#cash-flow-import-form'); $dateFormatW.on('change.cash', 'select', function (e) { var $this = $(this), $selected = $this.find(':selected'), value = $selected.val(); if (!value) { var format = prompt($_( 'Enter format')); if (format) { $selected.before('') .removeAttr('selected'); $this.trigger('change.cash'); } } else { $form.find('[name="import[datetime]"]').trigger('change.cash'); } }); $form.find('[name="import[datetime]"], [name="import[amount][single][column]"]').trigger('change.cash'); $('#c-import-step-1').hide(); }(jQuery)) ``` -------------------------------- ### Initialize Date Range Toggle with Update Functionality Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/report/includes/DateRange.html Initializes the date range toggle component and sets up event listeners for date updates. Use this when you need to capture selected dates and redirect the user. ```javascript import renderRangeToggle from '{$wa_app_static_url}js/reports/rangeToggle.js?v={$wa->version()}'; $(function () { renderRangeToggle('.range-container', [-365, -90, -30, 30, 90, 365, 1095, 1825], updateDates); $('.range-container button').on('click', updateDates); function updateDates () { const from = $('.range-container [name="from"]').val(); const to = $('.range-container [name="to"]').val(); window.location = 'from=' + from + '&to=' + to; } }); ``` -------------------------------- ### Automatic Average Daily Sales Calculation Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/shop/ShopSettings.html A checkbox to enable automatic calculation of average daily sales based on the last 30 days of data. The 'checked' attribute is set based on the isAutoForecast() method. ```html isAutoForecast()}checked{/if} /> Calculate average daily sales automatically (≈{$avg}/day based on the data for the last 30 days) ``` -------------------------------- ### Confirm and Reset Tinkoff Import Source: https://github.com/1312inc/webasyst-cashflow/blob/master/plugins/tinkoff/templates/actions/backend/Backend.html Provides a confirmation dialog before performing a full reset of the Tinkoff import. This is a critical action intended for situations where a complete restart is necessary. ```javascript $('.js-tinkoff-reset').on('click', function (e) { e.preventDefault(); $.waDialog.confirm({ title: 'Не совершайте ошибку', text: 'Перезапускать импорт с нуля имеет смысл, только если что-то пошло совсем не так. Например, если нужно кардинально сменить режим работы и переключить плагин из авто-режима в селф-сервис или наоборот.', success_button_title: 'Начать все с начала', success_button_class: 'danger', cancel_button_title: 'Ничего не менять', cancel_button_class: 'light-gray', onSuccess: function () { $.get('?plugin=tinkoff&module=reset', function () { window.location.reload(); }); } }); }); ``` -------------------------------- ### Enable Tinkoff Self-Service Mode Source: https://github.com/1312inc/webasyst-cashflow/blob/master/plugins/tinkoff/templates/actions/backend/Backend.html Makes the token field visible, indicating that the plugin is being switched to self-service mode. ```javascript $('.js-on-self-mode').on('click', function (e) { e.preventDefault(); $('.js-token-field').removeClass('hidden'); }); ``` -------------------------------- ### CSV Import Account Mapping Row Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/csv/form.html HTML template for rendering a row in the CSV import form that maps a column to a financial account. Includes an option to skip rows. ```html ${columnValue} =>
${transactions} ``` -------------------------------- ### Import Name Display Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/csv/view.html Displays the name of the import, escaped for safe rendering in HTML. ```html {$filter->name|escape} ``` -------------------------------- ### Initialize Report Sankey Chart Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/report/internal/ReportSankey.html Initializes a Sankey chart using the reportSankey JavaScript function. Ensure the necessary JS file is imported and data is correctly formatted. ```javascript import reportSankey from "/static/js/reports/reportSankey.js?v=1.0.0"; reportSankey('chartdiv_sankey', {"data": []}, 'en_US', '[`All currencies`]'); ``` -------------------------------- ### Order Import Update Notice Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/shop/ShopSettings.html Informs the user that changes to order import settings apply only to new orders. It advises on how to update existing data by deleting and re-importing. ```html All changes to the order import setup will be applied to new orders only. To update data for existing orders and transactions that had been imported already, delete all existing transactions manually and then [re-start the integration from scratch](%s). ``` -------------------------------- ### Handle CSV File Upload and Preview Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/Import.html This JavaScript code handles the change event for a file input, submitting the form and processing the response to display a preview of the imported data. It's used for the initial step of uploading a CSV file for import. ```javascript var $w = $("#cash-import-page"), $importProgress = $w.find(".c-import-progress"), $uploadForm = $("#cash-import-upload-form"), $uploadIframe = $("#cash-upload-file"), $step2 = $("#c-import-step-2"), $loading = $("
"); $uploadForm.on("change", "[name=\"upload[file]\"]", function () { $uploadForm.append($loading); $uploadForm.trigger("submit"); $uploadIframe.one("load", function () { $loading.remove(); var html = $(this).contents().find("body").html(); $step2.html(html); $w.trigger("stepChange.cash", 2); }); }); ``` -------------------------------- ### Premium Feature Card CSS Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/upgrade/Upgrade.html CSS for styling premium feature cards, including border-radius, background, margin, and padding. Includes a specific style for half-width cards. ```css .c-premium-feature { border-radius: 0.75rem; background: var(--background-color-blank); margin-bottom: 1.5rem; padding: 1.5rem 2rem; } .c-premium-feature.halfwidth { width: 40%; margin-bottom: 0; padding-bottom: 0.5rem; } .c-premium-feature.halfwidth h3 { fonc-size: 1.25rem; } .c-app-inline-badge { max-height: 50px; width: auto; margin-bottom: 0.5rem; } @media screen and (max-width: 760px) { .c-premium-feature.halfwidth { width: 100%; } } ``` -------------------------------- ### Datepicker Initialization Source: https://github.com/1312inc/webasyst-cashflow/blob/master/plugins/tinkoff/templates/actions/backend/Backend.html Configures a jQuery datepicker widget with specific options, including date format and month/year selection. It also sets a callback to update an import period field when a date is selected. ```javascript let datepicker_options = { changeMonth: true, changeYear: true, shortYearCutoff: 2, dateShowWeek: false, showOtherMonths: true, selectOtherMonths: true, stepMonths: 1, numberOfMonths: 1, gotoCurrent: true, constrainInput: false, dateFormat: 'yy-mm-dd', onSelect: function (date) { $(this).closest('div').find('[name$="[import_period]"]').prop('checked', true).val(date); } }; let $date_picker = $('[name$="[begin_import_period]"]'); $date_picker.datepicker(datepicker_options); ``` -------------------------------- ### Fetch Unique Column Values and Map Them Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/import/csv/form.html Fetches unique values for a selected column and populates a mapping interface. It allows users to map these values to existing categories or create new ones. Stores relations in localStorage. ```javascript }).on('change.cash', '[data-cash-csv-import-action="fetch-column-data"]', function (e) { var $this = $(this), name = $this.find(':selected').text(), scope = $this.data('cash-csv-import-conditions'), dataScope = 'data-cash-csv-import-conditions-' + scope, $wrapper = $('table[' + dataScope + ']'), $template = $('script[' + dataScope + ']'); $wrapper.empty(); fetchColumnUniqueValues(name, function (r) { if (r.status === 'ok') { if (!r.data['{{cashImportCsvAbstractValidator::UNIQUE_VALUES}}']) { return; } $.each(r.data.{{cashImportCsvAbstractValidator::UNIQUE_VALUES}}, function (index, columnValue) { if (!transactionCounts[name][columnValue]) { return; } var $tpl = $template.tmpl({ columnValue: columnValue, sources: data[scope], scope: scope, translate: { 'Expense': $\_('Expense'), 'Income': $\_('Income'), 'Skip rows with this value': $\_('Skip rows with this value') }, transactions: transactionCounts[name][columnValue] + ' ' + $\_('transactions') }).on('change', 'select', function () { var relations = JSON.parse(localStorage.getItem('relationsStorage') || '{}'), optionValue = $(this).find('option:selected').val(); // Exclude Skip rows and New Category options if (['0', '-1111111111', '-2222222222'].includes(optionValue)) { delete relations[columnValue] } else { relations[columnValue] = $(this).find('option:selected').text(); } localStorage.setItem('relationsStorage', JSON.stringify(relations)); }).appendTo($wrapper); var relationsFromStorage = JSON.parse(localStorage.getItem('relationsStorage') || '{}'); if (relationsFromStorage[columnValue]) { var $select = $tpl.find('select'), val = $select.find("option").filter(function () { return $(this).text() == relationsFromStorage[columnValue]; }).val(); $select.val(val).change(); } }); } else { alert(r.errors.join("\n")); } }); }) ``` -------------------------------- ### Cash Flow Report Title and Sandbox Message Source: https://github.com/1312inc/webasyst-cashflow/blob/master/templates/actions/report/internal/ReportDds.html Displays the main title for the cash flow report and a message if sandbox accounts are not included. ```html [`Cash flow report`] ======================== {if $is_imaginary} [\`Sandbox accounts are not displayed in the cash flow report.\`] {/if} ```