[ADD] explanation + interaction of journals + chart of accounts

After discussion with fp this probably isn't the direction (ish), but
want to checkpoint this in order to work on other stuff earlier in the
document, but not commit a single gigantic blob of stuff.
This commit is contained in:
Xavier Morel 2015-02-17 16:38:00 +01:00
parent 0ab12904e1
commit 931c1c8ec3
10 changed files with 5615 additions and 329 deletions

48
_static/atom.js Normal file
View File

@ -0,0 +1,48 @@
function createAtom(val, options) {
var watchers = {};
var validator = options && options.validator || function () { return true; };
function transition(next) {
if (!validator(next)) {
var err = new Error(next + " failed validation");
err.name = "AssertionError";
throw err;
}
var prev = val;
val = next;
Object.keys(watchers).forEach(function (k) {
watchers[k](k, atom, prev, next);
});
}
var atom = {
addWatch: function (key, fn) {
watchers[key] = fn;
},
removeWatch: function (key) {
delete watchers[key];
},
swap: function (fn) {
var args = [val].concat([].slice.call(arguments, 1));
transition(fn.apply(null, args));
},
reset: function (v) {
transition(v);
},
deref: function () {
return val;
},
toString: function () {
return "Atom(" + JSON.stringify(val) + ")";
}
};
return atom;
}

View File

