From 555b71c0cd011b997276a728ed058d0692db9666 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 14 Nov 2019 11:35:39 +0100 Subject: [PATCH] [FIX] plug chart of accounts & journal entries widgets on explicit classes Sections get an id automatically generated from the title, "journal entries" and "chart of accounts" are pretty generic concepts, so the widgets looking for these ids can get enabled on sections they're not intended to live in. On the other hand, Sphinx is not likely to generically create classes for these concepts without being explicitly prompted (via e.g. rst-class). --- _static/atom.js | 8 ++ _static/chart-of-accounts.js | 2 +- _static/coa-valuation.js | 270 ----------------------------------- _static/entries.js | 10 +- conf.py | 1 - 5 files changed, 14 insertions(+), 277 deletions(-) delete mode 100644 _static/coa-valuation.js diff --git a/_static/atom.js b/_static/atom.js index 49642ee41..1589afee1 100644 --- a/_static/atom.js +++ b/_static/atom.js @@ -1,3 +1,11 @@ +function findAncestor(element, name) { + name = name.toUpperCase(); + while(element && element.nodeName.toUpperCase() !== name) { + element = element.parentElement; + }; + return element; +} + function createAtom(val, options) { var watchers = {}; var validator = options && options.validator || function () { return true; }; diff --git a/_static/chart-of-accounts.js b/_static/chart-of-accounts.js index c29ba430d..e8cf343d7 100644 --- a/_static/chart-of-accounts.js +++ b/_static/chart-of-accounts.js @@ -133,7 +133,7 @@ }); document.addEventListener('DOMContentLoaded', function () { - var chart = document.getElementById('chart-of-accounts'); + var chart = findAncestor(document.querySelector('.chart-of-accounts'), 'section'); if (!chart) { return; } var controls = document.createElement('div'); diff --git a/_static/coa-valuation.js b/_static/coa-valuation.js deleted file mode 100644 index 1413b4af0..000000000 --- a/_static/coa-valuation.js +++ /dev/null @@ -1,270 +0,0 @@ -(function () { - 'use strict'; - - var data = createAtom(); - - function toKey(s, postfix) { - if (postfix) { - s += ' ' + postfix; - } - return s.replace(/[^0-9a-z ]/gi, '').toLowerCase().split(/\s+/).join('-'); - - } - var Controls = React.createClass({ - render: function () { - var state = this.props.p; - return React.DOM.div(null, operations.map(function (op) { - var label = op.get('label'), operations = op.get('operations'); - return React.DOM.label( - { - key: toKey(label), - style: {display: 'block'}, - className: (operations === state.get('active') ? 'highlight-op' : void 0) - }, - React.DOM.input({ - type: 'checkbox', - checked: state.get('operations').contains(operations), - onChange: function (e) { - if (e.target.checked) { - data.swap(function (d) { - return d.set('active', operations) - .update('operations', function (ops) { - return ops.add(operations) - }); - }); - } else { - data.swap(function (d) { - return d.set('active', null) // keep visible in state map - .update('operations', function (ops) { - return ops.remove(operations); - }) - }); - } - } - }), - " ", - label - ); - })); - } - }); - - var Chart = React.createClass({ - render: function () { - var lastop = Immutable.Map( - (this.props.p.get('active') || Immutable.List()).map(function (op) { - return [op.get('account'), op.has('credit') ? 'credit' : 'debit']; - }) - ); - return React.DOM.div( - null, - React.DOM.table( - {className: 'table table-condensed'}, - React.DOM.thead( - null, - React.DOM.tr( - null, - React.DOM.th(), - React.DOM.th({className: 'text-right'}, "Debit"), - React.DOM.th({className: 'text-right'}, "Credit"), - React.DOM.th({className: 'text-right'}, "Balance")) - ), - React.DOM.tbody( - null, - this.accounts().map(function (data) { - var highlight = lastop.get(data.get('code')); - return React.DOM.tr( - {key: data.get('code')}, - React.DOM.th(null, - data.get('level') ? '\u2001 ' : '', - data.get('code'), ' ', data.get('label')), - React.DOM.td({className: React.addons.classSet({ - 'text-right': true, - 'highlight-op': highlight === 'debit' - })}, format(data.get('debit'))), - React.DOM.td({className: React.addons.classSet({ - 'text-right': true, - 'highlight-op': highlight === 'credit' - })}, format(data.get('credit'))), - React.DOM.td( - {className: 'text-right'}, - ((data.get('debit') || data.get('credit')) - ? format(data.get('debit') - data.get('credit'), 0) - : '') - ) - ); - }) - ) - ) - ); - }, - accounts: function() { - var data = this.props.p.get('operations'); - - var totals = data.toIndexedSeq().flatten(true).reduce(function (acc, op) { - return acc - .updateIn([op.get('account'), 'debit'], function (d) { - return (d || 0) + op.get('debit', zero)(data); - }) - .updateIn([op.get('account'), 'credit'], function (c) { - return (c || 0) + op.get('credit', zero)(data); - }); - }, Immutable.Map()); - - return accounts.map(function (account) { - // for each account, add sum - return account.merge( - account.get('accounts').map(function (code) { - return totals.get(code, NULL); - }).reduce(function (acc, it) { - return acc.mergeWith(function (a, b) { return a + b; }, it, NULL); - }) - ); - }); - } - }); - data.addWatch('chart', function (k, m, prev, next) { - React.render( - React.createElement(Controls, {p: next}), - document.getElementById('chart-controls')); - React.render( - React.createElement(Chart, {p: next}), - document.querySelector('.valuation-chart')); - }); - - document.addEventListener('DOMContentLoaded', function () { - var chart = document.querySelector('.valuation-chart'); - if (!chart) { return; } - - var controls = document.createElement('div'); - controls.setAttribute('id', 'chart-controls'); - chart.parentNode.insertBefore(controls, chart); - - data.reset(Immutable.Map({ - // last-selected operation - active: null, - // set of all currently enabled operations - operations: Immutable.OrderedSet() - })); - }); - - var NULL = Immutable.Map({debit: 0, credit: 0}); - var ASSETS = { - code: 1, - label: "Assets", - BANK: { code: 11000, label: "Cash" }, - ACCOUNTS_RECEIVABLE: { code: 13100, label: "Accounts Receivable" }, - STOCK: { code: 14000, label: "Inventory" }, - RAW_MATERIALS: { code: 14100, label: "Raw Materials Inventory" }, - STOCK_OUT: { code: 14600, label: "Goods Issued Not Invoiced" }, - TAXES_PAID: { code: 19000, label: "Deferred Tax Assets" } - }; - var LIABILITIES = { - code: 2, - label: "Liabilities", - ACCOUNTS_PAYABLE: { code: 21000, label: "Accounts Payable" }, - STOCK_IN: { code: 23000, label: "Goods Received Not Purchased" }, - TAXES_PAYABLE: { code: 26200, label: "Deferred Tax Liabilities" } - }; - var EQUITY = { - code: 3, - label: "Equity", - CAPITAL: { code: 31000, label: "Common Stock" } - }; - var REVENUE = { - code: 4, - label: "Revenue", - SALES: { code: 41000, label: "Goods" }, - }; - var EXPENSES = { - code: 5, - label: "Expenses", - GOODS_SOLD: { code: 51100, label: "Cost of Goods Sold" }, - MANUFACTURING_OVERHEAD: { code: 52000, label: "Manufacturing Overhead" }, - PRICE_DIFFERENCE: { code: 53000, label: "Price Difference" } - }; - var categories = Immutable.fromJS([ASSETS, LIABILITIES, EQUITY, REVENUE, EXPENSES], function (k, v) { - return Immutable.Iterable.isIndexed(v) - ? v.toList() - : v.toOrderedMap(); - }); - var accounts = categories.toSeq().flatMap(function (cat) { - return Immutable.Seq.of(cat.set('level', 0)).concat(cat.filter(function (v, k) { - return k.toUpperCase() === k; - }).toIndexedSeq().map(function (acc) { return acc.set('level', 1) })); - }).map(function (account) { // add accounts: Seq to each account - return account.set( - 'accounts', - Immutable.Seq.of(account.get('code')).concat( - account.toIndexedSeq().map(function (val) { - return Immutable.Map.isMap(val) && val.get('code'); - }).filter(function (val) { return !!val; }) - ) - ); - }); - - var sale = 100, - cor = 50, - cor_tax = cor * 0.09, - tax = sale * 0.09, - total = sale + tax, - purchase = 52, - purchase_tax = 52 * 0.09; - var operations = Immutable.fromJS([{ - label: "Vendor Bill (PO $50, Invoice $40)", - operations: [ - {account: LIABILITIES.STOCK_IN.code, debit: constant(50)}, - {account: ASSETS.TAXES_PAID.code, debit: constant(50 * 0.09)}, - {account: LIABILITIES.ACCOUNTS_PAYABLE.code, credit: constant(50 * 1.09)}, - ] - }, { - label: "Vendor Goods Reception (PO $50, Invoice $50)", - operations: [ - {account: LIABILITIES.STOCK_IN.code, credit: constant(50)}, - {account: ASSETS.STOCK.code, debit: constant(50)}, - ] - }, { - label: "Vendor Bill (PO $48, Invoice $50)", - operations: [ - {account: EXPENSES.PRICE_DIFFERENCE.code, debit: constant(2)}, - {account: LIABILITIES.STOCK_IN.code, debit: constant(48)}, - {account: ASSETS.TAXES_PAID.code, debit: constant(50 * 0.09)}, - {account: LIABILITIES.ACCOUNTS_PAYABLE.code, credit: constant(50 * 1.09)}, - ] - }, { - label: "Vendor Goods Reception (PO $48, Invoice $50)", - operations: [ - {account: LIABILITIES.STOCK_IN.code, credit: constant(48)}, - {account: ASSETS.STOCK.code, debit: constant(48)}, - ] - }, { - label: "Customer Invoice", - operations: [ - {account: ASSETS.ACCOUNTS_RECEIVABLE.code, debit: constant(total)}, - {account: EXPENSES.GOODS_SOLD.code, debit: constant(cor)}, - {account: REVENUE.SALES.code, credit: constant(sale)}, - {account: ASSETS.STOCK_OUT.code, credit: constant(cor)}, - {account: LIABILITIES.TAXES_PAYABLE.code, credit: constant(tax)} - ] - }, { - label: "Customer Shipping", - operations: [ - {account: ASSETS.STOCK_OUT.code, debit: constant(cor)}, - {account: ASSETS.STOCK.code, credit: constant(cor)} - ] - }, { - label: "Production Order", - operations: [ - {account: ASSETS.STOCK.code, debit: constant(50)}, - {account: EXPENSES.MANUFACTURING_OVERHEAD.code, debit: constant(2)}, - {account: ASSETS.RAW_MATERIALS.code, credit: constant(52)} - ] - }]); - function constant(val) {return function () { return val; };} - var zero = constant(0); - function format(val, def) { - if (!val) { return def === undefined ? '' : def; } - if (val % 1 === 0) { return val; } - return val.toFixed(2); - } -})(); diff --git a/_static/entries.js b/_static/entries.js index 4a2ec52fe..2da8c6275 100644 --- a/_static/entries.js +++ b/_static/entries.js @@ -11,12 +11,12 @@ document.querySelector('.journal-entries')); }); document.addEventListener('DOMContentLoaded', function () { - var entries_node = document.getElementById('journal-entries'); - if (!entries_node) { return; } + var entries_section = findAncestor(document.querySelector('.journal-entries'), 'section'); + if (!entries_section) { return; } var controls = document.createElement('div'); controls.setAttribute('id', 'entries-control'); - entries_node.insertBefore(controls, entries_node.lastElementChild); + entries_section.insertBefore(controls, entries_section.lastElementChild); data.reset(entries.first()); }); @@ -151,7 +151,7 @@ explanation: [ "Revenues increase by $100", "A tax to pay at the end of the month of $9", - "The customer owns you $109", + "The customer owes $109", "The inventory is decreased by $50 (shipping of the goods)", "The cost of goods sold decreases the gross profit by $50" ], @@ -172,7 +172,7 @@ ], explanation: [ "The company receives $109 in cash", - "The customer owns you $109 less" + "The customer owes $109 less" ], configuration: [ "Cash: defined on the journal used when registering the payment, fields Default Credit Account and Default Debit Account", diff --git a/conf.py b/conf.py index a0628a39f..bc594f9da 100644 --- a/conf.py +++ b/conf.py @@ -334,7 +334,6 @@ def setup(app): app.add_javascript('misc.js') app.add_javascript('inventory.js') - app.add_javascript('coa-valuation.js') app.add_javascript('coa-valuation-continental.js') app.add_javascript('coa-valuation-anglo-saxon.js')