Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

What I Learned about Payment Systems While Working at a Pizza Place


Placing an order and capturing a payment are really different actions. I also learned a lot in a few days.

Quick Jump: Placing an Order for Pickup | Placing Orders in Multiple Ways | Multiple Payments Per Order | Extra Charges, Tips and Discounts | Voids and Refunds | Customers | Stripe, Shopify and Square | Video

Prefer video? I’ve put up a YouTube video going over this post with a bit more color and detail.

Up until recently I’ve never worked at a register or collected payments at a physical location. I’ve only ever sold online video courses where you typically start the checkout process and digitally purchase an item within a few seconds or minutes.

I was helping a friend out recently and worked the counter at a pizza place for a couple of weeks after my normal job. It’s a much different world than doing remote programming and making YouTube videos. I’ll likely make more posts related to this in a programming context but let’s focus on payments in this one.

Placing an Order for Pickup

Check out this run of the mill workflow that may happen many times a day:

  1. Customer calls in on the phone to place an order for pickup
  2. They want to buy a large lightly cooked pie and 6 garlic knots
  3. You input their order into the POS (point of sale) system
  4. Each item is listed as a line item with a name, quantity, note and price
  5. You ask for their name and number and put it into the system
  6. A total is calculated with sales tax being a separate line item
  7. The order gets “Created” and the following things happen:
    • The order is placed into “In Progress” with a little icon showing it’s not paid for
      • Being paid or not is independent of the order being in progress
    • A receipt is printed at the register which is marked “INCOMPLETE”
      • You hang this receipt up so you and others know an order is pending
    • An order to make 1 pie is printed where the pizza maker can see it

Step 7 is going to be different depending on which POS system you use but the general ideas are the same. There’s the concept of an order being in the system with a status, a human workflow is executed to track that order physically and receipts get printed.

At no point did we even think about capturing a payment here. For this pickup order there’s a few ways a payment can be collected:

  • They pay for it with either cash or credit when they pick it up
  • While on the phone with the customer you enter their credit card details into the terminal on their behalf which is PCI DSS compliant by the way, with our above workflow that could have been done after step 6 and then step 7 would be different but let’s put that on hold for now

For now we’re also ignoring other types of ways for orders to be input such as them ordering it online and paying for it on the spot or a delivery which could either be paid for and done online or have cash collected upon delivery. More on that later!

Ok so now let’s say the customer comes in 20 minutes from now to pick up their order. At this point you may have accepted 10 other orders from different customers. Some might be in progress and others might be completed. Maybe someone popped in to buy 2 slices to go and was in and out in 3 minutes.

You check the receipts that are hanging and notice this order is #137, so you go back to the POS system’s “In Progress” tab and find that order. Yep there it is.

You can see the full total of the order and see if the customer has cash out or a card (or their phone if they’re using Apple / Google Pay). If not, you ask them cash or card and the POS system will let you choose which one.

If they pick cash, you input the amount they give you and it auto-calculates their change. If they pick card or another digital payment method, they can use the terminal to tap or insert their card / device. It will get authorized and then hopefully be successful unless their card has issues.

In any case, if the payment is successful then the following happens:

  • The order is marked as “Completed” in the system
  • Another receipt is printed except with payment information filled in
  • You save the receipt if the business owner wants physical receipts saved
  • You remove and throw away the hung “INCOMPLETE” receipt so you know it’s done

The pizza maker threw away their print out for that pie independently of the order being completed. From their POV, they are finished when the pie is first placed IN the oven or OUT depending on if the counter workers know how to gauge when a pie is ready to be taken out.

At this point you have a clean slate. The order is complete and it’s been moved through the workflow. Depending on how busy the place is, this might be executed 50 or even 300 times a day with surges coming in around popular lunch and dinner times.

If you need to go back to an order that’s already been completed you can. You can also print receipts on demand and if there’s been a payment captured you can issue a full or partial refund.

There’s so much more to go into around payment details but let’s go over a few technical takeaways from the above.

Technical Takeaways

Here’s a couple of things I got out of the above and remember thinking about while taking orders and observing the system. If you were building this system out think about the database terms and relationships you might have.

