Order states
Orders kept as three fields - payment, fulfilment, called off - and as one status column of five values for eighteen real states: what the column reads back as, and the answers it gets wrong.
Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.
About
Orders kept two ways - as three fields, and as one status column - with every event applied to both, what the column reads back as, and the answers each model gives.
main.eml- the menu, the orders in both models, an event, the reports, every real state, and a new orderorders.eml- the fields and the column's values, when an event can happen, the event applied to the fields and to the column, the value that names a state, the state a value claims, and the three questions
How each part works:
- An order's state is three facts: payment (unpaid, paid, refunded), fulfilment (none, shipped, returned) and whether it was called off. As in the corpus case
status-field-conflation, the column has five values - pending, paid, shipped, cancelled, refunded - for eighteen real states, and only five of those have a value; a new order can reach twelve of them. - Each event handler writes the value nearest to what happened, and a return has no value at all, so it leaves the column as it was. Read back, the column gives a state that did not happen: refunded after shipping reads as never shipped, cancelled after paying reads as unpaid.
- The column can be wrong even where a value exists: an order shipped before it is paid ends as paid and shipped, which
shippednames, but the payment handler wrotepaidovershipped. - The questions: the money we hold, the parcels with the customer, and the refunds we owe. The column never shows a refund owed; for the opening orders it answers all three wrong, and nothing raises an error.
What is checked: menu choices 1 to 6; an order number that exists and one of the five events, and only when the event can happen to that order. An empty answer cancels.
Sessions: sessions/basic.in gives: - the orders, the reports and every state; - a new order shipped, paid and refunded; order 3 returned; the orders and the reports again.
sessions/bad-input.in gives: - menu choices 0 and x; - order numbers: a cancel, x, 1234 and 9; events: a cancel and fly; - events that cannot happen: paying a paid order, returning one never shipped, shipping a cancelled one, returning one returned, cancelling a shipped one and a cancelled one, refunding an unpaid one; - order 1 cancelled and order 6 refunded; the orders and the reports.
Built on the verified corpus case status-field-conflation (payment and fulfilment as a pair in one column, the states with no value, and an order history the column cannot hold).
Recorded sessions
What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.
bad-input
interpreter: byte-equal== Order states ==
Payment, fulfilment and calling off, kept as three fields and as one status column.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 0
Pick a number from 1 to 6.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> x
Pick a number from 1 to 6.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number>
Cancelled.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> x
Type an order number.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 1234
Type an order number.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 9
There is no order #9.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 1
event (pay, ship, refund, return, cancel)>
Cancelled.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 1
event (pay, ship, refund, return, cancel)> fly
Type pay, ship, refund, return or cancel.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 2
event (pay, ship, refund, return, cancel)> pay
Order #2 cannot pay: it is already paid.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 1
event (pay, ship, refund, return, cancel)> return
Order #1 cannot return: it was never shipped.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 6
event (pay, ship, refund, return, cancel)> ship
Order #6 cannot ship: it was cancelled.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 5
event (pay, ship, refund, return, cancel)> return
Order #5 cannot return: it is already returned.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 3
event (pay, ship, refund, return, cancel)> cancel
Order #3 cannot cancel: it is already shipped.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 6
event (pay, ship, refund, return, cancel)> cancel
Order #6 cannot cancel: it is already cancelled.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 1
event (pay, ship, refund, return, cancel)> refund
Order #1 cannot refund: it is unpaid, not paid.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 1
event (pay, ship, refund, return, cancel)> cancel
Order #1, cancel: three fields unpaid, none, cancelled; the column pending -> cancelled.
The column names this state exactly: cancelled.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 6
event (pay, ship, refund, return, cancel)> refund
Order #6, refund: three fields refunded, none, cancelled; the column cancelled -> refunded.
No value names refunded, none, cancelled; the column reads back as refunded, none, open, wrong on called off.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 1
order three fields column reads back wrong
#1 unpaid, none, cancelled cancelled -
#2 paid, none, open paid -
#3 paid, shipped, open shipped -
#4 refunded, shipped, open refunded fulfilment
#5 paid, returned, open shipped fulfilment
#6 refunded, none, cancelled refunded called off
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 3
question three fields the column
money we hold 3: #2 #3 #5 3: #2 #3 #5
parcels with the customer 2: #3 #4 2: #3 #5
refunds we owe 1: #5 0: none
The column answers 2 of the 3 questions wrong, and raises no error doing it.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 6
Bye.
What was typed (46 lines)
0
x
2
2
x
2
1234
2
9
2
1
2
1
fly
2
2
pay
2
1
return
2
6
ship
2
5
return
2
3
cancel
2
6
cancel
2
1
refund
2
1
cancel
2
6
refund
1
3
6
basic
interpreter: byte-equal== Order states ==
Payment, fulfilment and calling off, kept as three fields and as one status column.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 1
order three fields column reads back wrong
#1 unpaid, none, open pending -
#2 paid, none, open paid -
#3 paid, shipped, open shipped -
#4 refunded, shipped, open refunded fulfilment
#5 paid, returned, open shipped fulfilment
#6 paid, none, cancelled cancelled payment
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 3
question three fields the column
money we hold 4: #2 #3 #5 #6 3: #2 #3 #5
parcels with the customer 2: #3 #4 2: #3 #5
refunds we owe 2: #5 #6 0: none
The column answers 3 of the 3 questions wrong, and raises no error doing it.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 4
Every real state, and the value that names it:
unpaid, none, open pending
unpaid, shipped, open -
unpaid, returned, open -
paid, none, open paid
paid, shipped, open shipped
paid, returned, open -
refunded, none, open refunded
refunded, shipped, open -
refunded, returned, open -
unpaid, none, cancelled cancelled
unpaid, shipped, cancelled -
unpaid, returned, cancelled -
paid, none, cancelled -
paid, shipped, cancelled -
paid, returned, cancelled -
refunded, none, cancelled -
refunded, shipped, cancelled -
refunded, returned, cancelled -
5 values name 5 of the 18 real states; 13 have no value, and the code that meets one writes a neighbour.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 5
Order #7 placed: unpaid, none, open; the column pending.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 7
event (pay, ship, refund, return, cancel)> ship
Order #7, ship: three fields unpaid, shipped, open; the column pending -> shipped.
No value names unpaid, shipped, open; the column reads back as paid, shipped, open, wrong on payment.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 7
event (pay, ship, refund, return, cancel)> pay
Order #7, pay: three fields paid, shipped, open; the column shipped -> paid.
The column reads back as paid, none, open, wrong on fulfilment, though shipped would name it.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 7
event (pay, ship, refund, return, cancel)> refund
Order #7, refund: three fields refunded, shipped, open; the column paid -> refunded.
No value names refunded, shipped, open; the column reads back as refunded, none, open, wrong on fulfilment.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 2
order number> 3
event (pay, ship, refund, return, cancel)> return
Order #3, return: three fields paid, returned, open; the column shipped -> shipped.
No value names paid, returned, open; the column reads back as paid, shipped, open, wrong on fulfilment.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 1
order three fields column reads back wrong
#1 unpaid, none, open pending -
#2 paid, none, open paid -
#3 paid, returned, open shipped fulfilment
#4 refunded, shipped, open refunded fulfilment
#5 paid, returned, open shipped fulfilment
#6 paid, none, cancelled cancelled payment
#7 refunded, shipped, open refunded fulfilment
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 3
question three fields the column
money we hold 4: #2 #3 #5 #6 3: #2 #3 #5
parcels with the customer 2: #4 #7 2: #3 #5
refunds we owe 3: #3 #5 #6 0: none
The column answers 3 of the 3 questions wrong, and raises no error doing it.
1) orders 2) an event 3) reports 4) every state 5) new order 6) quit
choice> 6
Bye.
What was typed (19 lines)
1
3
4
5
2
7
ship
2
7
pay
2
7
refund
2
3
return
1
3
6
Modules
The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.
main.eml(entry)
eml# P146 order states: orders kept as three fields and as one status column,
# events applied to both, what the column reads back as, the reports each
# model gives, and the real states the column can name.
import orders
def plain(s):
0 => i
len(s) => j
while i < j and s[i] == " ":
i + 1 => i
while j > i and s[j - 1] == " ":
j - 1 => j
return s[i:j]
def pad(s, n):
s => out
while len(out) < n:
out + " " => out
return out
def lpad(s, n):
s => out
while len(out) < n:
" " + out => out
return out
def triple(st):
return st[0] + ", " + st[1] + ", " + st[2]
def wrong(st, col):
# the fields the column reads back wrong, or ""
orders.read(col) => back
["payment", "fulfilment", "called off"] => names
"" => out
0 => i
while i < 3:
if back[i] != st[i]:
if out == "":
names[i] => out
else:
out + " and " + names[i] => out
i + 1 => i
return out
def make(number, evs):
orders.start() => st
"pending" => col
for e in evs:
orders.apply(st, e) => st
orders.write(col, e) => col
return [number, st, col]
def show(os):
(" " + pad("order", 7) + pad("three fields", 30) + pad("column", 11) + "reads back wrong") ^0
for o in os:
wrong(o[1], o[2]) => w
if w == "":
"-" => w
(" " + pad("#" + str(o[0]), 7) + pad(triple(o[1]), 30) + pad(o[2], 11) + w) ^0
def find(os, n):
0 => i
for o in os:
if o[0] == n:
return i
i + 1 => i
return 0 - 1
def event(os):
plain(input("order number> ")) => t
if t == "":
"Cancelled." ^0
return os
if len(t) > 3:
"Type an order number." ^0
return os
for c in t:
if c < "0" or c > "9":
"Type an order number." ^0
return os
find(os, int(t)) => k
if k < 0:
("There is no order #" + t + ".") ^0
return os
plain(input("event (pay, ship, refund, return, cancel)> ")) => e
if e == "":
"Cancelled." ^0
return os
False => known
for x in orders.events():
if x == e:
True => known
if not known:
"Type pay, ship, refund, return or cancel." ^0
return os
os[k] => o
orders.problem(o[1], e) => why
if why != "":
("Order #" + str(o[0]) + " cannot " + e + ": " + why + ".") ^0
return os
orders.apply(o[1], e) => st
orders.write(o[2], e) => col
("Order #" + str(o[0]) + ", " + e + ": three fields " + triple(st) + "; the column " + o[2] + " -> " + col + ".") ^0
orders.name_of(st) => exact
wrong(st, col) => w
if w == "":
("The column names this state exactly: " + col + ".") ^0
elif exact == "":
("No value names " + triple(st) + "; the column reads back as " + triple(orders.read(col)) + ", wrong on " + w + ".") ^0
else:
("The column reads back as " + triple(orders.read(col)) + ", wrong on " + w + ", though " + exact + " would name it.") ^0
[] => out
0 => i
for x in os:
if i == k:
out + [[o[0], st, col]] => out
else:
out + [x] => out
i + 1 => i
return out
def numbers(os, which, from_column):
"" => out
0 => n
for o in os:
if from_column:
orders.read(o[2]) => st
else:
o[1] => st
if which == 0:
orders.money_held(st) => yes
elif which == 1:
orders.parcel_out(st) => yes
else:
orders.refund_owed(st) => yes
if yes:
n + 1 => n
if out == "":
"#" + str(o[0]) => out
else:
out + " #" + str(o[0]) => out
if out == "":
"none" => out
return [n, out]
def reports(os):
["money we hold", "parcels with the customer", "refunds we owe"] => qs
(" " + pad("question", 28) + pad("three fields", 22) + "the column") ^0
0 => differ
0 => i
while i < 3:
numbers(os, i, False) => a
numbers(os, i, True) => b
(" " + pad(qs[i], 28) + pad(str(a[0]) + ": " + a[1], 22) + str(b[0]) + ": " + b[1]) ^0
if a[1] != b[1]:
differ + 1 => differ
i + 1 => i
if differ == 0:
"Both models answer every question the same, for these orders." ^0
else:
("The column answers " + str(differ) + " of the 3 questions wrong, and raises no error doing it.") ^0
def space():
"Every real state, and the value that names it:" ^0
0 => named
0 => total
for c in ["open", "cancelled"]:
for p in orders.payments():
for f in orders.fulfilments():
[p, f, c] => st
orders.name_of(st) => v
total + 1 => total
if v == "":
"-" => v
else:
named + 1 => named
(" " + pad(triple(st), 30) + v) ^0
(str(len(orders.columns())) + " values name " + str(named) + " of the " + str(total) + " real states; " + str(total - named) + " have no value, and the code that meets one writes a neighbour.") ^0
[] => os
for o in orders.opening():
os + [make(o[0], o[1])] => os
"== Order states ==" ^0
"Payment, fulfilment and calling off, kept as three fields and as one status column." ^0
True => running
while running:
"" ^0
"1) orders 2) an event 3) reports 4) every state 5) new order 6) quit" ^0
plain(input("choice> ")) => choice
if choice == "1":
show(os)
elif choice == "2":
event(os) => os
elif choice == "3":
reports(os)
elif choice == "4":
space()
elif choice == "5":
os[len(os) - 1][0] + 1 => n
os + [make(n, [])] => os
("Order #" + str(n) + " placed: unpaid, none, open; the column pending.") ^0
elif choice == "6":
False => running
else:
"Pick a number from 1 to 6." ^0
"Bye." ^0
Python projection (main.py)
import orders
def plain(s):
i = 0
j = len(s)
while i < j and s[i] == " ":
i = i + 1
while j > i and s[j - 1] == " ":
j = j - 1
return s[i:j]
def pad(s, n):
out = s
while len(out) < n:
out = out + " "
return out
def lpad(s, n):
out = s
while len(out) < n:
out = " " + out
return out
def triple(st):
return st[0] + ", " + st[1] + ", " + st[2]
def wrong(st, col):
back = orders.read(col)
names = ["payment", "fulfilment", "called off"]
out = ""
i = 0
while i < 3:
if back[i] != st[i]:
if out == "":
out = names[i]
else:
out = out + " and " + names[i]
i = i + 1
return out
def make(number, evs):
st = orders.start()
col = "pending"
for e in evs:
st = orders.apply(st, e)
col = orders.write(col, e)
return [number, st, col]
def show(os):
print(" " + pad("order", 7) + pad("three fields", 30) + pad("column", 11) + "reads back wrong")
for o in os:
w = wrong(o[1], o[2])
if w == "":
w = "-"
print(" " + pad("#" + str(o[0]), 7) + pad(triple(o[1]), 30) + pad(o[2], 11) + w)
def find(os, n):
i = 0
for o in os:
if o[0] == n:
return i
i = i + 1
return 0 - 1
def event(os):
t = plain(input("order number> "))
if t == "":
print("Cancelled.")
return os
if len(t) > 3:
print("Type an order number.")
return os
for c in t:
if c < "0" or c > "9":
print("Type an order number.")
return os
k = find(os, int(t))
if k < 0:
print("There is no order #" + t + ".")
return os
e = plain(input("event (pay, ship, refund, return, cancel)> "))
if e == "":
print("Cancelled.")
return os
known = False
for x in orders.events():
if x == e:
known = True
if not known:
print("Type pay, ship, refund, return or cancel.")
return os
o = os[k]
why = orders.problem(o[1], e)
if why != "":
print("Order #" + str(o[0]) + " cannot " + e + ": " + why + ".")
return os
st = orders.apply(o[1], e)
col = orders.write(o[2], e)
print("Order #" + str(o[0]) + ", " + e + ": three fields " + triple(st) + "; the column " + o[2] + " -> " + col + ".")
exact = orders.name_of(st)
w = wrong(st, col)
if w == "":
print("The column names this state exactly: " + col + ".")
elif exact == "":
print("No value names " + triple(st) + "; the column reads back as " + triple(orders.read(col)) + ", wrong on " + w + ".")
else:
print("The column reads back as " + triple(orders.read(col)) + ", wrong on " + w + ", though " + exact + " would name it.")
out = []
i = 0
for x in os:
if i == k:
out = out + [[o[0], st, col]]
else:
out = out + [x]
i = i + 1
return out
def numbers(os, which, from_column):
out = ""
n = 0
for o in os:
if from_column:
st = orders.read(o[2])
else:
st = o[1]
if which == 0:
yes = orders.money_held(st)
elif which == 1:
yes = orders.parcel_out(st)
else:
yes = orders.refund_owed(st)
if yes:
n = n + 1
if out == "":
out = "#" + str(o[0])
else:
out = out + " #" + str(o[0])
if out == "":
out = "none"
return [n, out]
def reports(os):
qs = ["money we hold", "parcels with the customer", "refunds we owe"]
print(" " + pad("question", 28) + pad("three fields", 22) + "the column")
differ = 0
i = 0
while i < 3:
a = numbers(os, i, False)
b = numbers(os, i, True)
print(" " + pad(qs[i], 28) + pad(str(a[0]) + ": " + a[1], 22) + str(b[0]) + ": " + b[1])
if a[1] != b[1]:
differ = differ + 1
i = i + 1
if differ == 0:
print("Both models answer every question the same, for these orders.")
else:
print("The column answers " + str(differ) + " of the 3 questions wrong, and raises no error doing it.")
def space():
print("Every real state, and the value that names it:")
named = 0
total = 0
for c in ["open", "cancelled"]:
for p in orders.payments():
for f in orders.fulfilments():
st = [p, f, c]
v = orders.name_of(st)
total = total + 1
if v == "":
v = "-"
else:
named = named + 1
print(" " + pad(triple(st), 30) + v)
print(str(len(orders.columns())) + " values name " + str(named) + " of the " + str(total) + " real states; " + str(total - named) + " have no value, and the code that meets one writes a neighbour.")
os = []
for o in orders.opening():
os = os + [make(o[0], o[1])]
print("== Order states ==")
print("Payment, fulfilment and calling off, kept as three fields and as one status column.")
running = True
while running:
print("")
print("1) orders 2) an event 3) reports 4) every state 5) new order 6) quit")
choice = plain(input("choice> "))
if choice == "1":
show(os)
elif choice == "2":
os = event(os)
elif choice == "3":
reports(os)
elif choice == "4":
space()
elif choice == "5":
n = os[len(os) - 1][0] + 1
os = os + [make(n, [])]
print("Order #" + str(n) + " placed: unpaid, none, open; the column pending.")
elif choice == "6":
running = False
else:
print("Pick a number from 1 to 6.")
print("Bye.")
orders.eml
eml# P146 order states - an order's payment, fulfilment and whether it was
# called off, kept as three fields and as one status column. As in the
# corpus case status-field-conflation, the column is asked to hold a pair
# (here a triple) in one slot: five values for eighteen real states. The
# event handlers write the value nearest to what happened, and reading the
# column back gives a state that did not happen. A state is [payment,
# fulfilment, called off]: payment unpaid, paid or refunded; fulfilment
# none, shipped or returned; called off "open" or "cancelled".
def payments():
return ["unpaid", "paid", "refunded"]
def fulfilments():
return ["none", "shipped", "returned"]
def columns():
return ["pending", "paid", "shipped", "cancelled", "refunded"]
def events():
return ["pay", "ship", "refund", "return", "cancel"]
def start():
return ["unpaid", "none", "open"]
def problem(st, e):
# why event e cannot happen to state st, or "" when it can
if e == "pay":
if st[0] != "unpaid":
return "it is already " + st[0]
if st[2] == "cancelled":
return "it was cancelled"
if e == "ship":
if st[1] != "none":
return "it is already " + st[1]
if st[2] == "cancelled":
return "it was cancelled"
if e == "refund" and st[0] != "paid":
return "it is " + st[0] + ", not paid"
if e == "return" and st[1] != "shipped":
if st[1] == "none":
return "it was never shipped"
return "it is already returned"
if e == "cancel":
if st[2] == "cancelled":
return "it is already cancelled"
if st[1] != "none":
return "it is already " + st[1]
return ""
def apply(st, e):
# the three fields after event e
if e == "pay":
return ["paid", st[1], st[2]]
if e == "ship":
return [st[0], "shipped", st[2]]
if e == "refund":
return ["refunded", st[1], st[2]]
if e == "return":
return [st[0], "returned", st[2]]
return [st[0], st[1], "cancelled"]
def write(col, e):
# the column after event e: each handler writes the value nearest to
# what happened; a return has no value, so it leaves the column
if e == "pay":
return "paid"
if e == "ship":
return "shipped"
if e == "refund":
return "refunded"
if e == "cancel":
return "cancelled"
return col
def name_of(st):
# the value that names state st exactly, or ""
if st[2] == "open":
if st[0] == "unpaid" and st[1] == "none":
return "pending"
if st[0] == "paid" and st[1] == "none":
return "paid"
if st[0] == "paid" and st[1] == "shipped":
return "shipped"
if st[0] == "refunded" and st[1] == "none":
return "refunded"
elif st[0] == "unpaid" and st[1] == "none":
return "cancelled"
return ""
def read(col):
# the state the column claims
if col == "paid":
return ["paid", "none", "open"]
if col == "shipped":
return ["paid", "shipped", "open"]
if col == "refunded":
return ["refunded", "none", "open"]
if col == "cancelled":
return ["unpaid", "none", "cancelled"]
return ["unpaid", "none", "open"]
def opening():
# [order number, events so far]
return [[1, []], [2, ["pay"]], [3, ["pay", "ship"]], [4, ["pay", "ship", "refund"]], [5, ["pay", "ship", "return"]], [6, ["pay", "cancel"]]]
def money_held(st):
return st[0] == "paid"
def parcel_out(st):
return st[1] == "shipped"
def refund_owed(st):
return st[0] == "paid" and (st[2] == "cancelled" or st[1] == "returned")
Python projection (orders.py)
def payments():
return ["unpaid", "paid", "refunded"]
def fulfilments():
return ["none", "shipped", "returned"]
def columns():
return ["pending", "paid", "shipped", "cancelled", "refunded"]
def events():
return ["pay", "ship", "refund", "return", "cancel"]
def start():
return ["unpaid", "none", "open"]
def problem(st, e):
if e == "pay":
if st[0] != "unpaid":
return "it is already " + st[0]
if st[2] == "cancelled":
return "it was cancelled"
if e == "ship":
if st[1] != "none":
return "it is already " + st[1]
if st[2] == "cancelled":
return "it was cancelled"
if e == "refund" and st[0] != "paid":
return "it is " + st[0] + ", not paid"
if e == "return" and st[1] != "shipped":
if st[1] == "none":
return "it was never shipped"
return "it is already returned"
if e == "cancel":
if st[2] == "cancelled":
return "it is already cancelled"
if st[1] != "none":
return "it is already " + st[1]
return ""
def apply(st, e):
if e == "pay":
return ["paid", st[1], st[2]]
if e == "ship":
return [st[0], "shipped", st[2]]
if e == "refund":
return ["refunded", st[1], st[2]]
if e == "return":
return [st[0], "returned", st[2]]
return [st[0], st[1], "cancelled"]
def write(col, e):
if e == "pay":
return "paid"
if e == "ship":
return "shipped"
if e == "refund":
return "refunded"
if e == "cancel":
return "cancelled"
return col
def name_of(st):
if st[2] == "open":
if st[0] == "unpaid" and st[1] == "none":
return "pending"
if st[0] == "paid" and st[1] == "none":
return "paid"
if st[0] == "paid" and st[1] == "shipped":
return "shipped"
if st[0] == "refunded" and st[1] == "none":
return "refunded"
elif st[0] == "unpaid" and st[1] == "none":
return "cancelled"
return ""
def read(col):
if col == "paid":
return ["paid", "none", "open"]
if col == "shipped":
return ["paid", "shipped", "open"]
if col == "refunded":
return ["refunded", "none", "open"]
if col == "cancelled":
return ["unpaid", "none", "cancelled"]
return ["unpaid", "none", "open"]
def opening():
return [[1, []], [2, ["pay"]], [3, ["pay", "ship"]], [4, ["pay", "ship", "refund"]], [5, ["pay", "ship", "return"]], [6, ["pay", "cancel"]]]
def money_held(st):
return st[0] == "paid"
def parcel_out(st):
return st[1] == "shipped"
def refund_owed(st):
return st[0] == "paid" and (st[2] == "cancelled" or st[1] == "returned")