@ -0,0 +1,355 @@
(function () {
'use strict';
// .journals
// .t-accounts
// .chart-of-accounts
// document.addEventListener('DOMContentLoaded', function () {
// React.render(
// React.createElement(CoA),
// document.querySelector('.chart-of-accounts'));
// });
var data = createAtom();
function toKey(s, postfix) {
if (postfix) {
s += ' ' + postfix;
}
return s.replace(/[^0-9a-z ]/gi, '').toLowerCase().split(/\s+/).join('-');
}
var isFulfilled = (function () {
var enabledTransactions = Immutable.Seq();
// memoize enabled ops so they don't have to be recomputed all the time
data.addWatch('enableds', function (k, m, prev, next) {
enabledTransactions = next.filter(function (v, k) {
return v.get('enabled');
}).keySeq();
});
return function isFulfilled(deps) {
var d = Immutable.Set(deps);
return d.isEmpty() || d.subtract(enabledTransactions).isEmpty();
}
})();
function isEnabled(transaction) {
var item = data.deref().get(transaction);
return item.get('enabled') && isFulfilled(item.get('depends'));
}
var Controls = React.createClass({
getInitialState: function () {
return { folded: true };
},
toggle: function () {
this.setState({folded: !this.state.folded});
},
render: function () {
return React.DOM.div(
null,
React.DOM.h4(
{ onClick: this.toggle, style: { cursor: 'pointer' } },
this.state.folded ? "\u25B8 " : "\u25BE ",
"Operations"),
this.state.folded ? undefined : this.props.p.map(function (v, k) {
return React.DOM.label(
{key: k, style: {display: 'block' } },
React.DOM.input({
type: 'checkbox',
disabled: !isFulfilled(v.get('depends')),
checked: v.get('enabled'),
onChange: function () {
data.swap(function (d) {
return d.updateIn(
[k, 'enabled'],
function (check) { return !check; });
});
}
}),
" ",
v.get('label')
);
}, this).toArray()
);
}
});
var Journal = React.createClass({
render: function () {
return React.DOM.div(
null,
React.createElement(Controls, this.props),
React.DOM.table(
{className: 'table'},
React.DOM.thead(
null,
React.DOM.tr(
null,
React.DOM.th(),
React.DOM.th({width: '20%'}, "Debit"),
React.DOM.th({width: '20%'}, "Credit")
)
),
React.DOM.tbody(
null,
this.props.p
.filter(function (v, k) { return isEnabled(k); })
.valueSeq()
.flatMap(function (tx) {
if (tx.get('operations').isEmpty()) {
return [];
}
var label = tx.get('label');
var k = toKey(label);
return tx.get('operations').toSeq().map(function (op) {
var credit = op.get('credit'), debit = op.get('debit');
return React.DOM.tr(
{key: toKey(label, op.get('account'))},
React.DOM.td(
null,
credit ? '\u2001' : '',
accounts[op.get('account')].label
),
React.DOM.td(null, debit && debit(this.props.p)),
React.DOM.td(null, credit && credit(this.props.p))
);
}, this).concat(
React.DOM.tr(
{key: k + '-label'},
React.DOM.td(
{colSpan: 3, style: {textAlign: 'center'}},
label)),
React.DOM.tr(
{key: k + '-spacer'},
React.DOM.td({colSpan: 3}, "\u00A0"))
);
}, this)
.toArray()
)
)
);
}
});
data.addWatch('journals', function (k, m, prev, next) {
React.render(
React.createElement(Journal, {p: next}),
document.querySelector('.journals')
);
});
var Chart = React.createClass({
render: function () {
return React.DOM.div(
null,
React.createElement(Controls, {p: this.props.p}),
DOM.table(
{className: 'table'},
DOM.tr(
null,
DOM.th(),
DOM.th({className: 'text-right'}, "Debit"),
DOM.th({className: 'text-right'}, "Credit"),
DOM.th({className: 'text-right'}, "Balance")),
this.accounts().map(function (data) {
return DOM.tr(
{key: data.code},
DOM.th(null,
data.level ? '\u2001 ' : '',
data.code, ' ', data.label),
DOM.td({className: 'text-right'}, data.debit),
DOM.td({className: 'text-right'}, data.credit),
DOM.td({className: 'text-right'}, data.debit - data.credit)
);
})
)
);
},
accounts: function() {
var _this = this;
var out = [];
var zero = function () { return 0; }
var data = this.props.p;
// for each operated-on account, apply all operations and save the
// resulting (debit, credit) state
var chart = data
.filter(function (v, k) { return isEnabled(k); })
.valueSeq()
.flatMap(function (v) { return v.get('operations'); })
.reduce(function (acc, op) {
// update operation's account debit and credit by adding
// operation's debit and credit to them, initialize to 0
// if not set yet
return acc
.updateIn([op.get('account'), 'debit'], 0, function (d) {
return d + op.get('debit', zero)(data);
})
.updateIn([op.get('account'), 'credit'], 0, function (c) {
return c + op.get('credit', zero)(data);
});
}, Immutable.Map());
categories.forEach(function (cat) {
var current = { level: 0, label: cat.label, code: cat.code, credit: 0, debit: 0 };
var values = accs(cat).map(function (acc) {
// If no operation has been performed on an account, 0 debit or credit
var it = chart.get(acc.code, Immutable.Map({credit: 0, debit: 0}));
var debit = it.get('debit') || 0;
var credit = it.get('credit') || 0;
current.debit += debit;
current.credit += credit;
return {
level: 1,
code: acc.code,
label: acc.label,
debit: debit,
credit: credit
}
});
values.unshift(current);
out.push.apply(out, values);
});
return out;
}
});
data.addWatch('chart', function (k, m, prev, next) {
React.render(
React.createElement(Chart, {p: next}),
document.querySelector('.chart-of-accounts'));
});
document.addEventListener('DOMContentLoaded', function () {
var sale = 100,
tax = sale * 0.09,
total = sale + tax,
refund = sale * 0.1,
purchase = 80;
data.reset(Immutable.fromJS({
customer_invoice: {
enabled: false,
label: "Customer Invoice ($100 + 9% tax)",
depends: [],
operations: [
{account: ASSETS.ACCOUNTS_RECEIVABLE.code, debit: function () { return total; }},
{account: REVENUE.SALES.code, credit: function () { return sale; }},
{account: LIABILITIES.TAXES_PAYABLE.code, credit: function () { return tax; }}
]
},
// TODO: dependencies?
customer_refund: {
enabled: false,
label: "Customer Refund 10%",
depends: ['customer_invoice'],
operations: [
{account: REVENUE.SALES.code, debit: function () { return refund; }},
{account: ASSETS.ACCOUNTS_RECEIVABLE.code, credit: function () { return refund; }}
]
},
customer_payment: {
enabled: false,
label: "Customer Payment",
depends: ['customer_invoice'],
operations: [
// TODO: depends of refund
{account: ASSETS.CASH.code, debit: function (ops) {
return ops.getIn(['customer_refund', 'enabled'])
? total - refund
: total;
}},
{account: ASSETS.ACCOUNTS_RECEIVABLE.code, credit: function (ops) {
return ops.getIn(['customer_refund', 'enabled'])
? total - refund
: total;
}}
]
},
supplier_invoice: {
enabled: false,
label: "Supplier Invoice",
depends: [],
operations: [
{account: EXPENSES.PURCHASES.code, debit: function () { return purchase; }},
{account: LIABILITIES.ACCOUNTS_PAYABLE.code, credit: function () { return purchase; }},
]
},
supplier_invoice_paid: {
enabled: false,
label: "Supplier Invoice Paid",
depends: ['supplier_invoice'],
operations: [
{account: LIABILITIES.ACCOUNTS_PAYABLE.code, debit: function () { return purchase; }},
{account: ASSETS.CASH.code, credit: function () { return purchase; }}
]
},
inventory_reception: {
enabled: false,
label: "Inventory Reception",
depends: ['supplier_invoice'],
// TODO: ???
operations: []
},
customer_delivery: {
enabled: false,
label: "Customer Delivery",
depends: ['customer_invoice', 'inventory_reception'],
// TODO: ???
operations: [],
},
taxes: {
enabled: false,
label: "Pay Taxes Due",
depends: [],
// TODO: no taxes due if no customer invoice?
operations: [
{account: LIABILITIES.TAXES_PAYABLE.code, debit: function () { return tax; }},
{account: ASSETS.CASH.code, credit: function () { return tax; }}
]
},
}));
});
var DOM = React.DOM;
var ASSETS = {
code: 1,
label: "Assets",
CASH: { code: 10100, label: "Cash" },
ACCOUNTS_RECEIVABLE: { code: 12100, label: "Accounts Receivable" }
};
var LIABILITIES = {
code: 2,
label: "Liabilities",
ACCOUNTS_PAYABLE: { code: 21000, label: "Accounts Payable" },
TAXES_PAYABLE: { code: 23100, label: "Taxes Payable" }
};
var REVENUE = {
code: 4,
label: "Revenue",
SALES: { code: 40100, label: "Sales" }
};
var EXPENSES = {
code: 5,
label: "Expenses",
PURCHASES: { code: 50100, label: "Purchases" }
};
var categories = [ASSETS, LIABILITIES, REVENUE, EXPENSES];
var accounts = (function () {
var acs = {};
categories.forEach(function (cat) {
acs[cat.code] = cat;
accs(cat).forEach(function (acc) {
acs[acc.code] = acc;
});
});
return acs;
})();
function accs(category) {
var out = [];
for(var k in category) {
if (k.toUpperCase() === k) {
out.push(category[k]);
}
}
return out;
}
})();

View File

