Hi Erik, A few things to discuss. NOTE: On my mobile and the mail client doesn't look
to handle inline responses well, so I'll top post....sorry.Shouldn't the linetotal
be returned within the calculated block rather than the user supplied block?Doing
otherwise seems like a massive rounding nightmare.As for handling db side changes during
the life cycle of the invoice (eg: price and tax changes) I'm not sure I see an easy
solution. We currently have a problem here anyway.If we follow a full quote => order
=> invoice workflow you expect a price as shown on a quote to be static throughout the
sequence.However it will most likely change if any source info changes along the
way.Personally, I think a specific request to update a line is required. To that end, I
think each line should (as the first element) contain a boolean "recalc" element
and a "lastcalc" timestampAs should the entire invoice.Regardless, there
probably needs to be 3 sets of price data presented.- user overrides- system calculated-
actual data for useAll of the above should be permanently stored in the db. (FYI, we
should be doing this even for non API entries as well.This preserves the data. Allowing
better auditing and diagnostics)There is probably more to consider, but there's a
start for discussion RegardsDavid G
-------- Original message --------From: Erik Huelsmann <ehuels(a)gmail.com> Date:
6/7/21 04:56 (GMT+08:00) To: devel(a)lists.ledgersmb.orgHi,Over the past months, I've
been working on a webservice for LedgerSMB to post invoices. The current status can be
viewed here:
https://github.com/ehuelsmann/LedgerSMB/blob/webservices/lib/LedgerSMB/Rout…
what I have achieved so far: * An endpoint /erp/api/v0/invoices/, which accepts POST
requests * The "specification" of the payload can be found here:
https://github.com/ehuelsmann/LedgerSMB/blob/webservices/lib/LedgerSMB/Rout… *
The toplevel keys "eca", "account", "dates",
"lines", "taxes", "currency", "description",
"invumber", "ordnumber", "ponumber" are supported * The
pricematrix is consulted when determining pricing * Customers and vendors are supported
(each with their own type of pricematrix)The endpoint has been coded defensively, throwing
an "unacceptable input" error on anything that's not consistent with what
the database should expect. A lot of things are currently not supported: * Invoices will
end up in "draft" state and cannot be Post-ed * Payments are not processed *
Rounding (in the price matrix, but also of the line-totals) isn't in place * Complex
taxes have limited support ("simple taxes only") * No multi-currency support
yet * No support for "taxes included" tax extraction calculation (from the gross
invoice amount) * I have no idea what happens with Cost Of Goods Sold calculations * No
support for shipping addresses * No support for printing/mailing/etc. * All invoices are
posted into the 'ar' table (oops!)That said, I have some questions with respect to
what the functionality needs to be able to do, especially with respect to saving invoices
in order to post them later. With respect to saving and posting invoices, I'm
envisaging the workflow to require a number (lots) of save actions on the invoice in order
to calculate its prices, i.e. to calculate the price matrix. There may be other reasons to
save the invoice in the mean time.In the current invoice-entry process (running through
"old code"), there's a lot of code which tries to determine if anything
changed in the invoice based on the fields entered. If it did (or rather, if the deduction
code thinks it did), the invoice will be recalculated either partial or in full.This code
causes lots of headaches, because most of the time the user didn't expect their edits
to trigger a full recalculation, or, the recalculation didn't happen the way it should
e.g. due to the fact that prices had been overridden by the user.To prevent similar
complexity in the webservice, I've created a structure where each line returns the
data entered by the user (as provided on input) as well as calculated data. It is up to
the front-end to present that data in a useful way to the user. Just as an example, the
following structure could be a line in the invoice: { "part": {
"number": "p1", "description": "p1 desc",
"price": 1.23 }, "quantity": 5, "description": null,
"price": null, "linetotal": 6.15, "discount": null }The
above line means to say that the user didn't enter a price, description or discount.
The part has been configured with a price of $1.23 for the current customer/vendor and the
quantity on the line is 5 (as entered by the user). If the user enters a description, the
description field in the line itself gets filled with that, e.g. "bike rental
fees".Assuming that the user saves the above line without further input and continues
by posting the invoice, I'm thinking that the posting action should copy the
description and price from the part configuration to the invoice.This poses a timing
challenge: what if in the mean time the part configuration gets changed and the price is
updated to 5.23? Then the actual invoice posted goes from a linetotal of 6.15$ to 25.15$.
Seems unacceptable.So, the other option is: create a "calculate the price matrix for
this invoice without actually storing it" endpoint and do the "copy data from
part" step on save instead of on posting. Here, I'm running into a problem too:
lets assume the user wants to save the invoice only to work on it more tomorrow? In that
case, all the prices have been filled and the price matrix calculation won't work
anymore, because it doesn't work due to the "price" fields no longer being
'null'.The above problem exists not only for parts, but also for taxes; maybe
other scenarios too.By posting this, I hope to get some good discussion on the topic (and
hopefully some good additional ideas)!--
Bye,Erik.http://efficito.com -- Hosted accounting
and ERP.Robust and Flexible. No vendor lock-in.