[IMP] inventory: update automated inventory valuation
closes odoo/documentation#3606
X-original-commit: aaa1de94bd
Signed-off-by: Brandon Seltenrich (brse) <brse@odoo.com>
This commit is contained in:
parent
ea6b25aba8
commit
8c6175f77d
@ -1,424 +1,132 @@
|
|||||||
:code-column:
|
|
||||||
:custom-css: accounting.css
|
|
||||||
:custom-js: coa-valuation-continental.js,coa-valuation-anglo-saxon.js,misc.js
|
|
||||||
|
|
||||||
=================================
|
=================================
|
||||||
Inventory valuation configuration
|
Inventory Valuation Configuration
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
Inventory valuation refers to how you value your stock. It’s a very
|
All of a company's stock on-hand contributes to the valuation of its inventory. That value should
|
||||||
important aspect of a business as the inventory can be the biggest asset
|
be reflected in the company's accounting records to accurately show the value of the company and
|
||||||
of a company.
|
all of its assets.
|
||||||
|
|
||||||
Inventory valuation implies two main choices:
|
By default, Odoo uses a periodic inventory valuation (also known as manual inventory valuation).
|
||||||
|
This method implies that the accounting team posts journal entries based on the physical inventory
|
||||||
- The cost method you use to value your goods (standard, fifo, avco)
|
of the company, and that warehouse employees take the time to count the stock. In Odoo, this method
|
||||||
- The way you record this value into your accounting books (manually or automatically)
|
is reflected inside each product category, where the :guilabel:`Costing Method` field will be set
|
||||||
|
to `Standard Price` by default, and the :guilabel:`Inventory Valuation` field will be set to
|
||||||
Those two concepts are explained in the sections below.
|
`Manual`.
|
||||||
|
|
||||||
Costing Methods: Standard, FIFO, AVCO
|
.. image:: inventory_valuation_config/inventory-valuation-fields.png
|
||||||
=====================================
|
:align: center
|
||||||
|
:alt: The Inventory Valuation fields are located on the Product Categories form.
|
||||||
The costing method is defined in the product category. There are three
|
|
||||||
options available. Each of them is explained in detail below.
|
Alternatively, automated inventory valuation is an integrated valuation method that updates the
|
||||||
|
inventory value in real-time by creating journal entries whenever there are stock moves initiated
|
||||||
.. rst-class:: alternatives doc-aside
|
between locations in a company's inventory.
|
||||||
|
|
||||||
Standard Price
|
.. note::
|
||||||
.. rst-class:: values-table
|
Automated inventory valuation is a method recommended for expert accountants, given the extra
|
||||||
|
steps involved in journal entry configuration. Even after the initial setup, the method will
|
||||||
.. list-table::
|
need to be periodically checked to ensure accuracy, and adjustments may be needed on an ongoing
|
||||||
:widths: 28 18 18 18 18
|
basis depending on the needs and priorities of the business.
|
||||||
:header-rows: 1
|
|
||||||
:stub-columns: 1
|
Types of Accounting
|
||||||
|
-------------------
|
||||||
* - Operation
|
|
||||||
- Unit Cost
|
Accounting entries will depend on the accounting mode: Continental or Anglo-Saxon.
|
||||||
- Qty On Hand
|
|
||||||
- Delta Value
|
.. tip::
|
||||||
- Inventory Value
|
Verify the accounting mode by activating the :ref:`developer-mode`
|
||||||
* -
|
and navigating to :menuselection:`Accounting --> Configuration --> Settings`.
|
||||||
- €10
|
|
||||||
- 0
|
In Anglo-Saxon accounting, the costs of goods sold (COGS) are reported when products are sold or
|
||||||
-
|
delivered. This means that the cost of a good is only recorded as an expense when a customer is
|
||||||
- €0
|
invoiced for a product. Interim Stock Accounts are used for the input and output accounts, and are
|
||||||
* - Receive 8 Products at €10
|
both Asset Accounts in the Balance Sheet.
|
||||||
- €10
|
|
||||||
- 8
|
In Continental accounting, the cost of a good is reported as soon as a product is received into
|
||||||
- +8*€10
|
stock. Additionally, a *single* Expense account is used for both input and output accounts in
|
||||||
- €80
|
the Balance Sheet.
|
||||||
* - Receive 4 Products at €16
|
|
||||||
- €10
|
Costing Methods
|
||||||
- 12
|
---------------
|
||||||
- +4*€10
|
|
||||||
- €120
|
Below are the three costing methods that can be used in Odoo for inventory valuation.
|
||||||
* - Deliver 10 Products
|
|
||||||
- €10
|
- **Standard Price**: is the default costing method in Odoo. The cost of the product is manually
|
||||||
- 2
|
defined on the product form, and this cost is used to compute the valuation. Even if the purchase
|
||||||
- | -10*€10
|
price on a Purchase Order differs, the valuation will still use the cost defined on the product
|
||||||
|
|
form.
|
||||||
- €20
|
- **Average Cost (AVCO)**: calculates the valuation of a product based on the average cost of that
|
||||||
* - Receive 2 Products at €9
|
product, divided by the total number of available stock on-hand. With this costing method,
|
||||||
- €10
|
inventory valuation is *dynamic*, and constantly adjusts based on the purchase price of products.
|
||||||
- 4
|
- **First In First Out (FIFO)**: tracks the costs of incoming and outgoing items in real-time and
|
||||||
- +2*€10
|
uses the real price of the products to change the valuation. The oldest purchase price is used as
|
||||||
- €40
|
the cost for the next good sold until an entire lot of that product is sold. When the next
|
||||||
|
inventory lot moves up in the queue, an updated product cost is used based on the valuation of
|
||||||
In **Standard Price**, any product will be valued at the cost that you defined
|
that specific lot. This method is arguably the most accurate inventory valuation method for a
|
||||||
manually on the product form. Usually, this cost is an estimation based
|
variety of reasons, however, it's highly sensitive to input data and human error.
|
||||||
on the material and labor needed to obtain the product. This cost must
|
|
||||||
be reviewed periodically.
|
.. warning::
|
||||||
|
Changing the costing method greatly impacts inventory valuation. It's highly recommended to
|
||||||
Average Price
|
consult an accountant first before making any adjustments here.
|
||||||
.. rst-class:: values-table
|
|
||||||
|
Configure automated inventory valuation in Odoo
|
||||||
.. list-table::
|
-----------------------------------------------
|
||||||
:widths: 28 18 18 18 18
|
|
||||||
:header-rows: 1
|
Make changes to inventory valuation options by navigating to :menuselection:`Inventory -->
|
||||||
:stub-columns: 1
|
Configuration --> Product Categories`, and choose the category/categories where the automated
|
||||||
|
valuation method should apply.
|
||||||
* - Operation
|
|
||||||
- Unit Cost
|
.. note::
|
||||||
- Qty On Hand
|
It is possible to use different valuation settings for different product categories.
|
||||||
- Delta Value
|
|
||||||
- Inventory Value
|
Under the :guilabel:`Inventory Valuation` heading are two labels: :guilabel:`Costing Method` and
|
||||||
* -
|
:guilabel:`Inventory Valuation`. Pick the desired :guilabel:`Costing Method` using the drop-down
|
||||||
- €0
|
menu (e.g. :guilabel:`Standard`, :guilabel:`Average Cost (AVCO)`, or :guilabel:`First In First Out
|
||||||
- 0
|
(FIFO)` and switch the :guilabel:`Inventory Valuation` to :guilabel:`Automated`.
|
||||||
-
|
|
||||||
- €0
|
.. seealso::
|
||||||
* - Receive 8 Products at €10
|
:doc:`Using the inventory valuation <using_inventory_valuation>`
|
||||||
- €10
|
|
||||||
- 8
|
.. note::
|
||||||
- +8*€10
|
When choosing :guilabel:`Average Cost (AVCO)` as the :guilabel:`Costing Method`, the numerical
|
||||||
- €80
|
value in the :guilabel:`Cost` field for products in the respective product category will no
|
||||||
* - Receive 4 Products at €16
|
longer be editable, and will appear grayed out. The :guilabel:`Cost` amount will instead
|
||||||
- €12
|
automatically update based on the average purchase price both of inventory on hand and the costs
|
||||||
- 12
|
accumulated from validated purchase orders.
|
||||||
- +4*€16
|
|
||||||
- €144
|
On the same screen, the :guilabel:`Account Stock Properties` fields will appear, as they are now
|
||||||
* - Deliver 10 Products
|
required fields given the change to automated inventory valuation. These accounts are defined as
|
||||||
- €12
|
follows:
|
||||||
- 2
|
|
||||||
- | -10*€12
|
- :guilabel:`Stock Valuation Account`: when automated inventory valuation is enabled on a product,
|
||||||
|
|
this account will hold the current value of the products.
|
||||||
- €24
|
- :guilabel:`Stock Input Account`: counterpart journal items for all incoming stock moves will be
|
||||||
* - Receive 2 Products at €6
|
posted in this account, unless there is a specific valuation account set on the source location.
|
||||||
- €9
|
This is the default value for all products in a given category, and can also be set directly on
|
||||||
- 4
|
each product.
|
||||||
- +2*€6
|
- :guilabel:`Stock Output Account`: counterpart journal items for all outgoing stock moves will be
|
||||||
- €36
|
posted in this account, unless there is a specific valuation account set on the destination
|
||||||
|
location. This is the default value for all products in a given category, and can also be set
|
||||||
In **AVCO (Average Cost)**, each product has the same value and this
|
directly on each product.
|
||||||
value is the average purchase cost of the product. With this costing method, the
|
|
||||||
cost of the product is recomputed as each receipt.
|
Access reporting data generated by inventory valuation
|
||||||
|
------------------------------------------------------
|
||||||
The average cost does not change when products leave the warehouse.
|
|
||||||
|
To start, go to :menuselection:`Accounting --> Reporting --> Balance Sheet`. At the top of the
|
||||||
FIFO
|
dashboard, change the :guilabel:`As of` field value to :guilabel:`Today`, and adjust the filtering
|
||||||
.. rst-class:: values-table
|
:guilabel:`Options` to :guilabel:`Unfold All` in order to see all of the latest data displayed,
|
||||||
|
all at once.
|
||||||
.. list-table::
|
|
||||||
:widths: 28 18 18 18 18
|
Under the parent :guilabel:`Current Assets` line item, look for the nested :guilabel:`Stock
|
||||||
:header-rows: 1
|
Valuation Account` line item, where the total valuation of all of the inventory on hand is
|
||||||
:stub-columns: 1
|
displayed.
|
||||||
|
|
||||||
* - Operation
|
Access more specific information with the :guilabel:`Stock Valuation Account` drop-down menu, by
|
||||||
- Unit Cost
|
selecting either the :guilabel:`General Ledger` to see an itemized view of all of the journal
|
||||||
- Qty On Hand
|
entries, or by selecting :guilabel:`Journal Items` to review all of the individualized journal
|
||||||
- Delta Value
|
entries that were submitted to the account. As well, annotations to the :guilabel:`Balance Sheet`
|
||||||
- Inventory Value
|
can be added by choosing :guilabel:`Annotate`, filling in the text box, and clicking
|
||||||
* -
|
:guilabel:`Save`.
|
||||||
- €0
|
|
||||||
- 0
|
.. image:: inventory_valuation_config/stock-valuation-breakdown-in-accounting.png
|
||||||
-
|
:align: center
|
||||||
- €0
|
:alt: See the full inventory valuation breakdown in Odoo Accounting app.
|
||||||
* - Receive 8 Products at €10
|
|
||||||
- €10
|
|
||||||
- 8
|
|
||||||
- +8*€10
|
|
||||||
- €80
|
|
||||||
* - Receive 4 Products at €16
|
|
||||||
- €12
|
|
||||||
- 12
|
|
||||||
- +4*€16
|
|
||||||
- €144
|
|
||||||
* - Deliver 10 Products
|
|
||||||
- €16
|
|
||||||
- 2
|
|
||||||
- | -8*€10
|
|
||||||
| -2*€16
|
|
||||||
- €32
|
|
||||||
* - Receive 2 Products at €6
|
|
||||||
- €11
|
|
||||||
- 4
|
|
||||||
- +2*€6
|
|
||||||
- €44
|
|
||||||
|
|
||||||
In **FIFO (First In First Out)**, the products are valued at their
|
|
||||||
purchase cost. When a product leaves the stock, that’s the “First in,
|
|
||||||
first out” rule that applies.
|
|
||||||
|
|
||||||
Pay attention, that this is a financial FIFO. The first value “in”
|
|
||||||
is the first value “out”, no matter the storage location, warehouse
|
|
||||||
or serial number.
|
|
||||||
|
|
||||||
FIFO is advised if you manage all your workflows into Odoo (Sales,
|
|
||||||
Purchases, Inventory). It suits any kind of users.
|
|
||||||
|
|
||||||
Inventory Valuation: Manual or Automated
|
|
||||||
========================================
|
|
||||||
|
|
||||||
There are two ways to record your inventory valuation in your accounting
|
|
||||||
books. As the costing method, this is defined in your product category.
|
|
||||||
Those two methods are detailed below.
|
|
||||||
|
|
||||||
It is important to also note that the accounting entries will depend on
|
|
||||||
your accounting mode: it can be continental or anglo-saxon. In
|
|
||||||
continental accounting, the cost of a good is taken into account as soon
|
|
||||||
as the product is received in stock. In anglo-saxon accounting, the cost
|
|
||||||
of a good is only recorded as an expense when this good is invoiced to a
|
|
||||||
final customer. In the tables below, you can easily compare those two
|
|
||||||
accounting modes.
|
|
||||||
|
|
||||||
Usually, based on your country, the correct accounting mode will be
|
|
||||||
chosen by default. If you want to verify your accounting mode, activate
|
|
||||||
the :ref:`developer mode <developer-mode>` and open your accounting
|
|
||||||
settings.
|
|
||||||
|
|
||||||
Manual Inventory Valuation
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
In this case, goods receipts and deliveries won’t have any direct impact
|
|
||||||
on your accounting books. Periodically, you create a manual journal
|
|
||||||
entry representing the value of what you have in stock. To know that
|
|
||||||
value, go in :menuselection:`Inventory --> Reporting --> Inventory Valuation`.
|
|
||||||
|
|
||||||
This is the default configuration in Odoo and it works
|
|
||||||
out-of-the-box. Check following operations and find out how
|
|
||||||
Odoo is managing the accounting postings.
|
|
||||||
|
|
||||||
Continental Accounting
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. rst-class:: alternatives doc-aside
|
|
||||||
|
|
||||||
Vendor Bill
|
|
||||||
.. rst-class:: values-table
|
|
||||||
|
|
||||||
============================= ===== ======
|
|
||||||
\ Debit Credit
|
|
||||||
============================= ===== ======
|
|
||||||
Assets: Inventory 50
|
|
||||||
Assets: Deferred Tax Assets 4.68
|
|
||||||
Liabilities: Accounts Payable 54.68
|
|
||||||
============================= ===== ======
|
|
||||||
|
|
||||||
Configuration:
|
|
||||||
* Purchased Goods: defined on the product or on the internal category of related product (Expense Account field)
|
|
||||||
* Deferred Tax Assets: defined on the tax used on the purchase order line
|
|
||||||
* Accounts Payable: defined on the vendor related to the bill
|
|
||||||
Goods Receptions
|
|
||||||
No Journal Entry
|
|
||||||
Customer Invoice
|
|
||||||
.. rst-class:: values-table
|
|
||||||
|
|
||||||
===================================== ===== ======
|
|
||||||
\ Debit Credit
|
|
||||||
===================================== ===== ======
|
|
||||||
Revenues: Sold Goods 100
|
|
||||||
Liabilities: Deferred Tax Liabilities 9
|
|
||||||
Assets: Accounts Receivable 109
|
|
||||||
===================================== ===== ======
|
|
||||||
|
|
||||||
Configuration:
|
|
||||||
* Revenues: defined on the product or on the internal category of related product (Income Account field)
|
|
||||||
* Deferred Tax Liabilities: defined on the tax used on the invoice line
|
|
||||||
* Accounts Receivable: defined on the customer (Receivable Account)
|
|
||||||
|
|
||||||
The fiscal position used on the invoice may have a rule that replaces the
|
|
||||||
Income Account or the tax defined on the product by another one.
|
|
||||||
Customer Shipping
|
|
||||||
No Journal Entry
|
|
||||||
Manufacturing Orders
|
|
||||||
No Journal Entry
|
|
||||||
|
|
||||||
.. raw:: html
|
|
||||||
|
|
||||||
<hr style="float: none; visibility: hidden; margin: 0;">
|
|
||||||
|
|
||||||
At the end of the month/year, your company does a physical inventory
|
|
||||||
or just relies on the inventory in Odoo to value the stock into your books.
|
|
||||||
|
|
||||||
Create a journal entry to move the stock variation value from your
|
|
||||||
Profit&Loss section to your assets.
|
|
||||||
|
|
||||||
.. h:div:: doc-aside
|
|
||||||
|
|
||||||
.. rst-class:: values-table
|
|
||||||
|
|
||||||
===================================== ===== ======
|
|
||||||
\ Debit Credit
|
|
||||||
===================================== ===== ======
|
|
||||||
Assets: Inventory X
|
|
||||||
Expenses: Inventory Variations X
|
|
||||||
===================================== ===== ======
|
|
||||||
|
|
||||||
If the stock value decreased, the **Inventory** account is credited
|
|
||||||
and the **Inventory Variations** debited.
|
|
||||||
|
|
||||||
.. raw:: html
|
|
||||||
|
|
||||||
<hr style="float: none; visibility: hidden; margin: 0;">
|
|
||||||
|
|
||||||
Anglo-Saxon Accounting
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. rst-class:: alternatives doc-aside
|
|
||||||
|
|
||||||
Vendor Bill
|
|
||||||
.. rst-class:: values-table
|
|
||||||
|
|
||||||
============================= ===== ======
|
|
||||||
\ Debit Credit
|
|
||||||
============================= ===== ======
|
|
||||||
Assets: Inventory 50
|
|
||||||
Assets: Deferred Tax Assets 4.68
|
|
||||||
Liabilities: Accounts Payable 54.68
|
|
||||||
============================= ===== ======
|
|
||||||
|
|
||||||
Configuration:
|
|
||||||
* Purchased Goods: defined on the product or on the internal category of related product
|
|
||||||
(Expense Account field)
|
|
||||||
* Deferred Tax Assets: defined on the tax used on the purchase order line
|
|
||||||
* Accounts Payable: defined on the vendor related to the bill
|
|
||||||
Goods Receptions
|
|
||||||
No Journal Entry
|
|
||||||
Customer Invoice
|
|
||||||
.. rst-class:: values-table
|
|
||||||
|
|
||||||
===================================== ===== ======
|
|
||||||
\ Debit Credit
|
|
||||||
===================================== ===== ======
|
|
||||||
Revenues: Sold Goods 100
|
|
||||||
Liabilities: Deferred Tax Liabilities 9
|
|
||||||
Assets: Accounts Receivable 109
|
|
||||||
===================================== ===== ======
|
|
||||||
|
|
||||||
Configuration:
|
|
||||||
* Revenues: defined on the product or on the internal category of related
|
|
||||||
product (Income Account field)
|
|
||||||
* Deferred Tax Liabilities: defined on the tax used on the invoice line
|
|
||||||
* Accounts Receivable: defined on the customer (Receivable Account)
|
|
||||||
|
|
||||||
The fiscal position used on the invoice may have a rule that replaces the
|
|
||||||
Income Account or the tax defined on the product by another one.
|
|
||||||
Customer Shipping
|
|
||||||
No Journal Entry
|
|
||||||
Manufacturing Orders
|
|
||||||
No Journal Entry
|
|
||||||
|
|
||||||
.. raw:: html
|
|
||||||
|
|
||||||
<hr style="float: none; visibility: hidden; margin: 0;">
|
|
||||||
|
|
||||||
At the end of the month/year, your company does a physical inventory
|
|
||||||
or just relies on the inventory in Odoo to value the stock into your books.
|
|
||||||
|
|
||||||
Then you need to break down the purchase balance into both the inventory and
|
|
||||||
the cost of goods sold using the following formula:
|
|
||||||
|
|
||||||
Cost of goods sold (COGS) = Starting inventory value + Purchases – Closing inventory value
|
|
||||||
|
|
||||||
To update the stock valuation in your books, record such an entry:
|
|
||||||
|
|
||||||
.. h:div:: doc-aside
|
|
||||||
|
|
||||||
.. rst-class:: values-table
|
|
||||||
|
|
||||||
===================================== ===== ======
|
|
||||||
\ Debit Credit
|
|
||||||
===================================== ===== ======
|
|
||||||
Assets: Inventory (closing value) X
|
|
||||||
Expenses: Cost of Good Sold X
|
|
||||||
Expenses: Purchased Goods X
|
|
||||||
Assets: Inventory (starting value) X
|
|
||||||
===================================== ===== ======
|
|
||||||
|
|
||||||
Automated Inventory Valuation
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
In that case, when a product enters or leaves your stock, an accounting
|
|
||||||
entry will be automatically created. This means your accounting books
|
|
||||||
are always up-to-date. This mode is dedicated to expert accountants and
|
|
||||||
advanced users only. As opposed to periodic valuation, it requires some
|
|
||||||
extra configuration & testing.
|
|
||||||
|
|
||||||
First, you need to define the accounts that will be used for those
|
|
||||||
accounting entries. This is done on the product category.
|
|
||||||
|
|
||||||
Continental Accounting
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. h:div:: valuation-chart-continental doc-aside
|
|
||||||
|
|
||||||
.. placeholder
|
|
||||||
|
|
||||||
.. raw:: html
|
|
||||||
|
|
||||||
<hr style="float: none; visibility: hidden; margin: 0;">
|
|
||||||
|
|
||||||
.. h:div:: doc-aside
|
|
||||||
|
|
||||||
**Configuration:**
|
|
||||||
|
|
||||||
- Accounts Receivable/Payable: defined on the partner (Accounting tab)
|
|
||||||
|
|
||||||
- Deferred Tax Assets/Liabilities: defined on the tax used on the invoice line
|
|
||||||
|
|
||||||
- Revenues/Expenses: defined by default on product's internal category; can be
|
|
||||||
also set in product form (Accounting tab) as a replacement value.
|
|
||||||
|
|
||||||
- Inventory Variations: to set as Stock Input/Output Account in product's internal
|
|
||||||
category
|
|
||||||
|
|
||||||
- Inventory: to set as Stock Valuation Account in product's internal category
|
|
||||||
|
|
||||||
Anglo-Saxon Accounting
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. h:div:: valuation-chart-anglo-saxon doc-aside
|
|
||||||
|
|
||||||
.. placeholder
|
|
||||||
|
|
||||||
.. raw:: html
|
|
||||||
|
|
||||||
<hr style="float: none; visibility: hidden; margin: 0;">
|
|
||||||
|
|
||||||
.. h:div:: doc-aside
|
|
||||||
|
|
||||||
**Configuration:**
|
|
||||||
|
|
||||||
- Accounts Receivable/Payable: defined on the partner (Accounting tab)
|
|
||||||
|
|
||||||
- Deferred Tax Assets/Liabilities: defined on the tax used on the
|
|
||||||
invoice line
|
|
||||||
|
|
||||||
- Revenues: defined on the product category as a default, or specifically
|
|
||||||
to a specific product.
|
|
||||||
|
|
||||||
- Expenses: this is where you should set the "Cost of Goods Sold" account.
|
|
||||||
Defined on the product category as a default value, or specifically on
|
|
||||||
the product form.
|
|
||||||
|
|
||||||
- Goods Received Not Purchased: to set as Stock Input Account in product's
|
|
||||||
internal category
|
|
||||||
|
|
||||||
- Goods Issued Not Invoiced: to set as Stock Output Account in product's
|
|
||||||
internal category
|
|
||||||
|
|
||||||
- Inventory: to set as Stock Valuation Account in product's internal category
|
|
||||||
|
|
||||||
- Price Difference: to set in product's internal category or in product
|
|
||||||
form as a specific replacement value
|
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
@ -1,276 +0,0 @@
|
|||||||
/* global Immutable, React */
|
|
||||||
/* global createAtom */
|
|
||||||
(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-sm' },
|
|
||||||
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-anglo-saxon'));
|
|
||||||
React.render(
|
|
||||||
React.createElement(Chart, { p: next }),
|
|
||||||
document.querySelector('.valuation-chart-anglo-saxon'));
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
var chart = document.querySelector('.valuation-chart-anglo-saxon');
|
|
||||||
if (!chart) { return; }
|
|
||||||
|
|
||||||
var controls = document.createElement('div');
|
|
||||||
controls.setAttribute('id', 'chart-controls-anglo-saxon');
|
|
||||||
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<AccountCode> 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 $50)",
|
|
||||||
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: "Supplier 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: "Supplier 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);
|
|
||||||
}
|
|
||||||
})();
|
|
@ -1,265 +0,0 @@
|
|||||||
/* global Immutable, React */
|
|
||||||
/* global createAtom */
|
|
||||||
(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-sm' },
|
|
||||||
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-continental'));
|
|
||||||
React.render(
|
|
||||||
React.createElement(Chart, { p: next }),
|
|
||||||
document.querySelector('.valuation-chart-continental'));
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
var chart = document.querySelector('.valuation-chart-continental');
|
|
||||||
if (!chart) { return; }
|
|
||||||
|
|
||||||
var controls = document.createElement('div');
|
|
||||||
controls.setAttribute('id', 'chart-controls-continental');
|
|
||||||
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" },
|
|
||||||
TAXES_PAID: { code: 19000, label: "Deferred Tax Assets" }
|
|
||||||
};
|
|
||||||
var LIABILITIES = {
|
|
||||||
code: 2,
|
|
||||||
label: "Liabilities",
|
|
||||||
ACCOUNTS_PAYABLE: { code: 21000, label: "Accounts Payable" },
|
|
||||||
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",
|
|
||||||
PURCHASED_GOODS: { code: 51000, label: "Purchased Goods" },
|
|
||||||
PURCHASED_SERVICES: { code: 52000, label: "Purchased Services" },
|
|
||||||
INVENTORY_VARIATIONS: { code: 58000, label: "Inventory Variations" },
|
|
||||||
OTHER_OPERATING_EXPENSES: { code: 59000, label: "Other Operating Expenses" },
|
|
||||||
};
|
|
||||||
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<AccountCode> 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 Invoice (PO €50, Invoice €50)",
|
|
||||||
operations: [
|
|
||||||
{ account: EXPENSES.PURCHASED_GOODS.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: EXPENSES.INVENTORY_VARIATIONS.code, credit: constant(50) },
|
|
||||||
{ account: ASSETS.STOCK.code, debit: constant(50) },
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
label: "Vendor Invoice (PO €48, Invoice €50)",
|
|
||||||
operations: [
|
|
||||||
{ account: EXPENSES.PURCHASED_GOODS.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 €48, Invoice €50)",
|
|
||||||
operations: [
|
|
||||||
{ account: EXPENSES.INVENTORY_VARIATIONS.code, credit: constant(48) },
|
|
||||||
{ account: ASSETS.STOCK.code, debit: constant(48) },
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
label: "Customer Invoice (€100 + 9% tax)",
|
|
||||||
operations: [
|
|
||||||
{ account: ASSETS.ACCOUNTS_RECEIVABLE.code, debit: constant(total) },
|
|
||||||
{ account: REVENUE.SALES.code, credit: constant(sale) },
|
|
||||||
{ account: LIABILITIES.TAXES_PAYABLE.code, credit: constant(tax) }
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
label: "Customer Shipping",
|
|
||||||
operations: [
|
|
||||||
{ account: EXPENSES.INVENTORY_VARIATIONS.code, debit: constant(cor) },
|
|
||||||
{ account: ASSETS.STOCK.code, credit: constant(cor) }
|
|
||||||
]
|
|
||||||
}]);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
})();
|
|
Loading…
Reference in New Issue
Block a user