Production Orders
In this section, you'll create your first production order manually. In later sections, orders will come from ERP instead.
Create a production order
- Navigate to Ops → Scheduling → Production Orders.
- Create a new order with the following values:
| Order Number | Item | Mode | Quantity | Units | Status | Due Date |
|---|---|---|---|---|---|---|
| 260526-001 | CoreForge\WIP\Machined\SC-2024 | Production | 30000 | units | Released | End of the month |
- Save the production order.
Check your work
Copy this script into the Ignition Designer Script Console (Tools → Script Console) and run it. It checks that order 260526-001 exists with the right item, mode, quantity, units, status and an end-of-month due date. Each check prints PASS or FAIL with what to fix. It doesn't change anything.
Show the check script
checkLesson-productionOrders.py
# Kanoa Ops Training - check "Production Orders" (Scheduling, lesson 2)
#
# Run in the Ignition Designer Script Console (Tools > Script Console), in the
# project that inherits KANOA_SCRIPTS. It only reads; it changes nothing.
# Every check prints PASS or FAIL with what to fix, then a summary.
from java.util import Calendar, TimeZone, Date
ORDER = '260526-001'
ITEM = 'CoreForge\\WIP\\Machined\\SC-2024'
MODE = 'Production'
QTY = 30000
UNITS = 'units'
STATUS = 'Released'
# the next lessons start this order, which moves it on from Released
LATER_STATUSES = ['In Progress', 'Completed', 'Closed']
SITE = 'CoreForge\\Philadelphia'
WINDOWS_TZ = {
'eastern standard time': 'America/New_York', 'central standard time': 'America/Chicago',
'mountain standard time': 'America/Denver', 'pacific standard time': 'America/Los_Angeles',
}
results = []
def check(ok, what, fix=None):
results.append(bool(ok))
if ok:
print 'PASS %s' % what
else:
print 'FAIL %s' % what
if fix:
print ' -> %s' % fix
def field(row, *names):
for n in names:
if n in row and row[n] is not None:
return row[n]
return None
def text(v):
return '' if v is None else unicode(v).strip()
def squash(v):
return ' '.join(text(v).lower().split())
def norm(path):
return text(path).replace('/', '\\').strip('\\')
def rows(fn, params):
# Kanoa returns a dataset, a list, or None when there's nothing to return
data = fn(params)
if data is None:
return []
if hasattr(data, 'getRowCount'):
cols = list(data.getColumnNames())
return [dict((c, data.getValueAt(i, c)) for c in cols) for i in range(data.getRowCount())]
return [dict(r) for r in data]
def showColumns(label, data, key):
if data and key not in data[0]:
print 'NOTE %s has no %s column. Columns: %s' % (label, key, ', '.join(sorted(data[0].keys())))
def toDate(v):
if v is None:
return None
if isinstance(v, Date):
return v
if hasattr(v, 'getTime'):
return Date(v.getTime())
if isinstance(v, (int, long, float)) or text(v).isdigit():
return Date(long(float(text(v))))
s = text(v).replace('T', ' ')
for value, fmt in ((s[:19], 'yyyy-MM-dd HH:mm:ss'), (s[:16], 'yyyy-MM-dd HH:mm'), (s[:10], 'yyyy-MM-dd')):
try:
return system.date.parse(value, fmt)
except:
pass
return None
print '=' * 70
print 'Kanoa Ops Training - Production Orders check'
print '=' * 70
# 1. The order exists
print '\n-- Production order %s' % ORDER
orders = rows(system.kanoa.order.getProductionOrders, {'workOrderName': ORDER, 'ignoreActualQty': True})
orders = [r for r in orders if text(field(r, 'workOrderName')) in ('', ORDER)]
if not orders:
# look for a near miss, e.g. extra spaces or a different dash
allOrders = rows(system.kanoa.order.getProductionOrders, {'ignoreActualQty': True})
key = ''.join(ch for ch in ORDER if ch.isalnum())
near = [text(field(r, 'workOrderName')) for r in allOrders
if ''.join(ch for ch in text(field(r, 'workOrderName')) if ch.isalnum()) == key]
if near:
check(False, 'Production order %s exists' % ORDER,
"Found '%s'. Edit it and set the Order # to %s exactly." % (near[0], ORDER))
orders = [r for r in allOrders if text(field(r, 'workOrderName')) == near[0]]
else:
check(False, 'Production order %s exists' % ORDER,
'In Ops > Scheduling > Production Orders, click + and add order %s.' % ORDER)
else:
check(True, 'Production order %s exists' % ORDER)
if len(orders) > 1:
print 'NOTE There are %d orders named %s; checking the first.' % (len(orders), ORDER)
if orders:
o = orders[0]
showColumns('getProductionOrders', orders, 'itemPath')
# 2. Item
itemPath = norm(field(o, 'itemPath'))
if not itemPath:
cls = norm(field(o, 'itemClassPath'))
name = text(field(o, 'itemName'))
itemPath = (cls + '\\' + name) if cls else name
check(itemPath == ITEM or (itemPath == ITEM.split('\\')[-1]), 'Item is %s' % ITEM,
"It's '%s'. Edit the order and use the item selector to pick %s." % (itemPath or 'blank', ITEM))
# 3. Mode
mode = text(field(o, 'modeName'))
check(mode == MODE, 'Mode is %s' % MODE,
"It's '%s'. Edit the order and set Mode to %s." % (mode or 'blank', MODE))
# 4. Quantity and units
qty = field(o, 'reqdQty', 'requiredQty', 'qty')
try:
qtyOk = abs(float(qty) - QTY) < 0.001
except:
qtyOk = False
check(qtyOk, 'Quantity is %s' % QTY,
"It's %s. Edit the order and set Qty to %s." % (text(qty) or 'blank', QTY))
units = text(field(o, 'itemUnitName', 'unitName', 'units'))
check(units.lower() == UNITS, 'Units are %s' % UNITS,
"It's '%s'. Edit the order and set Units to %s." % (units or 'blank', UNITS))
# 5. Status
status = text(field(o, 'workOrderStatusName', 'statusName'))
if status in LATER_STATUSES:
check(True, 'Status is %s (now %s, because a run has started on it)' % (STATUS, status))
else:
check(status == STATUS, 'Status is %s' % STATUS,
"It's '%s'. Edit the order and set Status to %s, so it can be scheduled." % (status or 'blank', STATUS))
# 6. Due date: the end of a month, in the site's time zone
site = rows(system.kanoa.asset.getAssets, {'assetPath': SITE})
tzName = text(field(site[0], 'timeZone')) if site else ''
tz = TimeZone.getTimeZone(WINDOWS_TZ.get(tzName.lower(), tzName)) if tzName else TimeZone.getDefault()
due = toDate(field(o, 'dueDate'))
if due is None:
check(False, 'Due date is set to the end of the month',
'The order has no due date. Edit it and set Due Date to the last day of the month.')
else:
c = Calendar.getInstance(tz)
c.setTime(due)
day, last = c.get(Calendar.DAY_OF_MONTH), c.getActualMaximum(Calendar.DAY_OF_MONTH)
shown = '%04d-%02d-%02d' % (c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, day)
check(day == last, 'Due date is set to the end of the month (%s)' % shown,
"It's %s. Edit the order and set Due Date to the last day of the month." % shown)
passed = results.count(True)
print '\n' + '=' * 70
print 'Result: %d of %d checks passed' % (passed, len(results))
if passed == len(results):
print 'All good. Your production order is set up.'
else:
print 'Fix the FAIL items above, then run this again.'
print '=' * 70
You'll schedule this order onto Machine 1 in the next section.



