Order Initiation
The workflow for an order begins with its creation. Even though this seems universal, it also is the first point at which various business rules may take effect, turning what would otherwise be something relatively simple into what might be a very custom event. This page describes some of the typical scenarios as well as some known possibilities for variation.
The Basics
The following will occur regardless of workflow:
- A new Order is created.
 - A new OrderEvent is created to log who created the Order, and when.
 - One or more OrderProducts are created and attached to the Order.
 
Customer Resolution
Orders are designed to have been somehow initiated by (and therefore belong to) a Customer. (However, a valid User is required to actually create an Order within Rattail - this User in real life could be either a customer or an employee, etc., depending on your setup.) Some shops might get by without ever assigning a Customer to an Order, some may allow an Order to be Customer-less for certain stages in the workflow, and others will require a valid Customer from the beginning.
If the Customer is required for the entire workflow then it's pretty straightforward; one must be selected and assigned during Order creation. Likewise, if no Customer is ever really needed, then there's really nothing to document. However if the Customer must be selected pryor to some later stage in the workflow, then something like the following must occur:
- Order is created with 
Order.customerset toNone. Order.customer_nameandOrder.customer_phoneare set according to user input, for help in Customer identification later.Order.statusis set to "customer unresolved" or similar.
Then at some later point:
- The Customer is identified (created or ETLed if necessary) within Rattail and 
Order.customeris set accordingly. Order.customer_nameandOrder.customer_phoneare possibly reassigned from newly-attached Customer.Order.statusis set to "customer resolved" or similar.- A "customer resolved" OrderEvent is logged.
 
Also note that if Order.status is not of particular interest to you, the same effect may be had per OrderProduct by using OrderProduct.status instead.  However since multiple OrderProducts may belong to a single Order it'd probably be nice for the user if they could all be resolved at once.
Product Resolution
As with the "Customer Resolution" (above), some shops may allow an OrderProduct to exist for some time without having a valid Product assigned to it. If that is the case, something like the following must occur:
- OrderProduct is created with 
OrderProduct.productset toNone. OrderProduct.initial_descriptionis set according to user input, for help in Product identification later.OrderProduct.statusis set to "product unresolved" or similar.
Then at some later point:
- The Product is identified (created or ETLed if necessary) within Rattail and 
OrderProduct.productis set accordingly. OrderProduct.priceis set, presumably to the Product's current price.OrderProduct.statusis set to "product resolved" or similar.- A "product resolved" OrderProductEvent is logged.
 
The OrderProduct.initial_description, if used, is assumed to be a free-form (preferably detailed) description of the product and anything known about it (source vendor, relevant department, etc.).
Product Stock
TODO: Another possibility though is if the product is already in-stock or on-order. In this case it would be nice to alert the user to the situation somehow. If the product is in-stock then perhaps it can be physically located and there would be no need for an Order to even be created. If the product is on-order then perhaps it can be "reserved" for the customer somehow.
Product Pricing
The default case would probably one in which whenever the product is resolved, OrderProduct.price is also set to whatever the product's current price happens to be for the customer placing the order.  It may be, however, that some other data should be considered when determining which price will be locked-in for the OrderProduct, or indeed if one will be locked in at all.
Discounts
If the Product already exists in the system, then Product.discountable should determine whether or not a discount is allowed at all.  Assuming it is allowed, shop-specific business rules would determine what the maximum discount would be, and perhaps who would even be allowed to make that call or override the default, etc.  (Indeed discount determination might need to be a completely separate step in the workflow for some.)
In the vanilla case where the product is discountable, the basic algorithm might be like this:
OrderProduct.productandOrderProdut.priceare set.OrderProduct.discount_percentis set, e.g. to 10%.OrderProduct.discount_amountis calculated based onOrderProduct.price,OrderProduct.discount_percentandOrderProduct.quantity.
It would also be possible to manually set OrderProduct.discount_amount to a value, e.g. $10.00, in which case {{{OrderProduct.discount_percent}}} would be dynamically calculated instead.  (Note that these automatic calculations could be seen as "for reference only"; they could also be ignored if not needed, as could the entire discount idea.)
Deposits / Pre-Payment
TODO: Some customers might just prefer to pay up-front for their order, and they should probably be allowed to do so (depending on your shop's preference). Also some shops may wish to require a deposit of some sort, either globally or for specific products. In either case the payment must be recorded, etc.