You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Allow store operators to edit orders after they have been placed by the customer.
Description
Allow placed orders to be edited by store operators to eliminate the need for canceling orders if an order is placed that needs changes. This may happen in a few scenarios:
Stock discrepancies result in an order coming in with oos items
Customer changes their mind after placing an order
The workaround today is to make the change directly in the DB, which is manual and tedious. Alternatively, store operators can cancel the order and ask the customer to place a new order containing items - this is done at the risk of the customer not returning.
Key Business Logic
Only one OrderEdit can be active on a given order at any time.
OrderEdits can be confirmed without payment confirmation.
// Admin Endpoints// Create an Order EditPOST/admin/order-editsPOST/admin/orders/:id/editsGET/admin/order-edits/:id{id: "..","order_id": "...","changes": [],"removed_items": [],"items": [{/* an item that existed before the edit was kicked off */"id": "this item will be the original_order.items.$.id"},{/* a brand new item */"id": "this is a brand new id"}]}// Update an order edit - note only select fields can be updatedPOST/admin/order-edits/:id// Add an item to an OrderEditPOST/admin/order-edits/:id/items// Edit an item on an OrderEditPOST/admin/order-edits/:id/items/:id// Delete an item from an OrderEditDELETE/admin/order-edits/:id/items/:id// Undo a changeDELETE/admin/order-edits/:id/changes/:id// Request an OrderEditPOST/admin/order-edits/:id/request// Confirm an OrderEditPOST/admin/order-edits/:id/confirm// Cancel an OrderEditPOST/admin/order-edits/:id/cancel// Create a Payment CollectionPOST/admin/payment-collectionsPOST/admin/orders/:id/payment-collections// Mark a Payment Collection paidPOST/admin/payment-collections/:id/payment---// Storefront Endpoints// Retrieve an OrderEditGET/store/order-edits/:id// Complete an OrderEdit | Marks Order Edit as confirmed + handles payment collection / refundPOST/store/order-edits/:id/complete// Declines an OrderEditPOST/store/order-edits/:id/decline
Service Layer
OrderEditService// Dependencies// - LineItemService// - TotalsService// - /** * Creates a new OrderEdit. * 1. ?? */create(...)retrieve(...)list(...)/** * Updates an OrderEdit. The updatable fields are: * - internal_note */update(...)/** * Generates a new line item, including adding line item adjustments and tax lines * based on the Order's region/discounts/etc. * Adds an entry in OrderEdit.changes * * 1. Generate a line item + adjustment and tax lines * 2. Generate the orderEditChange record which includes the new line item * and the tax lines. */addLineItem(...)/** * Removes a line from line_items. * Adds an entry in OrderEdit.changes * 1. Generate a change record for delete operation. */removeLineItem(...)/** * Stages an edit of order lines. This has no change on the line item itself. * Adds an entry in OrderEdit.changes * * 0. Check whether update quantity change for the item already exists * * if the quantity change doesn't note already exists * 1. Create a line item (w. adjustment and tax lines etc.) * 2. Create an order item change record w. newly created line item * * if the quantity change already exists * 1. Find the existing change record and update the quantity * 2. Update line item adjustments * */updateLineItem(...)/** * Delete the staged change. * * 0. Check if order edit is not confirmed... * 1. Delete staged change item (and the line item if exists). */revertLineItemChange(...)/** * Performs all staged changes and updates the order line items.(idempotent) * 1. Compute the difference due before confirmation and set it as the final value * - NOTE: this is needed before original items are disassociated from the order * ^ [See resolved comments for details] * 1. Filter + clone order edit line items * set orderEditLineItem.order_id = order.id * set orderOriginalLineItem.order_id = null * 2. Set confirmed_at flag * 3. Dispatch an event */confirm(...)/** * Allow the admin operator to cancel the proposed order edit. * Canceling is idempotent so if the OrderEdit was previously canceled this * method returns early. * 1. Set canceled_at if the following conditions are met: * - the edit is not already confirmed */cancel()/** * Set requested filed on the entity and dispatch an event.*/requestUserConfirmation(...)/** * Allow the customer to accept the proposed order edit. (idempotent) * 1. Set confirmed_at if the following conditions are met: * - the edit is not already confirmed * 2. Confirm the edit if payment is OK */userAccepted()/** * Allow the customer to decline the proposed order edit. (idempotent) * 1. Set declined_at if the following conditions are met: * - the edit is not already confirmed */userDeclined()
How does customer confirmation work?
When an OrderEdit is confirmed it will change the original order as defined by the OrderEdit’s changes. This is a somewhat sensitive operation as it will potentially mean that a cheap item is changed to an expensive item, in which case the customer will owe the merchant money. To avoid a scenario where a customer requests a change to an expensive item, confirms the change, and then “disappears,” merchants want to ensure that any outstanding amounts are paid before the OrderEdit is confirmed.
From an architectural perspective, it is important to note that it is not the OrderEdit service that is responsible for ensuring that the payments are reconciled, but rather we delegate this responsibility to the human store operator. This has the consequence that a store operator can force confirmation of an OrderEdit, but it becomes their responsibility to obtain the payment afterwards.
If an edit is not force confirmed, we add some additional validation to the API layer to make the flow of ensuring payment before confirmation simpler to deal with. The two examples below are meant to serve as
Customer Confirmation (Storefront example) positive amount to be paid
Client retrieves OrderEdit
Client displays details and shows associated payment collection
Client initiates payment sessions for payment collection
Customer enters payment details
Customer presses “confirm”
Client POSTs /order-edit/:id/complete
{ payment_collection_id: …, }
The handler verifies that the payment_collection is authorized before calling orderEditService.confirm
Customer Confirmation (Storefront example) amount to be refunded
constorderEditSubtotal=orderEdit.changes.map((change)=>{if(change.type===remove){// noop because the line item is removed and doesn't go towards the subtotalreturn0}consttotals=totalsService.getLineItemTotals(change.item)returntotals.subtotal})difference_due=orderEditTotal-order.paid_total
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Goal
Allow store operators to edit orders after they have been placed by the customer.
Description
Allow placed orders to be edited by store operators to eliminate the need for canceling orders if an order is placed that needs changes. This may happen in a few scenarios:
The workaround today is to make the change directly in the DB, which is manual and tedious. Alternatively, store operators can cancel the order and ask the customer to place a new order containing items - this is done at the risk of the customer not returning.
Key Business Logic
Data Model
API layer
Service Layer
How does customer confirmation work?
When an OrderEdit is confirmed it will change the original order as defined by the OrderEdit’s changes. This is a somewhat sensitive operation as it will potentially mean that a cheap item is changed to an expensive item, in which case the customer will owe the merchant money. To avoid a scenario where a customer requests a change to an expensive item, confirms the change, and then “disappears,” merchants want to ensure that any outstanding amounts are paid before the OrderEdit is confirmed.
From an architectural perspective, it is important to note that it is not the OrderEdit service that is responsible for ensuring that the payments are reconciled, but rather we delegate this responsibility to the human store operator. This has the consequence that a store operator can force confirmation of an OrderEdit, but it becomes their responsibility to obtain the payment afterwards.
If an edit is not force confirmed, we add some additional validation to the API layer to make the flow of ensuring payment before confirmation simpler to deal with. The two examples below are meant to serve as
Customer Confirmation (Storefront example) positive amount to be paid
Client retrieves OrderEdit
Client displays details and shows associated payment collection
Client initiates payment sessions for payment collection
Customer enters payment details
Customer presses “confirm”
Client POSTs /order-edit/:id/complete
{ payment_collection_id: …, }
orderEditService.confirm
Customer Confirmation (Storefront example) amount to be refunded
Computing
orderEdit.items
Totals computation
Beta Was this translation helpful? Give feedback.
All reactions