@ -1,46 +1,22 @@
(function () {
'use strict';
var Table = React.createClass({
getInitialState: function () {
return {text: [], counter: 0};
},
render: function () {
return React.createElement(
'div', null,
React.createElement('button', {
style: {color: 'red'},
onClick: this.handleClick,
}, "Click Me!"),
React.createElement('ul', null, this.state.text.map(function (item) {
return React.createElement(
'li', null, "This is number ", item);
}))
);
},
handleClick: function () {
this.setState({
text: this.state.text.concat([this.state.counter]),
counter: this.state.counter + 1,
})
},
});
function item(it) {
if (it.credit && it.debit) {
throw new Error("A journal item can't have both credit and debit, got " + JSON.stringify(it));
}
return React.createElement(
'tr', null,
React.createElement('td', null, (it.credit ? '\u2001' : '') + it.label),
React.createElement('td', null, it.debit),
React.createElement('td', null, it.credit)
return React.DOM.tr(
{key: it.label.toLowerCase().split(' ').concat(
['debit', it.debit, 'credit', it.credit]
).join('-')
},
React.DOM.td(null, (it.credit ? '\u2001' : '') + it.label),
React.DOM.td(null, it.debit),
React.DOM.td(null, it.credit)
);
}
function spacer() {
return React.createElement(
'tr', null, React.createElement(
'td', {colSpan: 3}, "\u00A0"));
function spacer(key) {
return React.DOM.tr({key: 'spacer-' + key}, React.DOM.td({colSpan: 3}, "\u00A0"));
}
var ClotureTable = React.createClass({
@ -68,18 +44,18 @@
},
render: function () {
return React.createElement(
'div', null,
return React.DOM.div(
null,
this.controls(),
React.createElement(
'table', {className: 'table'},
React.DOM.table(
{className: 'table'},
this.makeHeader(),
React.createElement(
'tbody', null,
React.DOM.tbody(
null,
this.revenues(this.state.revenues),
spacer(),
spacer('table-1'),
this.expenses(this.state.expenses),
spacer(),
spacer('table-2'),
this.closure({
dividends: this.state.dividends,
income: this.income(),
@ -89,13 +65,13 @@
);
},
makeHeader: function () {
return React.createElement(
'thead', null,
React.createElement(
'tr', null,
React.createElement('th'),
React.createElement('th', null, "Debit"),
React.createElement('th', null, "Credit")
return React.DOM.thead(
null,
React.DOM.tr(
null,
React.DOM.th(),
React.DOM.th(null, "Debit"),
React.DOM.th(null, "Credit")
)
);
},
@ -103,12 +79,12 @@
controls: function () {
var _this = this;
return [
React.createElement(
'fieldset', null,
React.createElement('legend', null, "Income"),
React.createElement(
'label', null, "Cash ",
React.createElement('input', {
React.DOM.fieldset(
{key: 'income'},
React.DOM.legend(null, "Income"),
React.DOM.label(
null, "Cash ",
React.DOM.input({
type: 'number',
step: 1,
value: this.state.revenues.cash,
@ -123,9 +99,10 @@
}
})
),
React.createElement(
'label', null, " Accounts Receivable ",
React.createElement('input', {
' ',
React.DOM.label(
null, " Accounts Receivable ",
React.DOM.input({
type: 'number',
step: 1,
value: this.state.revenues.receivable,
@ -141,12 +118,12 @@
})
)
),
React.createElement(
'fieldset', null,
React.createElement('legend', null, "Expenses"),
React.createElement(
'label', null, "Cash ",
React.createElement('input', {
React.DOM.fieldset(
{key: 'expenses'},
React.DOM.legend(null, "Expenses"),
React.DOM.label(
null, "Cash ",
React.DOM.input({
type: 'number',
step: 1,
value: this.state.expenses.cash,
@ -161,9 +138,10 @@
}
})
),
React.createElement(
'label', null, " Accounts Payable ",
React.createElement('input', {
' ',
React.DOM.label(
null, " Accounts Payable ",
React.DOM.input({
type: 'number',
step: 1,
value: this.state.expenses.payable,
@ -179,13 +157,13 @@
})
)
),
React.createElement(
'fieldset', null,
React.createElement('legend', null, "Dividends"),
React.createElement(
'label', null,
React.DOM.fieldset(
{key: 'dividends'},
React.DOM.legend(null, "Dividends"),
React.DOM.label(
null,
"Ratio (from retained earnings) ",
React.createElement('input', {
React.DOM.input({
type: 'range',
min: 0,
max: 1,
@ -220,7 +198,7 @@
}
if (dividends) {
result = result.concat([
spacer(),
spacer('closure'),
item({label: "Retained Earnings", debit: dividends}),
item({label: "Dividends Payable", credit: dividends})
]);
@ -233,13 +211,10 @@
item({label: "Cash", debit: props.cash}),
item({label: "Accounts Receivable", debit: props.receivable}),
item({label: "Revenue", credit: total}),
React.createElement(
'tr', null, React.createElement(
'td', {colSpan: 3},
"\u2001\u2001Consolidation of revenues"
)
),
spacer(),
React.DOM.tr({key: 'revenue-notes'}, React.DOM.td(
{colSpan: 3},
"\u2001\u2001Consolidation of revenues")),
spacer('revenues'),
item({label: "Revenue", debit: total}),
item({label: "Income Summary", credit: total})
];
@ -250,13 +225,13 @@
item({label: "Expenses", debit: total}),
item({label: "Cash", credit: props.cash}),
item({label: "Accounts Payable", credit: props.payable}),
React.createElement(
'tr', null, React.createElement(
'td', {colSpan: 3},
React.DOM.tr(
{key: 'expenses-note'}, React.DOM.td(
{colSpan: 3},
"\u2001\u2001Consolidation of expenses"
)
),
spacer(),
spacer('expenses'),
item({label: "Income Summary", debit: total}),
item({label: "Expenses", credit: total})
];

4856
_static/immutable.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -68,8 +68,13 @@ def visit_table(self, node):
self._table_row_index = 0
self.context.append(self.compact_p)
self.compact_p = True
classes = ' '.join({'table', self.settings.table_style}).strip()
self.body.append(self.starttag(node, 'table', CLASS=classes))
classes = {self.settings.table_style}
node_classes = node.get('classes', [])
if 'no-table' in node_classes: node_classes.remove('no-table')
else: classes.add('table')
self.body.append(self.starttag(node, 'table', CLASS=' '.join(classes).strip()))
def starttag_data(self, node, tagname, suffix='\n', empty=False, **attributes):
attributes.update(

View File

@ -1 +1 @@
@import "style.css";
@import url("style.css");

View File

@ -6811,58 +6811,58 @@ td.field-body > ul {
margin-bottom: 2em;
}
@media (min-width: 992px) {
.stripe .section > *,
.stripe .section > .force-left {
.stripe .section:not(.force-right) > *,
.stripe .section:not(.force-right) > .force-left {
width: 49%;
float: left;
clear: left;
}
.stripe .section > .force-right {
.stripe .section:not(.force-right) > .force-right {
padding-left: 1em;
padding-right: 1em;
}
.stripe .section > .force-right,
.stripe .section > [class*=highlight] {
.stripe .section:not(.force-right) > .force-right,
.stripe .section:not(.force-right) > [class*=highlight] {
float: none;
clear: none;
margin-left: 50%;
width: 50%;
color: #eeeeee;
}
.stripe .section > .force-right legend,
.stripe .section > [class*=highlight] legend {
.stripe .section:not(.force-right) > .force-right legend,
.stripe .section:not(.force-right) > [class*=highlight] legend {
color: inherit;
}
.stripe .section > .force-right input,
.stripe .section > [class*=highlight] input {
.stripe .section:not(.force-right) > .force-right input,
.stripe .section:not(.force-right) > [class*=highlight] input {
color: inherit;
background-color: #555555;
}
.stripe .section > .force-right a,
.stripe .section > [class*=highlight] a {
.stripe .section:not(.force-right) > .force-right a,
.stripe .section:not(.force-right) > [class*=highlight] a {
color: #d9a8cc;
}
.stripe .section > .force-right code,
.stripe .section > [class*=highlight] code,
.stripe .section > .force-right .literal,
.stripe .section > [class*=highlight] .literal {
.stripe .section:not(.force-right) > .force-right code,
.stripe .section:not(.force-right) > [class*=highlight] code,
.stripe .section:not(.force-right) > .force-right .literal,
.stripe .section:not(.force-right) > [class*=highlight] .literal {
color: #f9f2f4;
background-color: #555555;
}
.stripe .section > .force-right:not(.highlight-json) .highlight,
.stripe .section > [class*=highlight]:not(.highlight-json) .highlight {
.stripe .section:not(.force-right) > .force-right:not(.highlight-json) .highlight,
.stripe .section:not(.force-right) > [class*=highlight]:not(.highlight-json) .highlight {
border-bottom-color: #777777;
}
.stripe .section > .force-right.admonition,
.stripe .section > [class*=highlight].admonition {
.stripe .section:not(.force-right) > .force-right.admonition,
.stripe .section:not(.force-right) > [class*=highlight].admonition {
margin-left: 51%;
width: 49%;
border-top-color: #777777;
border-bottom-color: #777777;
border-right-color: #777777;
}
.stripe .section > .force-right .highlight,
.stripe .section > [class*=highlight] .highlight {
.stripe .section:not(.force-right) > .force-right .highlight,
.stripe .section:not(.force-right) > [class*=highlight] .highlight {
border-color: #555555;
border-style: solid;
border-width: 1px 0;
@ -6939,302 +6939,302 @@ td.field-body > ul {
/* Name.Variable.Instance */
/* Literal.Number.Integer.Long */
}
.stripe .section > .force-right .highlight .lineno,
.stripe .section > [class*=highlight] .highlight .lineno {
.stripe .section:not(.force-right) > .force-right .highlight .lineno,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .lineno {
color: #586e75;
}
.stripe .section > .force-right .highlight .c,
.stripe .section > [class*=highlight] .highlight .c {
.stripe .section:not(.force-right) > .force-right .highlight .c,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .c {
color: #586e75;
}
.stripe .section > .force-right .highlight .err,
.stripe .section > [class*=highlight] .highlight .err {
.stripe .section:not(.force-right) > .force-right .highlight .err,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .err {
color: #cccccc;
}
.stripe .section > .force-right .highlight .g,
.stripe .section > [class*=highlight] .highlight .g {
.stripe .section:not(.force-right) > .force-right .highlight .g,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .g {
color: #cccccc;
}
.stripe .section > .force-right .highlight .k,
.stripe .section > [class*=highlight] .highlight .k {
.stripe .section:not(.force-right) > .force-right .highlight .k,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .k {
color: #859900;
}
.stripe .section > .force-right .highlight .l,
.stripe .section > [class*=highlight] .highlight .l {
.stripe .section:not(.force-right) > .force-right .highlight .l,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .l {
color: #cccccc;
}
.stripe .section > .force-right .highlight .n,
.stripe .section > [class*=highlight] .highlight .n {
.stripe .section:not(.force-right) > .force-right .highlight .n,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .n {
color: #cccccc;
}
.stripe .section > .force-right .highlight .o,
.stripe .section > [class*=highlight] .highlight .o {
.stripe .section:not(.force-right) > .force-right .highlight .o,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .o {
color: #859900;
}
.stripe .section > .force-right .highlight .x,
.stripe .section > [class*=highlight] .highlight .x {
.stripe .section:not(.force-right) > .force-right .highlight .x,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .x {
color: #cb4b16;
}
.stripe .section > .force-right .highlight .p,
.stripe .section > [class*=highlight] .highlight .p {
.stripe .section:not(.force-right) > .force-right .highlight .p,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .p {
color: #cccccc;
}
.stripe .section > .force-right .highlight .cm,
.stripe .section > [class*=highlight] .highlight .cm {
.stripe .section:not(.force-right) > .force-right .highlight .cm,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .cm {
color: #586e75;
}
.stripe .section > .force-right .highlight .cp,
.stripe .section > [class*=highlight] .highlight .cp {
.stripe .section:not(.force-right) > .force-right .highlight .cp,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .cp {
color: #859900;
}
.stripe .section > .force-right .highlight .c1,
.stripe .section > [class*=highlight] .highlight .c1 {
.stripe .section:not(.force-right) > .force-right .highlight .c1,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .c1 {
color: #586e75;
}
.stripe .section > .force-right .highlight .cs,
.stripe .section > [class*=highlight] .highlight .cs {
.stripe .section:not(.force-right) > .force-right .highlight .cs,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .cs {
color: #859900;
}
.stripe .section > .force-right .highlight .gd,
.stripe .section > [class*=highlight] .highlight .gd {
.stripe .section:not(.force-right) > .force-right .highlight .gd,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gd {
color: #2aa198;
}
.stripe .section > .force-right .highlight .ge,
.stripe .section > [class*=highlight] .highlight .ge {
.stripe .section:not(.force-right) > .force-right .highlight .ge,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ge {
color: #cccccc;
font-style: italic;
}
.stripe .section > .force-right .highlight .gr,
.stripe .section > [class*=highlight] .highlight .gr {
.stripe .section:not(.force-right) > .force-right .highlight .gr,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gr {
color: #dc322f;
}
.stripe .section > .force-right .highlight .gh,
.stripe .section > [class*=highlight] .highlight .gh {
.stripe .section:not(.force-right) > .force-right .highlight .gh,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gh {
color: #cb4b16;
}
.stripe .section > .force-right .highlight .gi,
.stripe .section > [class*=highlight] .highlight .gi {
.stripe .section:not(.force-right) > .force-right .highlight .gi,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gi {
color: #859900;
}
.stripe .section > .force-right .highlight .go,
.stripe .section > [class*=highlight] .highlight .go {
.stripe .section:not(.force-right) > .force-right .highlight .go,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .go {
color: #cccccc;
}
.stripe .section > .force-right .highlight .gp,
.stripe .section > [class*=highlight] .highlight .gp {
.stripe .section:not(.force-right) > .force-right .highlight .gp,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gp {
color: #cccccc;
}
.stripe .section > .force-right .highlight .gs,
.stripe .section > [class*=highlight] .highlight .gs {
.stripe .section:not(.force-right) > .force-right .highlight .gs,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gs {
color: #cccccc;
font-weight: bold;
}
.stripe .section > .force-right .highlight .gu,
.stripe .section > [class*=highlight] .highlight .gu {
.stripe .section:not(.force-right) > .force-right .highlight .gu,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gu {
color: #cb4b16;
}
.stripe .section > .force-right .highlight .gt,
.stripe .section > [class*=highlight] .highlight .gt {
.stripe .section:not(.force-right) > .force-right .highlight .gt,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gt {
color: #cccccc;
}
.stripe .section > .force-right .highlight .kc,
.stripe .section > [class*=highlight] .highlight .kc {
.stripe .section:not(.force-right) > .force-right .highlight .kc,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kc {
color: #cb4b16;
}
.stripe .section > .force-right .highlight .kd,
.stripe .section > [class*=highlight] .highlight .kd {
.stripe .section:not(.force-right) > .force-right .highlight .kd,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kd {
color: #268bd2;
}
.stripe .section > .force-right .highlight .kn,
.stripe .section > [class*=highlight] .highlight .kn {
.stripe .section:not(.force-right) > .force-right .highlight .kn,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kn {
color: #859900;
}
.stripe .section > .force-right .highlight .kp,
.stripe .section > [class*=highlight] .highlight .kp {
.stripe .section:not(.force-right) > .force-right .highlight .kp,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kp {
color: #859900;
}
.stripe .section > .force-right .highlight .kr,
.stripe .section > [class*=highlight] .highlight .kr {
.stripe .section:not(.force-right) > .force-right .highlight .kr,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kr {
color: #268bd2;
}
.stripe .section > .force-right .highlight .kt,
.stripe .section > [class*=highlight] .highlight .kt {
.stripe .section:not(.force-right) > .force-right .highlight .kt,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kt {
color: #dc322f;
}
.stripe .section > .force-right .highlight .ld,
.stripe .section > [class*=highlight] .highlight .ld {
.stripe .section:not(.force-right) > .force-right .highlight .ld,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ld {
color: #cccccc;
}
.stripe .section > .force-right .highlight .m,
.stripe .section > [class*=highlight] .highlight .m {
.stripe .section:not(.force-right) > .force-right .highlight .m,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .m {
color: #2aa198;
}
.stripe .section > .force-right .highlight .s,
.stripe .section > [class*=highlight] .highlight .s {
.stripe .section:not(.force-right) > .force-right .highlight .s,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .s {
color: #2aa198;
}
.stripe .section > .force-right .highlight .na,
.stripe .section > [class*=highlight] .highlight .na {
.stripe .section:not(.force-right) > .force-right .highlight .na,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .na {
color: #cccccc;
}
.stripe .section > .force-right .highlight .nb,
.stripe .section > [class*=highlight] .highlight .nb {
.stripe .section:not(.force-right) > .force-right .highlight .nb,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nb {
color: #b58900;
}
.stripe .section > .force-right .highlight .nc,
.stripe .section > [class*=highlight] .highlight .nc {
.stripe .section:not(.force-right) > .force-right .highlight .nc,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nc {
color: #268bd2;
}
.stripe .section > .force-right .highlight .no,
.stripe .section > [class*=highlight] .highlight .no {
.stripe .section:not(.force-right) > .force-right .highlight .no,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .no {
color: #cb4b16;
}
.stripe .section > .force-right .highlight .nd,
.stripe .section > [class*=highlight] .highlight .nd {
.stripe .section:not(.force-right) > .force-right .highlight .nd,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nd {
color: #268bd2;
}
.stripe .section > .force-right .highlight .ni,
.stripe .section > [class*=highlight] .highlight .ni {
.stripe .section:not(.force-right) > .force-right .highlight .ni,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ni {
color: #cb4b16;
}
.stripe .section > .force-right .highlight .ne,
.stripe .section > [class*=highlight] .highlight .ne {
.stripe .section:not(.force-right) > .force-right .highlight .ne,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ne {
color: #cb4b16;
}
.stripe .section > .force-right .highlight .nf,
.stripe .section > [class*=highlight] .highlight .nf {
.stripe .section:not(.force-right) > .force-right .highlight .nf,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nf {
color: #268bd2;
}
.stripe .section > .force-right .highlight .nl,
.stripe .section > [class*=highlight] .highlight .nl {
.stripe .section:not(.force-right) > .force-right .highlight .nl,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nl {
color: #cccccc;
}
.stripe .section > .force-right .highlight .nn,
.stripe .section > [class*=highlight] .highlight .nn {
.stripe .section:not(.force-right) > .force-right .highlight .nn,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nn {
color: #cccccc;
}
.stripe .section > .force-right .highlight .nx,
.stripe .section > [class*=highlight] .highlight .nx {
.stripe .section:not(.force-right) > .force-right .highlight .nx,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nx {
color: #cccccc;
}
.stripe .section > .force-right .highlight .py,
.stripe .section > [class*=highlight] .highlight .py {
.stripe .section:not(.force-right) > .force-right .highlight .py,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .py {
color: #cccccc;
}
.stripe .section > .force-right .highlight .nt,
.stripe .section > [class*=highlight] .highlight .nt {
.stripe .section:not(.force-right) > .force-right .highlight .nt,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nt {
color: #268bd2;
}
.stripe .section > .force-right .highlight .nv,
.stripe .section > [class*=highlight] .highlight .nv {
.stripe .section:not(.force-right) > .force-right .highlight .nv,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nv {
color: #268bd2;
}
.stripe .section > .force-right .highlight .ow,
.stripe .section > [class*=highlight] .highlight .ow {
.stripe .section:not(.force-right) > .force-right .highlight .ow,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ow {
color: #859900;
}
.stripe .section > .force-right .highlight .w,
.stripe .section > [class*=highlight] .highlight .w {
.stripe .section:not(.force-right) > .force-right .highlight .w,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .w {
color: #cccccc;
}
.stripe .section > .force-right .highlight .mf,
.stripe .section > [class*=highlight] .highlight .mf {
.stripe .section:not(.force-right) > .force-right .highlight .mf,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .mf {
color: #2aa198;
}
.stripe .section > .force-right .highlight .mh,
.stripe .section > [class*=highlight] .highlight .mh {
.stripe .section:not(.force-right) > .force-right .highlight .mh,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .mh {
color: #2aa198;
}
.stripe .section > .force-right .highlight .mi,
.stripe .section > [class*=highlight] .highlight .mi {
.stripe .section:not(.force-right) > .force-right .highlight .mi,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .mi {
color: #2aa198;
}
.stripe .section > .force-right .highlight .mo,
.stripe .section > [class*=highlight] .highlight .mo {
.stripe .section:not(.force-right) > .force-right .highlight .mo,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .mo {
color: #2aa198;
}
.stripe .section > .force-right .highlight .sb,
.stripe .section > [class*=highlight] .highlight .sb {
.stripe .section:not(.force-right) > .force-right .highlight .sb,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sb {
color: #586e75;
}
.stripe .section > .force-right .highlight .sc,
.stripe .section > [class*=highlight] .highlight .sc {
.stripe .section:not(.force-right) > .force-right .highlight .sc,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sc {
color: #2aa198;
}
.stripe .section > .force-right .highlight .sd,
.stripe .section > [class*=highlight] .highlight .sd {
.stripe .section:not(.force-right) > .force-right .highlight .sd,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sd {
color: #cccccc;
}
.stripe .section > .force-right .highlight .s2,
.stripe .section > [class*=highlight] .highlight .s2 {
.stripe .section:not(.force-right) > .force-right .highlight .s2,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .s2 {
color: #2aa198;
}
.stripe .section > .force-right .highlight .se,
.stripe .section > [class*=highlight] .highlight .se {
.stripe .section:not(.force-right) > .force-right .highlight .se,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .se {
color: #cb4b16;
}
.stripe .section > .force-right .highlight .sh,
.stripe .section > [class*=highlight] .highlight .sh {
.stripe .section:not(.force-right) > .force-right .highlight .sh,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sh {
color: #cccccc;
}
.stripe .section > .force-right .highlight .si,
.stripe .section > [class*=highlight] .highlight .si {
.stripe .section:not(.force-right) > .force-right .highlight .si,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .si {
color: #2aa198;
}
.stripe .section > .force-right .highlight .sx,
.stripe .section > [class*=highlight] .highlight .sx {
.stripe .section:not(.force-right) > .force-right .highlight .sx,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sx {
color: #2aa198;
}
.stripe .section > .force-right .highlight .sr,
.stripe .section > [class*=highlight] .highlight .sr {
.stripe .section:not(.force-right) > .force-right .highlight .sr,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sr {
color: #dc322f;
}
.stripe .section > .force-right .highlight .s1,
.stripe .section > [class*=highlight] .highlight .s1 {
.stripe .section:not(.force-right) > .force-right .highlight .s1,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .s1 {
color: #2aa198;
}
.stripe .section > .force-right .highlight .ss,
.stripe .section > [class*=highlight] .highlight .ss {
.stripe .section:not(.force-right) > .force-right .highlight .ss,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ss {
color: #2aa198;
}
.stripe .section > .force-right .highlight .bp,
.stripe .section > [class*=highlight] .highlight .bp {
.stripe .section:not(.force-right) > .force-right .highlight .bp,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .bp {
color: #268bd2;
}
.stripe .section > .force-right .highlight .vc,
.stripe .section > [class*=highlight] .highlight .vc {
.stripe .section:not(.force-right) > .force-right .highlight .vc,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .vc {
color: #268bd2;
}
.stripe .section > .force-right .highlight .vg,
.stripe .section > [class*=highlight] .highlight .vg {
.stripe .section:not(.force-right) > .force-right .highlight .vg,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .vg {
color: #268bd2;
}
.stripe .section > .force-right .highlight .vi,
.stripe .section > [class*=highlight] .highlight .vi {
.stripe .section:not(.force-right) > .force-right .highlight .vi,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .vi {
color: #268bd2;
}
.stripe .section > .force-right .highlight .il,
.stripe .section > [class*=highlight] .highlight .il {
.stripe .section:not(.force-right) > .force-right .highlight .il,
.stripe .section:not(.force-right) > [class*=highlight] .highlight .il {
color: #2aa198;
}
.stripe .body > .section > .section {
border-top: 1px solid #eeeeee;
}
.stripe .section > h1,
.stripe .section > h2,
.stripe .section > h3,
.stripe .section > h4,
.stripe .section > h5,
.stripe .section > h6 {
.stripe .section:not(.force-right) > h1,
.stripe .section:not(.force-right) > h2,
.stripe .section:not(.force-right) > h3,
.stripe .section:not(.force-right) > h4,
.stripe .section:not(.force-right) > h5,
.stripe .section:not(.force-right) > h6 {
max-width: 50%;
}
.stripe .section > h1,
.stripe .section > h2,
.stripe .section > h3,
.stripe .section > h4,
.stripe .section > h5,
.stripe .section > h6,
.stripe .section > .section {
.stripe .section:not(.force-right) > h1,
.stripe .section:not(.force-right) > h2,
.stripe .section:not(.force-right) > h3,
.stripe .section:not(.force-right) > h4,
.stripe .section:not(.force-right) > h5,
.stripe .section:not(.force-right) > h6,
.stripe .section > .section:not(.force-right) {
position: relative;
width: auto;
float: none;

View File

@ -610,19 +610,19 @@ td.field-body {
// === columning only on medium+ ===
@media (min-width: @screen-md-min) {
// column 1
.section > *,
.section > .force-left {
.section:not(.force-right) > *,
.section:not(.force-right) > .force-left {
width: 49%;
float: left;
clear: left;
}
// column 2
.section > .force-right {
.section:not(.force-right) > .force-right {
padding-left: 1em;
padding-right: 1em;
}
.section > .force-right,
.section > [class*=highlight] {
.section:not(.force-right) > .force-right,
.section:not(.force-right) > [class*=highlight] {
float: none;
clear: none;
margin-left: 50%;
@ -735,13 +735,16 @@ td.field-body {
.body > .section > .section {
border-top: 1px solid @color-right;
}
.section > h1, .section > h2, .section > h3, .section > h4, .section > h5,
.section > h6 {
.section:not(.force-right) > h1, .section:not(.force-right) > h2,
.section:not(.force-right) > h3, .section:not(.force-right) > h4,
.section:not(.force-right) > h5, .section:not(.force-right) > h6 {
max-width: 50%;
}
.section > h1, .section > h2, .section > h3, .section > h4, .section > h5,
.section > h6, .section > .section {
.section:not(.force-right) > h1, .section:not(.force-right) > h2,
.section:not(.force-right) > h3, .section:not(.force-right) > h4,
.section:not(.force-right) > h5, .section:not(.force-right) > h6,
.section > .section:not(.force-right) {
position: relative;
width: auto;
float: none;

View File

@ -265,5 +265,8 @@ texinfo_documents = [
#texinfo_no_detailmenu = False
def setup(app):
app.add_javascript('atom.js')
app.add_javascript('immutable.js')
app.add_javascript('react.js')
app.add_javascript('accounting.js')
app.add_javascript('chart-of-accounts.js')
app.add_javascript('fiscalyear.js')

159
index.rst
View File

@ -52,35 +52,37 @@ them being consumed for the company to "work".
What is owned has been financed through debts to reimburse or acquired
assets (profits, capical).
Journal Entries
===============
Journals
========
The chart of accounts is a list of P&L and balance sheet accounts. Journal
entries record debits and credits to accounts. For instance, for a banking
account:
* debit 500€ (500€ income)
* Credit 200€ (paid out 200€)
* Balance: 300€ (300€ left on the account)
Operations on an account are sometimes represented by T-accounts.
Accounting journals record business financial transactions as *journal
entries* before posting entries to account-specific ledgers.
To each financial document (invoice, bank statement, receipt, loan agreement)
corresponds a *Journal Entry*, which is itself composed of multiple *journal
items*. Each journal item represents a single change to a single account, but
entries must be balanced, the sum of all credits in an entry must be equal to
the sum of all debits.
corresponds a *journal entry*.
Example: a house doesn't get owned out of thin air, it must have been paid
(conversion of an asset to an other asset, no change in wealth) and that money
generally comes from a loan (liability to asset).
Each journal entry is composed of multiple *journal items*.
Each journal item represents a single change (debit or credit) to a single
account.
In *double-entry bookkeeping*, a journal entry must be balanced by having the
sum of all its debits be equal to the sum of all its credits. A journal entry
is thus composed of at least two *journal items*, a debit and a credit, and
involves at least two accounts.
Conventionally, all *debits* in journal entries are written first, with the
account name flush with their column, followed by all *credits* indented
slightly (to match the position/offset of the corresponding amount
column). Journal entries can include a note providing context for the
transaction.
A journal entry almost always corresponds to a separate justifying document:
invoice, pay slip, …. Financial audits may include matching "hard" evidence to
journal entries.
Journal entries are generally triaged into **accounting journals** based on
their classification or frequency. Common accounting journals are:
Journal entries are generally triaged into accounting journals based on their
classification or frequency. Common accounting journals are:
* Sales journals with all client transactions
* Purchase journals with supplier transactions
@ -89,30 +91,56 @@ their classification or frequency. Common accounting journals are:
.. rst-class:: force-right
.. todo::
Transactions
------------
Switch: European | Storno | Anglo-Saxon
.. h:div:: journals
Balance = Debit - Credit
needs javascript
By convention, on financial accounts.
Ledgers
=======
Active Documents To Show Impact:
Customer Invoice $100 + 9% tax
Customer Refund
Customer Payment
Customer Delivery
Pay Taxes Due
Supplier Invoice (an Asset)
Supplier Invoice (an Expense)
Inventory Reception
Where journals are general transaction logs (usually contextual on transaction
type or frequency), ledgers are change logs for a single account (or as a
central repository for all account changes when it comes to *general
ledgers*).
* provide a bunch of pre-defined operations (customisable accounts?)
* some operations enable further operations (e.g. a customer can only pay
if he got an invoice)
* selected operations get reflected on the ledger
* update the chart of accounts with content of each account?
* provide multiple GAAP accounts things?
.. todo:: is there a concept of ledger in Odoo?
Ledgers are collections of T-accounts which summarize operations affecting a
specific account. T-accounts are shaped thus because they are shaped as a T,
with debits under the left arm and all credits under the right arm of the T:
T-accounts can also be used as temporary scratch space when preparing
transactions by hand.
.. rst-class:: force-right
T-accounts for the transactions
-------------------------------
.. h:div:: t-accounts
needs javascript
Chart of Accounts
=================
The **chart of accounts** lists all balance sheet (assets, liabilities) and
P&L (revenue, expense) accounts. These accounts are used to organize and
classify the finances of the company to better understand the company's
financial state, and the chart can be used to get a snapshot of a company's
financial period.
.. rst-class:: force-right
Balance = debit - credit
------------------------
.. h:div:: chart-of-accounts
Requires javascript
Debit and credit
================
@ -135,31 +163,39 @@ that adding money to a bank account is a *debit* (in accounting terms):
credit on the receivable
* the invoice must thus be a debit on receivable and a credit on income.
.. h:div:: force-right
.. rst-class:: force-right
Follow the money:
Follow the money
----------------
1. Customer Payment: Increase bank account, it's a Debit. Thus, the
receivable is a credit.
1. Customer Payment: Increase bank account, it's a Debit. Thus, the receivable
is a credit.
================== ===== ======
\ Debit Credit
================== ===== ======
Bank Account 109€
Account Receivable 109€
================== ===== ======
+---------------------+-----+------+
| |Debit|Credit|
+=====================+=====+======+
|Bank Account | 109 | |
+---------------------+-----+------+
|| Account Receivable| | 109 |
+---------------------+-----+------+
|| Payment by customer XXX |
+---------------------+-----+------+
2. As the invoice should compensate the receivable
2. As the invoice should compensate the receivable
================== ===== ======
\ Debit Credit
================== ===== ======
Account Receivable 109€
Income 100€
Taxes 9€
================== ===== ======
+---------------------+-----+------+
| |Debit|Credit|
+=====================+=====+======+
|Account Receivable | 109 | |
+---------------------+-----+------+
|| Income | | 100 |
+---------------------+-----+------+
|| Taxes | | 9 |
+---------------------+-----+------+
|| Invoicing of customer XXX |
+---------------------+-----+------+
→ The income should be negative (a credit)
→ The income should be negative (a credit)
Closing Fiscal Years
====================
@ -179,7 +215,12 @@ E.g. if a company had 1000€ revenue and 600€ expenses it had a 400€ net
income. At FY closure the following closure operation is applied: net income
(debit 400) to retained earnings (credit 400).
.. h:div:: force-right fiscal-year-closing
.. rst-class:: force-right
Ledger for a fiscal year
------------------------
.. h:div:: fiscal-year-closing
+--------------------------+-------------------------+-------------------------+
| |Debit |Credit |