I’ve quoted the words that could be tables or models.

An “Order”, “Product” and “Payment” are different things

An order really pulls together multiple products into something that can be associated as a thing but in my opinion it’s not a join-table between products and payments.

Order #137 has N products. It also has X payments where X can even be 0 if the order happens to be free, such as if they have a coupon to get 1 free pie after buying 10.

You would still want that free pie to be put through the workflow and tracked. The only difference is you wouldn’t collect a payment.

An order has a status to clearly show the stage an order is at. You can almost think of it as a Kanban board that moves from created to completed.

A “Product” has “Variants” and “Notes”

At this place a pie can be personal (12”), medium (16”) or large (18”). A customer may want full pepperonis or meatballs. Maybe they want 1/2 and 1/2, or maybe they want 2 full toppings.

The pie can also have no notes or something specific that the customer wants such as lightly cooked, crispy or well done.

A variant and note are different things. A variant is something the customer can choose when making the purchase and it may or may not affect the price. Variants are standard things (T-shirt size, etc.) and notes are ADHOC customer requests.

If enough customers have the same request, maybe that’s a sign you can turn it into a variant but not always. For example, if 90% of people are ok with a normally cooked pizza you may not want to explicitly ask them to choose between regular, light, crispy or well done since it complicates the order process especially if it’s online where they are clicking form fields.

On the other hand, requiring them to pick large or personal is a good idea since those are different product variants with different prices. However if you were selling shirts you’d likely want colors as a variant even if they don’t adjust the price.

A “Receipt” is immutable

A receipt is created at a specific point in time and it reflects the details at that point in time. It may or may not be printed.

That’s a very important distinction because even if you didn’t print out orders onto paper you wouldn’t want to modify old orders with different details based on future events.

For example, if a pie costs $16.95 right now and you have 1,000 orders that happened in the past at that price and then bump your pie to $17.95 you can’t go back and adjust all of those previous orders to have $17.95.

No way right? The payment was already collected for $16.95 and it’s a done deal.

That means you shouldn’t have something like a reference to a product’s foreign key to dynamically grab the price when you render the receipt. Just about everything about that receipt should be denormalized, AKA. the details about the receipt are all self contained in that 1 row. It should be an individually rendered thing with its own separate data.

Placing Orders in Multiple Ways

In the above example we handled the use case of a single counter worker entering in an order through the POS system but that’s not the only way orders can be collected.

If your POS system is integrated with a website or app, customers can place orders online. They still need to come up into your system as “In Progress”. In this case the order isn’t “Completed” yet but the payment was captured.

Online orders still get receipts hung because the hanging receipt is an indicator to let workers know if a customer received their order. It’s fully independent of a payment being captured or not.

Additionally, orders can be placed through DoorDash which may or may not even integrate with your POS system. If not, you might get the DoorDash order through a different system but the idea of hanging a receipt while incomplete can still hold true.

Lastly if we go back to someone taking an order at the pizza shop there could technically be multiple POS systems and multiple terminals to accept credit card payments.

Each POS system should sync its orders and statuses to each other otherwise you may have conflicting information which will get very confusing. Other than that, it’s the same as our original plan of taking orders at the register. The hanging receipt workflow holds true.

Technical Takeaways

In the DoorDash case, it’s an interesting idea in that 2 different systems or inputs can still funnel into the same workflow for ensuring an order is fulfilled. In the DoorDash case all orders are already paid for, you’re only keeping track when someone will pick it up. Them picking it up and marking the order as picked up on their phone is the action to complete the order on our end.

That opens the door for a POS system to integrate with third party order collection systems such as DoorDash. There is a benefit of your POS system being aware of DoorDash so orders get shown in the same place.

At the place I worked at they were separate. It meant keeping track of 2 different iPad screens and the DoorDash system didn’t even have a printer so we had to write orders out by hand to hang them. Hooking up a receipt printer for DD is a short term TODO item for them.

The real takeaway here is thinking about separation of concerns, abstractions and the flexibility that’s available when you have decoupled systems. Having DD integration would be a nice quality of live improvement but it’s not a necessity.

