documentation/_static/fiscalyear.js
Xavier Morel 931c1c8ec3 [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.
2015-02-17 16:38:00 +01:00

248 lines
9.5 KiB
JavaScript

(function () {
'use strict';
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.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(key) {
return React.DOM.tr({key: 'spacer-' + key}, React.DOM.td({colSpan: 3}, "\u00A0"));
}
var ClotureTable = React.createClass({
getInitialState: function () {
return {
revenues: {
cash: 800,
receivable: 200,
},
expenses: {
cash: 100,
payable: 500,
},
// don't ignore/break invalid values
dividends: "0.5",
};
},
income: function () {
return (
(this.state.revenues.cash + this.state.revenues.receivable)
-
(this.state.expenses.cash + this.state.expenses.payable)
);
},
render: function () {
return React.DOM.div(
null,
this.controls(),
React.DOM.table(
{className: 'table'},
this.makeHeader(),
React.DOM.tbody(
null,
this.revenues(this.state.revenues),
spacer('table-1'),
this.expenses(this.state.expenses),
spacer('table-2'),
this.closure({
dividends: this.state.dividends,
income: this.income(),
})
)
)
);
},
makeHeader: function () {
return React.DOM.thead(
null,
React.DOM.tr(
null,
React.DOM.th(),
React.DOM.th(null, "Debit"),
React.DOM.th(null, "Credit")
)
);
},
controls: function () {
var _this = this;
return [
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,
onChange: function (e) {
var val = e.target.value;
_this.setState({
revenues: {
cash: val ? parseInt(val, 10) : 0,
receivable: _this.state.revenues.receivable
}
});
}
})
),
' ',
React.DOM.label(
null, " Accounts Receivable ",
React.DOM.input({
type: 'number',
step: 1,
value: this.state.revenues.receivable,
onChange: function (e) {
var val = e.target.value;
_this.setState({
revenues: {
cash: _this.state.revenues.cash,
receivable: val ? parseInt(val, 10) : 0,
}
})
}
})
)
),
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,
onChange: function (e) {
var val = e.target.value;
_this.setState({
expenses: {
cash: val ? parseInt(val, 10): 0,
payable: _this.state.expenses.payable
}
})
}
})
),
' ',
React.DOM.label(
null, " Accounts Payable ",
React.DOM.input({
type: 'number',
step: 1,
value: this.state.expenses.payable,
onChange: function (e) {
var val = e.target.value;
_this.setState({
expenses: {
cash: _this.state.expenses.cash,
payable: val ? parseInt(val, 10) : 0
}
})
}
})
)
),
React.DOM.fieldset(
{key: 'dividends'},
React.DOM.legend(null, "Dividends"),
React.DOM.label(
null,
"Ratio (from retained earnings) ",
React.DOM.input({
type: 'range',
min: 0,
max: 1,
step: 0.01,
value: this.state.dividends,
style: { display: 'inline-block' },
onChange: function (e) {
_this.setState({dividends: e.target.value});
}
})
)
)
];
},
// components must return a single root which isn't practical here
closure: function (props) {
var result, income = Math.abs(props.income), dividends = 0;
if (props.income > 0) {
// credit retained earnings from income, then credit dividends
// from retained
var dividends = parseInt(income * Math.max(0, Math.min(1, parseFloat(props.dividends))));
result = [
item({label: "Income Summary", debit: income}),
item({label: "Retained Earnings", credit: income}),
];
} else {
// debit retained earnings, no dividends
result = [
item({label: "Retained Earnings", debit: income}),
item({label: "Income Summary", credit: income}),
];
}
if (dividends) {
result = result.concat([
spacer('closure'),
item({label: "Retained Earnings", debit: dividends}),
item({label: "Dividends Payable", credit: dividends})
]);
}
return result;
},
revenues: function (props) {
var total = props.cash + props.receivable;
return [
item({label: "Cash", debit: props.cash}),
item({label: "Accounts Receivable", debit: props.receivable}),
item({label: "Revenue", credit: total}),
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})
];
},
expenses: function (props) {
var total = props.cash + props.payable;
return [
item({label: "Expenses", debit: total}),
item({label: "Cash", credit: props.cash}),
item({label: "Accounts Payable", credit: props.payable}),
React.DOM.tr(
{key: 'expenses-note'}, React.DOM.td(
{colSpan: 3},
"\u2001\u2001Consolidation of expenses"
)
),
spacer('expenses'),
item({label: "Income Summary", debit: total}),
item({label: "Expenses", credit: total})
];
}
});
document.addEventListener('DOMContentLoaded', function () {
React.render(
React.createElement(ClotureTable),
document.querySelector('.fiscal-year-closing'));
});
})();