The pizza maker on the back-end doesn’t even need to think about this detail. They just know they have to make a specific type of pizza before X time.

Multiple Payments Per Order

Most orders will be either cash or credit on their own but technically someone can pay with both cash and credit. This happened on the first day I was there where someone had a $14 order but they paid with both a gift card and the rest was cash.

Separate to that you may need to collect additional payments after a transaction has been completed. For example, someone places an order online for a regular pie with a custom note that says “Add buffalo chicken topping”.

Some folks do this on purpose in hopes to get a $5.50 topping for free. They should have chosen that as a topping through the menu system and it would have been calculated into the total before they paid.

Others make honest mistakes. Perhaps they’re not used to using online menus and didn’t notice the toppings section or the POS system’s software for online ordering isn’t ideal and didn’t make this noticeable enough.

In cases like this we’ll go back into the order and then charge an extra $5.50 onto their card. The POS allows you to add $X to an order as long as it’s under a certain amount (I think it’s based on a percent). In almost all cases this can be done without contacting the customer.

95%+ of the time this is fine and it’s what the customer wants. We always let them know when they pick it up or deliver it that we made the adjustment and it’s on the receipt. They are fully aware of the charge when they receive their food.

In the very off chance they don’t want the extra charge for the topping they ordered we refund them for just the topping’s charge and either give them a regular pie or let them keep the topping for free. It really depends on the situation.

Most business owners are ok with making you happy but if you try to take advantage of the situation and do this all the time they will notice and if you continue to abuse the system they may choose not to do business with you anymore.

Technical Takeaways

A way to describe all of this is an order has many payments. When displaying orders or showing receipts make sure that each payment method has its own line item.

Extra Charges, Tips and Discounts

Besides collecting payments after the initial transaction you may want to add additional charges before a transaction. This is done by clicking an “Extra charge” link near the total and then adding in the amount.

For example, there’s a $2 delivery charge that gets added to all orders marked as delivery.

There’s also scenarios where someone may request a custom order that doesn’t have a comparable menu item. Sometimes it makes sense to ring someone up for the closest menu item and then add an extra charge.

For example, an order of meatballs comes with (2) meatballs and there’s no way to order (1) meatball, so if someone wants (3) meatballs we may ring them up as (2) but then add an extra charge.

If they have a truly custom order the POS system also has an option to add an ADHOC item with a custom name, quantity and price. This isn’t an extra charge, it’s basically creating a 1 off menu item just for that 1 order.

Tips are basically extra charges with their own name. It’s important to be able to see “Tip” on the receipt in the expected spot. The credit card terminal allows someone to enter in no tip, a few common percents or a custom amount. There’s also a jar to collect cash tips. I was surprised at how many folks add tips even if they pick the order up themselves.

There’s also a way to reduce an order’s total with a discount. That’s done by clicking an “Add discount” link. You can choose to apply a fixed amount or percent off discount.

This may be through the customer having a coupon such as $3 off any pie or maybe the business owner gives a 5% discount on a large bulk order and also waives the delivery fee.

Technical Takeaways

It’s worth it to support both fixed and percent based discounts. I saw a number of both being applied in a short while and I do the same with courses. In the end a percent based discount applies a fixed amount discount so it’s not too bad to implement.

It should be easy to create custom items with a name and price for when the situation comes up. If a big order comes in, you don’t want to be struggling to figure out how to do it on the spot. If you’re sure it will happen, IMO it’s worth coding that feature up.

Likewise with courses, this comes up when organizations want to buy a team license. I ended up creating a custom package for the course for let’s say 25 licenses which goes through the normal checkout process. I have a couple of preset license amounts but I can add a custom amount too.

Voids and Refunds

Once in a while you may create an order that hasn’t received a payment yet and you want to cancel it. This could happen if let’s say you’ve made a menu adjustment on the back-end of the POS system and you want to ensure the price is up to date on the front-end.

Their specific POS system will auto-create an order as soon as you select any item. Personally I don’t like this but that’s how it is. It makes training more difficult because there’s no training mode and you have to create an order.

In those cases you can cancel or void the order. It still shows up as an order, except it’s been canceled with no payment. This audit trail is useful to help business owners protect themselves from employees ringing up orders, canceling them and then pocketing the cash.

Both partial and full refunds can happen on any order that has a payment. Sometimes you may need to refund someone for 1 specific item or the whole order. In our case we can also add a note to the refund so we and the customer know why.

All of this gets reflected back onto a new receipt that gets printed out.

Technical Takeaways

Generally speaking when dealing with money having more information is better than less. You want an audit trail covering every event. You should be able to trace through your events to recreate an order backwards and forwards.

Stripe does a very good job with this if you’ve ever used them before. You usually have multiple events being tied into a specific payment. The time lines all match up and the event data (JSON) is locked in at the time it occurred.


It’s useful to collect information such as at least the first name of someone who is picking up an order so it can be added to the receipt.

Having their phone number is handy too in case you need to call them to remind them to pick up their order or if something unexpected happens.

This is especially important for deliveries. For example, you might be delivering an order to an airport but the airport has 5 different terminals. Maybe the person who took the order over the phone didn’t get the details on where to go.

In this case the delivery driver can call the customer and arrange where to meet.

At this place they have a separate caller ID box that gets the name, number and address of the caller. It’s pretty handy. It’s not always correct or available but when it works it saves a good amount of time.

One thing I learned is it’s hard to hear things when folks have really bad phone habits and the store is busy. Also, trying to get a full address from someone who might be drunk is no easy task! Automating as much of this as possible helps.

Customer information gets saved too, this way if the same number is input again, the address is auto-filled out. Of course with mobile phones it’s possible that an address can change so we always ask them to confirm their address but again, 95%+ of the time this is a nice time saver.

Besides that, it helps business owners learn more about who likes what. If you know someone always orders similar pizzas every week then you can ask them “Hi Terry, do you want it lightly cooked like last time?”. This builds a nice rapport.

Technical Takeaways

Automating data input when possible is good but if it’s important you should always confirm it with another human on the other side. In this case a delivery to the wrong address is a really poor outcome.

For online orders outside of this pizza place, things like pre-filling a user’s state and zip code from a geo-location service is nice but allow the user to edit this information too. Especially if it’s for shipping an order.

Stripe, Shopify and Square

If you squint hard enough at this post related to “Order”, “Product” and “Customer” objects, this isn’t too different than Stripe, Shopify and Square’s APIs to accept payments for digital and physical goods.

Of course, this post only scratches the surface of what to think about. I wrote this post because I was excited about what I learned briefly working at a pizza place. I love thinking about optimizing workflows and self improvement.

I’m literally the definition of the “will work for pizza” meme but in a good way.

Seriously though, it really opened my eyes at how important a good user experience is, especially under pressure at a decently busy place. Every action should have a purpose and if there’s spots where you can forget something or you have to think about it, that’s a good opportunity to see how you can refine the workflow to make it seamless.

Personally if I were building a POS system I’d use their APIs as inspiration or even use one of them directly. Modern day POS systems can end up being basically an iPad mounted onto a register.

I can’t believe how much I learned about decomposing the problem of “taking orders” just by being in a physical location for a bit and getting into the thick of it. I highly encourage anyone to experience this for a bit at least once in their life.

So that’s about it in terms of payments. The video below goes into similar detail as this post with a bit more detail and personal asides.



  • 2:06 – Placing an order for pickup
  • 9:48 – Technical takeaways for picking up an order
  • 16:02 – Placing orders in multiple ways
  • 18:31 – Technical takeaways for placing orders in different ways
  • 20:37 – Multiple payments per order
  • 25:09 – Voids and refunds
  • 27:38 – Technical takeaways for refunds
  • 28:44 – Customers
  • 31:27 – Technical takeaways about customers
  • 32:02 – Using Stripe, Shopify and Square’s API as inspiration
  • 33:38 – Will work for pizza

What are your payment related takeaways when working at a register? Let us know!

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per month (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.